# From Malspam to a Fileless .NET Loader: Abusing Google DoubleClick and a Five-Stage Evasion Chain

A German-language "purchase order" email with an HTML attachment is the opening move of a five-stage attack chain in which the malicious link routes through `ad.doubleclick[.]net` — a high-reputation Google-owned domain most email gateways won't blink at. The Huntress SOC responded to this infection in May 2026 and traced it to a **.NET loader that barely touches disk**, blinding Windows telemetry before persisting on the victim's machine.

![Attack path from malspam to loader](https://cdn.builder.io/api/v1/image/assets%2F3eb6f92aedf74f109c7b4b0897ec39a8%2F6bef4143242042b7a61ac640a972470f align="center")

## Executive Summary

This malspam campaign is not a run-of-the-mill infection. Before the victim ever reaches attacker infrastructure, the lure routes through **Google DoubleClick** — a legitimate, high-reputation domain that is rarely blocklisted and frequently allowlisted by email gateways and URL-reputation services. From there, the victim is handed to a **self-personalizing malspam kit**: it reads the email address from the URL, rebuilds the page at runtime, and pulls the company logo live — no per-organization lure required.

Once the victim interacts, the operation shifts to layered malware staging: **HTML → JScript → PowerShell → .NET loader → core loader**, leaning heavily on in-memory execution and .NET reflection to stay under the radar. The loader patches AMSI and ETW at the native API level to blind Windows telemetry, hides inside legitimate Microsoft-signed processes (`InstallUtil.exe`, `MSBuild.exe`), and beacons to DDNS C2 domains on a non-standard port to keep infrastructure cheap and rotatable. The likely end goal is data exfiltration, with crypto-mining as a possible follow-on. For organizations in Vietnam, the lesson is blunt: **filtering email on the reputation of the front domain is not enough** — the chain only reveals itself in the later stages.

## Timeline and attribution correction

| Date | Event |
| --- | --- |
| May 2026 | Huntress SOC responded to a .NET loader infection that began with malspam |
| 2026-06-03 | Huntress published the delivery-chain analysis |
| 2026-06-05 | Huntress **issued a correction**: removed the "DesckVB RAT" attribution after review, reassessing it as an **unidentified .NET loader** |

> **Note on naming:** some early reporting (including The Hacker News headline) referred to this malware as *DesckVB RAT*. Huntress retracted that attribution on 2026-06-05. This article uses the neutral term "**.NET loader**" per the researchers' latest assessment.

## Kill chain

## Kill Chain

1.  **Malspam email** — `Bestellung_2026.html` attachment (German-language lure) ↓
    
2.  **0-second meta-refresh** → `ad.doubleclick[.]net` (click-tracking URL, high-reputation Google front) ↓
    
3.  **Redirector** → `fostercareintheus.optimizationprime[.]com` (decodes base64 email) ↓
    
4.  **Delivery kit** → `bth.startthewave[.]org/a/#<email>` (auto-rebrands to victim's company) ↓
    
5.  **POST email** → `pengajian.muliastudy[.]com/images/edu/u.php` → returns ZIP file ↓
    
6.  **JScript loader** — `A021185521S210008-11521.js` → self-copy to `C:\Users\Public\ktncm.js` ↓
    
7.  **PowerShell dropper** — `nlbzl.ps1` → builds `shmvg_01.ps1` (reflective .NET load) ↓
    
8.  **.NET loader** (`03.txt`) — anti-analysis + Defender kill + persistence (NVIDIA-themed) ↓
    
9.  **RunPE injector** (`01.txt`) — process hollowing → `InstallUtil.exe` / `MSBuild.exe` ↓
    
10.  **Core loader** (`bl.txt`) — patches AMSI/ETW (native), multi-layer decryption ↓
     
11.  **C2** — raw TCP + AES/RSA → `xtadts.ddns[.]net`, `afxwd.ddns[.]net`
     

## Technical analysis

### Abusing DoubleClick + a dynamic malspam kit

Initial access arrives via a malspam email with a malicious HTML attachment, `Bestellung_2026.html` ("Bestellung" = German for "order/purchase order"). The file contains nothing but a **0-second meta-refresh redirect** to a Google DoubleClick Campaign Manager click-tracking URL (`ad.doubleclick[.]net/ddm/trackclk/...`), bearing campaign/creative identifiers. The next destination is appended after the `?`, with the recipient's email base64-encoded in the URL fragment.

The rationale for routing through DoubleClick is **filter and reputation evasion**: `ad.doubleclick[.]net` is a high-reputation Google domain that is rarely blocklisted — so the only domain visible at the front of the chain is one defenders are least likely to flag.

![Malicious HTML attachment](https://cdn.builder.io/api/v1/image/assets%2F3eb6f92aedf74f109c7b4b0897ec39a8%2Fb1b9cf21f6ae4833adca0ad95e8303eb align="center")

DoubleClick forwards to `fostercareintheus.optimizationprime[.]com/b#<base64-email>` — a **redirector** stage (it does not serve the kit) that decodes the email and forwards to the kit host `bth.startthewave[.]org/a/#<email>`. Clicking "**PDF herunterladen**" ("Download PDF") triggers `downloadFile()`, which builds a hidden form and POSTs `email=<address>` to `pengajian.muliastudy[.]com/images/edu/u.php`; the server responds with a ZIP (`A021185521S210008-11521.zip`).

The clever part: the lure page is a single self-contained HTML file. `setupEmailAndUI()` reads the email from `window.location.hash`, extracts the domain, then rewrites the page title, header logo, and footer to **impersonate the victim's own employer**. The logo is fetched live via a fallback chain (Clearbit → logo.dev → Google favicons → favicone → DuckDuckGo → the company's `/favicon.ico`). The kit **hardcodes no organization-specific content** — swapping the email rebrands it instantly. `fetchLocationAndTime()` calls `ipapi[.]co/json/` to print the viewer's city/region/country/local time, reinforcing the "personalized and secure" feel.

### JScript loader: evading analysis and self-relocating

The ZIP contains `A021185521S210008-11521.js` — not the final malware but a multi-stage loader, heavily padded with junk (hundreds of repeated dead functions, garbage Unicode strings, `;;;;;` filler, and **Portuguese-language comments**).

![JScript loader contents](https://cdn.builder.io/api/v1/image/assets%2F3eb6f92aedf74f109c7b4b0897ec39a8%2F24e70096089f4706b25c7e3ba79d9bf4 align="center")

On execution, the script checks its own path via `WScript.ScriptFullName`. If it is running from Temp/Downloads (i.e. just extracted), it copies itself to `C:\Users\Public\ktncm.js`, relaunches the copy with `wscript.exe //nologo`, and exits. The second run (from the stable, world-writable location) falls through to the payload-staging logic. The function `vjwNvhDoHz()` repairs a base64 blob mangled with literal `A` characters and the `9999` token (to defeat static detection), decodes it into PowerShell, writes it to `C:\Users\Public\nlbzl.ps1`, and runs it hidden with `-ExecutionPolicy Bypass`.

### The PowerShell stages

`nlbzl.ps1` performs, in order: a **connectivity check** (`Test-Connection www.google.com`) — if offline, it does *not* simply exit but calls `Restart-Computer -Force`; an **anti-analysis sweep** matching running processes against a blocklist (`Dbgview`, `tcpvcon`, `tcpview`, `OLLYDBG`, `ImmunityDebugger`, `Wireshark`, `apateDNS`, plus the strings `any.run`, `sandbox`, `analyze`) — same reboot response on a hit; and a **payload download** via `WebClient`.

![Encoded and obfuscated PowerShell](https://cdn.builder.io/api/v1/image/assets%2F3eb6f92aedf74f109c7b4b0897ec39a8%2Fbd52c97d9195433096f077e1c5a66f8f align="center")

`nlbzl.ps1` acts as a builder: it assembles a further PowerShell script as a string, writes it to `C:\Users\Public\shmvg_01.ps1`, and launches it. That generated script performs the **reflective .NET load** (`[Reflection.Assembly]::Load`), resolves the type `ClassLibrary3.Class1`, and invokes the method `prFVI`. The signed Microsoft binary `InstallUtil.exe` is passed as an argument to `prFVI` for **signed-binary proxy execution**.

### The .NET loader (03.txt)

The `03.txt` payload is a stager: verify it is not being analyzed, disable defenses, download and assemble the next stages, establish persistence, and execute the final payload.

![Hardcoded configuration in the .NET loader](https://cdn.builder.io/api/v1/image/assets%2F3eb6f92aedf74f109c7b4b0897ec39a8%2Fc65a4aac1b6f4c68a654fe42590d006e align="center")

*   **Anti-analysis:** detects VMs/sandboxes (VirtualBox, VMware, Hyper-V, Parallels, QEMU, Sandboxie — including `SbieDll.dll`, `vmhgfs.dll`…), triage services (`mksSandbox`, `joeboxserver`, `triage`), cloud/RDP indicators, BIOS registry values containing "virtual"/"Hyper-V", debuggers, and tooling by process name/window title. On a hit, it writes a **marker file** (`vm.txt`, `Debugger.txt`, `01_detect_analisse_process.txt`) and exits.
    
*   **Staging directory:** creates a deeply nested directory under `%UserProfile%\AppData\LocalLow\` with **NVIDIA-themed** names (`LocalLow Windows`, `Program Rules`, `Program Rules NVIDEO`) to mimic a legitimate driver install path.
    
*   **Defender tampering:** if no Avast/AVG/Malwarebytes is running, it runs PowerShell to disable real-time monitoring, IPS, MAPS, and sample submission, and **adds the entire system drive as an exclusion**; it also kills `QHActiveDefense` (Qihoo 360).
    
*   **Payload retrieval:** uses a hardcoded **IE8 User-Agent** to fetch `bl.txt`, `01.txt`, `02.txt`.
    
*   **Persistence:** Run + RunOnce keys under `HKCU\...\CurrentVersion\` named `Update Drivers NVIDEO_<random>`, launched hidden via `powershell.exe -WindowStyle Hidden`; plus a copy in the **Startup folder**.
    

### Injector (01.txt) + template (02.txt)

`02.txt` is a **PowerShell template** with placeholder tokens; after the loader fills in values, it reflectively loads `01.txt` (`ClassLibrary1.dll`) and invokes its `Run` method. `01.txt` is a .NET DLL performing **process hollowing** via the standard RunPE API chain: `CreateProcessA` (create suspended) → `ZwUnmapViewOfSection` → `VirtualAllocEx` → `WriteProcessMemory` → `GetThreadContext`/`SetThreadContext` → `ResumeThread` (with Wow64 variants for cross-architecture). All API names are mangled; notably the `CreateProcessA` wrapper retains the Portuguese word **"criando"** ("creating").

![DllImport for VirtualAllocEx with obfuscated parameters](https://cdn.builder.io/api/v1/image/assets%2F3eb6f92aedf74f109c7b4b0897ec39a8%2F7644349a10f74e9ca0f88bacd761eb95 align="center")

**The injection target is operator-configurable:** in the statically analyzed sample it was `InstallUtil.exe`, but in live telemetry Huntress observed `MSBuild.exe` being used instead.

### The core loader (bl.txt) and C2

`bl.txt` (injected into `InstallUtil.exe`) is not the final loader but another packing layer: a static constructor reads an embedded resource and decrypts it with a **custom stream cipher** (32-byte key + 16-byte IV, mixed via multiply-accumulate with magic constants 9495/10476/22014 and shift-XOR), optionally LZX-decompresses, then `Assembly.Load`. A further layer uses **TripleDES-CBC (PKCS7) + GZip**. The entire configuration is packed into a single **protobuf** message, base64-encoded, and stored as one string literal.

![Loader configuration](https://cdn.builder.io/api/v1/image/assets%2F3eb6f92aedf74f109c7b4b0897ec39a8%2F176bfc90099f4198ae29471266baea5b align="center")

The loader communicates with C2 over **raw TCP sockets** using **AES-encrypted protobuf** messages; the AES key is derived from the password `P@55w0rd!` via `Rfc2898DeriveBytes` (PBKDF2); **RSA** handles the initial key exchange; and the loader **pins the server identity with five embedded SHA-256 certificate hashes**. On the first beacon it collects a hardware fingerprint (WMI: `Win32_Processor`, `Win32_DiskDrive`, `Win32_BaseBoard`, `Win32_VideoController`, `Win32_OperatingSystem`), enumerates AV via `SecurityCenter2`, and **specifically detects NVIDIA (GTX/RTX) and AMD (Radeon) GPUs** through both WMI and registry — a level of GPU interest that *could* point to crypto-mining as a follow-on, or be used for masquerading.

### Patching AMSI and ETW at the native level

The loader patches **AMSI** and **ETW** at the native API level to blind telemetry before it even sets up persistence:

*   It reads the build number; if **≥ 26100 (Windows 11 24H2)**, it resolves `NtManageHotPatch` from `ntdll.dll` and overwrites its prologue with a stub returning `STATUS_NOT_SUPPORTED` (`0xC00000BB`) — targeting the hot-patch-based AMSI loading mechanism introduced in 24H2.
    
*   On 64-bit systems, it pattern-scans `ntdll.dll` for `EtwEventWrite` and overwrites the entry point with `xor rax, rax; ret`, turning all ETW event logging into a no-op.
    
*   Both use `VirtualProtectEx` → `WriteProcessMemory` → `FlushInstructionCache`. The loader can receive additional payloads from C2 in **three modes**: in-memory injection (RunPE into `MSBuild.exe`/`InstallUtil.exe`, no disk write), PowerShell (`.ps1` via a one-shot scheduled task), or file-drop (AES-decrypt, write to disk, scheduled task).
    

## Indicators of Compromise (IOCs)

> IOCs are defanged. Huntress published the full set on [GitHub threat-intel](https://github.com/huntresslabs/threat-intel/blob/main/2026/2026-06/20260603_fileless-loader-rat.csv).

| Indicator | Description |
| --- | --- |
| `Bestellung_2026.html` | Malicious HTML attachment |
| `fostercareintheus.optimizationprime[.]com` | Redirector stage |
| `bth.startthewave[.]org` | Delivery kit |
| `pengajian.muliastudy[.]com/images/edu/u.php` | Serves the ZIP payload |
| `A021185521S210008-11521.zip` | Delivery ZIP served by kit (u.php) |
| `A021185521S210008-11521.js`, `ktncm.js` | JScript loader |
| `nlbzl.ps1` | PowerShell dropper |
| `shmvg_01.ps1` | PowerShell stager |
| `zkrbx.txt`, `gglhn.txt` | Staging files |
| `andrefelipedonascime1778799406970.2241107.meusitehostgator[.]com[.]br` | Serves `01/02/03.txt` |
| `catalogo.castrouria[.]com` | Serves `bl.txt` (packed loader) |
| `%USERPROFILE%\AppData\LocalLow\LocalLow Windows\Program Rules\Program Rules NVIDEO\...` | NVIDIA-themed staging directory |
| `xtadts.ddns[.]net`, `afxwd.ddns[.]net` | C2 servers (DDNS) |
| `P@55w0rd!` | AES password (PBKDF2) for C2 |
| IE8 UA (`Mozilla/4.0 ... MSIE 8.0 ... Trident/4.0 ...`) | Hardcoded User-Agent for payload retrieval |
| SHA-256 cert pins (×5) | `D5B7247C...59B5`, `C61B1941...01A6`, `C356AFF1...8C18`, `F1C3EBE7...5348`, `E91FB249...74DD` |

## MITRE ATT&CK mapping

| Tactic | Technique | ID |
| --- | --- | --- |
| Initial Access | Phishing: Spearphishing Attachment | [T1566.001](https://attack.mitre.org/techniques/T1566/001/) |
| Execution | User Execution: Malicious File/Link | [T1204.002](https://attack.mitre.org/techniques/T1204/002/) / [.001](https://attack.mitre.org/techniques/T1204/001/) |
| Execution | Command & Scripting: PowerShell / JavaScript | [T1059.001](https://attack.mitre.org/techniques/T1059/001/) / [.007](https://attack.mitre.org/techniques/T1059/007/) |
| Defense Evasion | Obfuscated Files or Information | [T1027](https://attack.mitre.org/techniques/T1027/) |
| Defense Evasion | Deobfuscate/Decode Files | [T1140](https://attack.mitre.org/techniques/T1140/) |
| Defense Evasion | System Binary Proxy Exec: InstallUtil | [T1218.004](https://attack.mitre.org/techniques/T1218/004/) |
| Defense Evasion | Trusted Developer Utilities: MSBuild | [T1127.001](https://attack.mitre.org/techniques/T1127/001/) |
| Defense Evasion | Process Injection: Process Hollowing | [T1055.012](https://attack.mitre.org/techniques/T1055/012/) |
| Defense Evasion | Reflective Code Loading | [T1620](https://attack.mitre.org/techniques/T1620/) |
| Defense Evasion | Impair Defenses: Disable/Modify Tools (AMSI/ETW/Defender) | [T1562.001](https://attack.mitre.org/techniques/T1562/001/) |
| Defense Evasion | Virtualization/Sandbox Evasion | [T1497](https://attack.mitre.org/techniques/T1497/) |
| Persistence | Registry Run Keys / Startup Folder | [T1547.001](https://attack.mitre.org/techniques/T1547/001/) |
| Persistence | Scheduled Task | [T1053.005](https://attack.mitre.org/techniques/T1053/005/) |
| Discovery | System Information Discovery | [T1082](https://attack.mitre.org/techniques/T1082/) |
| Discovery | Security Software Discovery | [T1518.001](https://attack.mitre.org/techniques/T1518/001/) |
| C2 | Non-Application Layer Protocol (raw TCP) | [T1095](https://attack.mitre.org/techniques/T1095/) |
| C2 | Encrypted Channel (AES/RSA) | [T1573](https://attack.mitre.org/techniques/T1573/) |

## Detection

Detection should lean toward **behavior/telemetry**, not payload signatures (given the fileless chain + signed-binary proxy + AMSI/ETW blinding). Huntress's two core hunting hypotheses: alert when `.js/.vbs/.hta` is a child process of `explorer.exe`; and when `wscript.exe` runs from `C:\Users\Public\` and spawns encoded/obfuscated PowerShell.

Suggested KQL for **Microsoft Sentinel / Defender XDR** (`DeviceProcessEvents`, `DeviceRegistryEvents`, `DeviceNetworkEvents`):

```kql
// 1) Script engine running from a world-writable path then spawning hidden PowerShell
DeviceProcessEvents
| where InitiatingProcessFileName in~ ("wscript.exe","cscript.exe")
| where InitiatingProcessCommandLine has @"C:\Users\Public\"
| where FileName =~ "powershell.exe"
| where ProcessCommandLine has_any ("-ExecutionPolicy Bypass","-WindowStyle Hidden","-File","FromBase64String")
| project Timestamp, DeviceName, InitiatingProcessCommandLine, ProcessCommandLine
```

```kql
// 2) Signed-binary proxy: InstallUtil/MSBuild launched by PowerShell (injection host)
DeviceProcessEvents
| where FileName in~ ("installutil.exe","msbuild.exe")
| where InitiatingProcessFileName =~ "powershell.exe"
| project Timestamp, DeviceName, FileName, FolderPath, InitiatingProcessCommandLine
```

```kql
// 3) Persistence: NVIDIA-themed Run/RunOnce keys
DeviceRegistryEvents
| where RegistryKey has_any (@"\CurrentVersion\Run", @"\CurrentVersion\RunOnce")
| where RegistryValueName startswith "Update Drivers NVIDEO"
| project Timestamp, DeviceName, RegistryKey, RegistryValueName, RegistryValueData
```

```kql
// 4) Beacon to known DDNS C2
DeviceNetworkEvents
| where RemoteUrl has_any ("xtadts.ddns.net","afxwd.ddns.net")
   or (RemoteIPType == "Public" and InitiatingProcessFileName in~ ("installutil.exe","msbuild.exe"))
| project Timestamp, DeviceName, RemoteUrl, RemoteIP, RemotePort, InitiatingProcessFileName
```

## Expert opinion

The most notable thing about this campaign is not the loader — which uses known techniques (process hollowing, AMSI/ETW patching, signed-binary proxy) — but the **"borrow the front domain's trust" strategy**. Using `ad.doubleclick[.]net` as the first hop targets an operational weak point in most SOCs: URL/email filtering policies built on domain reputation. When the front-of-chain domain is a Google asset, the gateway almost certainly lets it through, and the malicious payload lives in the later stages that delivery-time inspection misses.

For customer environments in Vietnam — where many organizations rely on reputation-based email gateways and proxies as their primary defensive line — this pattern is especially dangerous. Combining fileless execution + reflective loading + AMSI/ETW blinding leaves signature-only EDR effectively blind. In our analysis team's view, the three controls with the most real-world value here are: blocking the script attachment's ability to *execute* at the very first stage (GPO), inspecting attachments/URLs at **time-of-click rather than time-of-delivery**, and detection based on **process-behavior chains** (script engine → encoded PowerShell → InstallUtil/MSBuild as an injection host) rather than static IOCs — because the C2 uses fast-rotating DDNS, where blocking an IP gets you nowhere.

The German lures and Portuguese code comments suggest a commoditized kit reused across regions — consistent with the trend of malspam becoming more *scalable* while staying *convincing* through runtime personalization. Huntress having to retract the "DesckVB RAT" attribution is itself a useful reminder: **attaching a malware family name too early invites error**, and a good TI report should favor verifiable TTPs/IOCs over an eye-catching label.

## Recommendations

*   **Force scripts to open in Notepad.** Configure a GPO so `.js`, `.vbs`, and `.hta` open in Notepad/Notepad++ by default — neutralizing self-execution at the first stage.
    
*   **Inspect at time-of-click.** Deploy an email gateway with attachment/URL sandboxing; enable Safe Links/Safe Attachments (or equivalent) so URLs and files are inspected at click time, not just on delivery.
    
*   **Block script attachments at the mail layer.** Quarantine or block script files and macro-enabled Office documents at the gateway — a low-effort control that pays dividends.
    
*   **Harden the email perimeter.** Deploy SPF, DKIM, and DMARC to reduce spoofing/impersonation.
    
*   **Detect on behavior, not IPs.** Alert on behavior chains (script engine → encoded PowerShell from `C:\Users\Public\` → `InstallUtil`/`MSBuild` as injection host) and run regular phishing awareness training — the DDNS C2 rotates too fast for IP blocking to matter.
    

## References

*   Huntress — [From Malspam to Fileless .NET Loader](https://www.huntress.com/blog/malspam-to-loader-delivery-chain-analysis)
    
*   Huntress — [IOCs on GitHub (threat-intel)](https://github.com/huntresslabs/threat-intel/blob/main/2026/2026-06/20260603_fileless-loader-rat.csv)
    
*   The Hacker News — [Google DoubleClick Abused in New Malspam Campaign to Deliver .NET Loader](https://thehackernews.com/2026/06/google-doubleclick-abused-in-new.html)
    
*   MITRE ATT&CK — [Process Hollowing (T1055.012)](https://attack.mitre.org/techniques/T1055/012/) · [Reflective Code Loading (T1620)](https://attack.mitre.org/techniques/T1620/) · [Impair Defenses (T1562.001)](https://attack.mitre.org/techniques/T1562/001/)
