← Back
Security 2026-05-29 Edited: 2026-05-29

Mapping Out a Phishing Campaigns Infrastructure

A scam email...sent by me?

Mapping Out a Phishing Campaigns Infrastructure

Photo by @kasiade | Unsplash

TLDR

This originally started as idle curiosity about a phishing email that appeared to come from my own Gmail account, which then turned into a several day investigation that uncovered a coordinated international phishing campaign.

By tracing a chain of DNS records from a single spam email, I accidentally mapped out an entire criminal infrastructure with a sending cluster spread across Ukraine, Turkey, Romania and Russia, subdomain takeovers on major corporations including a US defence contractor and UK’s largest mobile network provider, an exposed spam framework, and a multi-layered redirect chain abusing Google’s own infrastructure to bypass spam filters.

I went in expecting to spend twenty minutes looking at some dodgy headers.

All investigations were conducted using publicly available DNS records and standard query tools. No systems were accessed without authorisation. Affected organisations have been notified.

It’s very rare for me to check my spam emails, but on this occasion where I did, I was quite surprised to see an email sent by me. photo

Obviously, I did not send myself an email saying I have failed to pay for my cloud storage, so how did they do it?

Spoofing

Luckily Gmail’s headers can give us some clues. photo

Email protocols actually have two separate concepts of “From”: Header-From and Envelope-From, this is something scammers can exploit. Envelope sender is the real origin of the message, the one mail servers actually use to route email. The second is the display headers, things like From: and Sender: Strangely, those are just text, so anyone can edit them to whatever they like.

They ran their own mail server on a .biz.ua Ukrainian domain, set the Sender: header in the email to read my email, and Gmail’s UI displayed that as “sent by.” That’s it. No Gmail account was hacked. No passwords were stolen. They just… typed a name into a field.

Digging

Now we have their mail domain, lets do some digging. photo

This give us their Sender Policy Framework (SPF) record, a DNS record which tells receiving mail servers which IP addresses are authorised to send email on behalf of that domain It looks like whatever addresses hosted on ips.dnstool.site can send mail.

Lets dig further

photo

A list of IP’s, this is likely their cluster for their snowshoe spamming operation. Now we can run a WHOIS on each domain to find out more information on them. It is a lot of IPs so I’ll use a bash script photo

A lot of servers, most importantly, they have distributed it across providers within different countries. If one gets taken down, they still have lots remaining.

photo

We can also do a reverse lookup using dig with the -x flag to see what domains they are associated with. Again, it’s a lot of IP’s so I’ll use a bash script.

photo

photo

The results are extremely interesting, they are resolving to legitimate domains such as

Subdomain Take Overs

Imagine a large company puts up a signpost outside saying “our billing office is in that building over there” but then leave after a while. They still own the signpost. But the lease on that building expired, someone else moved in, and the company never updated the sign. Anyone following the sign ends up at the wrong place entirely.

That’s essentially what a subdomain takeover is, attackers look around legitimate domains looking for old abandoned subdomains, often ones pointing to internal or third party services. When those shut down or are moved the DNS records are often forgotten. If the domain the CNAME points at becomes available, anyone can register it, the corporate subdomain now points at whoever claimed it.

Following the Trail

We already have their SPF record from earlier

$ dig TXT sb021.darow.biz.ua
    → "v=spf1 a:ips.dnstool.site -all"

This tells any receiving mail server to trust whatever IP addresses are listed on ips.dnstool.site. We already queried that and got our list of IPs.

The reverse DNS lookup from earlier shows that rather than resolving to obscure VPS hostnames, several resolve back to subdomains belonging to major corporations. Taking Honeywell as an example:

$ dig -x 82.41.64.81
    → www.shared.honeywell.com

Why does a spam server have a Honeywell PTR record? The attacker never touched Honeywell. They just registered a domain that Honeywell’s DNS happened to point at through a forgotten service, and set the PTR record on their VPS.

$ dig TXT www.shared.honeywell.com
    → CNAME honshared1.shared.com.sg
    → CNAME ips.dnstool.site
    
office2go.vodafone.com
    → briefcase2go.com
    → ips.dnstool.site

dashboard.freedommobile.ca
    → prdntxappl11.sjrb.ad
    → ips.dnstool.site

ebill.virginmobile.ca
    → ebill.vmobile.ca
    → vmc.e-billonline.com
    → ips.dnstool.site

www.shared.honeywell.com
    → honshared1.shared.com.sg
    → ips.dnstool.site

Strangely, a lot of these servers are hosting a static web page. photo

All links on this page point back to the same page, DeskFlow is not a real service nor company. It is likely this is a decoy website used to bypass spam filters. What gives it away is that it only appears when you connect directly via IP address, visiting the domain resolves nothing, so the decoy is designed for machines, not humans.

In addition to the the decoy webpages, one IP hosts a .php script. Which can tell use exactly how the whole operation works

Show code
<?php
/**
* @framework       Vugex Framework
* @version         1.0
* @author          H1DEV <[email protected]>
* @date            2024
* @name            index.php
*/

# require the helper
require_once '/var/www/scripts/help.php';

# defining separators
define('DS',DIRECTORY_SEPARATOR);
define('RDS','/');

# links
$api = decrypt('KG4LaPFgrdO8JtI0YigcKJhWBehFuOIez7khBCO/iV1fieeXiKgmeKQMOhkhQwMXYkc1/kzuaBOFrkD1rf5Odw==');
$upcenter = decrypt('2CgyvavJEoncNKk3/HQh13KIRM0B6pS4uykkPPrIrhkGp7hb89vCy+6gvTYeydLd6Jdp4UFQw1hdg2KxcW3MEw==');

# parse url to get parameters 
$url = (filter_input(INPUT_SERVER, 'HTTP_X_REWRITE_URL') != null) ? ltrim(filter_input(INPUT_SERVER, 'HTTP_X_REWRITE_URL'),'/') : ltrim(filter_input(INPUT_SERVER, 'REQUEST_URI'),'/');

# check if is an image 
checkForImage($url,$upcenter);

# check for short link
?>
<script>if(window.location.href.includes("#")) window.location.href = window.location.href.replace(/\/\#\//g,'#').replace(/\/\#/g,'#').replace(/\#/g,'/');</script>
<?php

# check for root call of the domain
checkForLandingPage($url);

# prepare data array 
$data = parseURL($url);

# check for data array
if(!is_array($data) || count($data) == 0) die('<pre style="color:red">parameters not found !</pre>');

# check for ids 
if($data['process-id'] == 0 && $data['offer-id'] == 0) die('<pre style="color:red">offer not found !</pre>');

# get user's info
$clientIp = getIp();
$agent = (filter_input(INPUT_SERVER,'HTTP_USER_AGENT') != null) ? filter_input(INPUT_SERVER,'HTTP_USER_AGENT') : '';

# opt out case
if($data['act'] == 'oop')
{
  $message = "";
          
  if(count($_POST)) 
  {
      $email = (filter_input(INPUT_POST,'email') != null) ? filter_input(INPUT_POST,'email') : '';

      # send tracking information to vugex
      if(!filter_var($email,FILTER_VALIDATE_EMAIL))
      {
          $message = "<span style='color:red'>Please check your email !</span>";
      }
      else
      {
          # check if email is the same
          $parameters = ['email' => md5($email),'list-id' => $data['list-id'],'client-id' => $data['client-id']];
          
          $results = cmd('php /var/www/scripts/request.php ' . base64_encode($api) . ' ' . base64_encode('Tracking') 
          . ' ' . base64_encode('checkEmail') . ' ' . base64_encode(json_encode($parameters)));
          
          # check results
          if(!is_array($results) || count($results) == 0 || !key_exists('output', $results) 
          || json_decode($results['output']) == false || $results['status'] != '200') $message = "<span style='color:red'>Your Email is not registered !</span>";

          # parse results
          $results = json_decode($results['output'],true);

          # check http status
          if($results['status'] != '200') $message = "<span style='color:red'>Your Email is not registered !</span>";

          if(strtolower(trim($result['message'])) == 'email is correct !')
          {
              # preparing parameters
              $parameters = [
                  'action' => $data['act'],
                  'process-id' => $data['process-id'],
                  'process-type' => $data['process-type'],
                  'user-id' => $data['user-id'],
                  'vmta-id' => $data['vmta-id'],
                  'list-id' => $data['list-id'],
                  'client-id' => $data['client-id'],
                  'offer-id' => $data['offer-id'],
                  'ip' => $clientIp,
                  'agent' => $agent
              ];
              
              # execute tracking job
              cmd('nohup php /var/www/scripts/request.php ' . base64_encode($api) . ' ' . base64_encode('Tracking') 
              . ' ' . base64_encode('procceed') . ' ' . base64_encode(json_encode($parameters)) . ' &');
              
              $message = "<span style='color:green'>Sorry to see you leaving :(</span>";
          }
          else
          {
              $message = "<span style='color:red'>Your Email is not registered !</span>";
          }
      }
  }

  include_once 'optout.php'; 
}
else
{
  # preparing parameters
  $parameters = [
      'action-id' => 0,
      'action' => $data['act'],
      'process-id' => $data['process-id'],
      'process-type' => $data['process-type'],
      'user-id' => $data['user-id'],
      'vmta-id' => $data['vmta-id'],
      'list-id' => $data['list-id'],
      'client-id' => $data['client-id'],
      'offer-id' => $data['offer-id'],
      'ip' => $clientIp,
      'agent' => $agent,
      'info' => []
  ];

  # get offer link
  $link = '';
  
  if(in_array($data['act'],['cl','un']))
  {
      $results = cmd('php /var/www/scripts/request.php ' . base64_encode($api) . ' ' . base64_encode('Tracking') 
      . ' ' . base64_encode('getLink') . ' ' . base64_encode(json_encode($parameters)));
      
      # check results
      if(!is_array($results) || count($results) == 0 || !key_exists('output', $results) 
      || json_decode($results['output']) == false) die('<pre style="color:red">offer unavailable !</pre>');
          
      # parse results
      $results = json_decode($results['output'],true);
      
      # check http status
      if($results['status'] != '200') die("<pre style='color:red'>{$results['status']} : {$results['message']}</pre>");
      
      # check link
      if(!key_exists('data',$results) || !key_exists('link',$results['data']) 
      || strpos($results['data']['link'],'http') === false) die('<pre style="color:red">offer link is unavailable !</pre>');
      
      $link = trim($results['data']['link']);
      $parameters['action-id'] = intval($results['data']['action_id']);
      $parameters['info'] = intval($results['data']['info']);
  }
  
  # send tracking information to master app
  if(in_array($data['act'],['op','cl','un']) && $data['process-id'] > 0)
  {
      # execute tracking job
      cmd('nohup php /var/www/scripts/request.php ' . base64_encode($api) . ' ' . base64_encode('Tracking') 
      . ' ' . base64_encode('procceed') . ' ' . base64_encode(json_encode($parameters)) . ' &');
  }

  # redirecting in case of a click or unsub 
  if($link == '') die('<pre style="color:red">operation completed !</pre>');
  header('Location: ' . $link); die();
}

The file has some clues about the author, and is part of the “Vugex Framework”, which seems to be a a bulk email platform. Specifically it’s the tracking and analytics engine behind the entire campaign.

Each click, open and unsubscribe are logged, capturing IP addresses and browser fingerprints then reporting them back to encrypted API endpoints.

Funnily enough, it has an unsubscribe mechanism, although submitting your email to opt out simply does the opposite and confirms your address is live and active, which is basically worse than doing nothing.

Unfortunately without access to /var/www/scripts/help.php it’s not possible to reverse cipher the domain. Therefore for now it seems this a dead end.

The Email

Now I can move onto the email content itself, it’s your average phishing email with a big button asking you to check something.

photo

Hovering anywhere over the email shows that wherever you click, you will be directed to https://storage.googleapis.com/carnivorous/carnivorous.html#?act=cl&pid=xxxx_md&uid=2&vid=xxxx&ofid=xxxxlid=253&cid=xxxxx

Some of the URL parameters are linked to the php script,

act=cl      ← action = click
pid=6920_md ← process-id
uid=2       ← user-id
vid=142445  ← vmta-id (Virtual MTA - mail server ID)
ofid=408    ← offer-id
lid=253     ← list-id
cid=188137  ← client-id

It also uses Google Cloud Storage, likely as a way to live off the land of trusted infrastructure. storage.googleapis.com is a real Google domain therefore spam filters and email scanners wont block it and the actual malicious redirect is handled by the HTML file hosted in the bucket. I’ve loaded the email into a VM so I can see what this html file is, resulting in domainpoint.online photo

Back to digging,

photo

Unlike the elaborate multi-hop SPF chains seen earlier on the sending infrastructure, this record is stripped back to a single IP address with no third party includes. It’s already behind a wall of obfuscation so it does not need to do any itself.

Instead of going through all the redirects, we can just send the tracking information directly to the source IP.

photo

Now theres another domain

The full chain from email to final destination looks like this:

Phishing email
  → storage.googleapis.com (trusted Google URL)
    → domainpoint.online (disposable redirect layer)
      → 180.131.145.190 (actual Apache server)
        → keybussinessserver.com (final destination)

Each layer has a specific job:

The tracking parameters are carried through every redirect, ensuring the operator gets credited for every victim that reaches the final page, this seems like a pay-per-click affiliate scam rather than direct credential harvesting.

Interestingly, a final WHOIS on the domain returned a Real Name, Email and Ukrainian address, potentially linking it to the .ua email we started with. However does that mean this person is behind it? Probably not, advanced phishing campaigns like these are often ran by sophisticated organised crime groups, therefore it could be a stolen identity, not that they thought the were covered by the layers of redirects and obfuscation

Infrastructure Diagram

    flowchart TD
    A["📧 Phishing Email\nsb021.darow.biz.ua"] --> B["Google Cloud Bucket\nstorage.googleapis.com/carnivorous"]
    B --> C["Redirect Layer\ndomainpoint.online"]
    C --> D["Apache Server\n180.131.145.190"]
    D --> E["💰 Final Destination\nkeybussinessserver.com"]

    A --> F["SPF Record\nips.dnstool.site"]

    F --> G["🖥️ 30-Node Sending Cluster\nTurkey · Romania · Russia"]

    G --> H["PTR: office2go.vodafone.com\n⚠️ Subdomain Takeover"]
    G --> I["PTR: dashboard.freedommobile.ca\n⚠️ Subdomain Takeover"]
    G --> J["PTR: ebill.virginmobile.ca\n⚠️ Subdomain Takeover"]
    G --> K["PTR: www.shared.honeywell.com\n⚠️ Subdomain Takeover"]

    H --> L["briefcase2go.com\n↓\nips.dnstool.site"]
    I --> M["prdntxappl11.sjrb.ad\n↓\nips.dnstool.site"]
    J --> N["ebill.vmobile.ca\n↓ vmc.e-billonline.com\n↓\nips.dnstool.site"]
    K --> O["honshared1.shared.com.sg\n↓\nips.dnstool.site"]

    L --> P["☁️ ips.dnstool.site\nCloudflare Protected\nCommand Centre"]
    M --> P
    N --> P
    O --> P

    style A fill:#ff6b6b,color:#fff
    style P fill:#ff6b6b,color:#fff
    style E fill:#ff6b6b,color:#fff
    style F fill:#ffa94d,color:#fff
    style G fill:#ffa94d,color:#fff
    style H fill:#ffe066,color:#333
    style I fill:#ffe066,color:#333
    style J fill:#ffe066,color:#333
    style K fill:#ffe066,color:#333