> ## Content Index
> Fetch the complete content index at: https://f4n6.co.uk/llms.txt
> Use this file to discover other available public pages before exploring further.

# Forty Bytes to the Panel: Feeding a Fresh SNOWLIGHT Windows Stager From an Emulated C2
- URL: https://f4n6.co.uk/forty-bytes-to-the-panel-feeding-a-fresh-snowlight-windows-stager-from-an-emulated-c2/
- Published: 2026-09-28T10:26:10.000Z
- Updated: 2026-09-28T10:26:10.000Z
- Author: Jeff Davies
- Tags: malware, Analysis, threat-research, snowlight, vshell, shellcode-loader, UNC5174, unc6586, tencent-cloud, c2-emulation, RAT

> *A 3.5 KB Windows loader with one import, a split-up C2 address, and a forty-byte handshake it repeats until somebody answers. We answered with an emulated panel and the stager ran our code at high integrity, then parked where we told it to.*

The archive password was `infected`. The executable inside was 3,584 bytes small enough that the first instinct is to check whether the extraction actually finished. It had. What followed was a complete staging loader: hash-resolved imports, a runtime-assembled C2 endpoint, an architecture check-in, a 30 MB executable scratch region, and a single-byte XOR key separating it from whatever the panel chooses to send.

The sample calls itself nothing. VirusTotal had seen it once before, as `eub36.exe` and `windows_amd64.exe`, first submitted on 2026-09-21 six days before it reached the lab. The public record had more to say once we knew where to look: this is a **SNOWLIGHT Windows stager**, the panel-generated delivery stub for the **VShell** remote-access trojan, and the specific variant it stages carries a Windows architecture tag that public reporting had described but never captured on the wire.

## The rig, and what the evidence means

The analysis ran through our malbox tooling. Dynamic execution took place in the isolated VMware guest `for710-win10`, configured with host-only networking and no route to the internet. The guest was reverted to a snapshot before and after each run. Static analysis and Ghidra work happened on the lab host.

Throughout this post, **observed** means recorded during the guest runs. **Static** means reconstructed from the binary or decompiled code. **Inferred** means a plausible explanation that still needs a trace.

That distinction matters here. No successful external C2 connection occurred in our runs the endpoint was unreachable by design. What the wire captures show is the implant's half of the protocol, reproduced under our control. Where we cite third-party observations of the live server, they are exactly that: secondhand, and labelled as such.

## Stage 0: the archive

```text
ae8df01df10e0b80b7f0b150366293e2  (MD5)

Format:     PE32+ GUI executable, x86-64
Size:       3,584 bytes
Sections:   3 (.text, .rdata, .pdata)
Imports:    1 — KERNEL32.dll!Sleep
Imphash:    e82dd51b077167be63c004bed23d0c1e
Entropy:    4.19 overall
Signature:  none

```

A single import of `Sleep` from a GUI executable is not a program that sleeps. It is a program that wants an import table too small to profile everything else gets resolved from memory. The compile timestamp reads 2023-10-26, but the family pins its timestamps (a sibling submission carries one from two weeks earlier while first appearing in the wild in 2026), so we treat it as static decoration, not provenance.

## Static: four functions, one job

Ghidra found four functions. One is the resolver, two are scaffolding, and one is the show.

The resolver (`FUN_14000145c`) walks the PEB's `InMemoryOrderModuleList`, hashes each module's base name and each export name with the classic rotate-accumulate scheme `h = rol32(h, 19) + c`, which is ROR-13 by another name and returns the address whose hash matches the caller's constant. Mixed-case module names are normalised by uppercasing characters above `0x60` before hashing. Nothing here is novel; everything here is competent.

The loader, in order:

1. Resolves `LoadLibraryA` and ten more API addresses by hash, loading `user32.dll`, `ws2_32.dll`, and `msvcrt.dll`.
2. Builds its C2 address at runtime by concatenating four fragments `"49.2"`, `"32.1"`, `"83.8"`, `"7"` through `sprintf("%s%s%s%s")`. A plain `strings` pass shows nothing; the endpoint never exists as a contiguous literal in the file.
3. Checks a marker file at `%TEMP%\log_de.log` before anything else.
4. Enters a connect loop against `49.232.183.87:18080` (the sockaddr carries `0xa046` in network byte order), sleeping ten seconds between attempts. There is no exit from this loop except success.
5. Sends a 40-byte check-in.
6. Allocates exactly 30,000,000 bytes of `PAGE_EXECUTE_READWRITE` memory.
7. Receives the next payload in `0x64000`\-byte chunks until the server closes the connection, XOR-decoding every byte with `0x99` as it arrives.
8. Closes the socket and calls the decoded buffer.

The stager authenticates nothing. There is no signature check, no size header, no `MZ` validation a 30 MB window with no enforced boundary, filled by whoever answers the socket, and then executed. The panel stager is small because it delegates trust and memory safety to the other end of the wire.

## The kill switch, settled by experiment

Public reporting on SNOWLIGHT's `%TEMP%\log_de.log` check disagrees about polarity. We settled it for this variant, with controls:

- With `log_de.log` present in `%TEMP%` (content irrelevant ours held one word), the loader **exited within seconds and made zero connection attempts**. No SYN left the guest.
- With the file deleted, the same launch produced a live process that persisted in its retry cycle.

So for the Windows stager: the file's presence terminates it. This also makes the check a defensive lever planting the file neuters this loader family on a machine and, with the caveat that we have not observed what the stage does about it, a potential canary. The polarity of the ELF variants reported by Sekoia may differ; we have not tested those.

## The beacon on the wire

With the guest isolated, the implant's SYNs die at the virtual switch. To learn more than the destination, we brought the panel to it: assigned `49.232.183.87/32` as a secondary address on the guest's own NIC and ran a small listener on port 18080 inside the guest. The hardcoded endpoint now resolved to a local stack we controlled.

The implant connected and sent the same forty bytes on every run, across several detonations:

```text
77 36 34 20 20 20 46 a0 34 39 2e 32 33 32 2e 31
38 33 2e 38 37 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00

```

| Offset | Bytes              | Meaning                               |
| ------ | ------------------ | ------------------------------------- |
| 0–5    | 77 36 34 20 20 20  | "w64 " — Windows x64 architecture tag |
| 6–7    | 46 a0              | Port 18080, network byte order        |
| 8–20   | 34 39 2e ... 38 37 | ASCII "49.232.183.87"                 |
| 21–39  | 00 × 19            | Zero padding                          |

The check-in carries the platform tag, the port, and the C2 string the implant was built with. SOCRadar's July 2026 report documented the tag scheme from exposed ELF loaders `l32`/`l64`/`a32`/`a64`, plus `w32`/`w64` for a Windows port they noted had not been seen in public reporting. Our capture is that missing wire-level description: `w64` behaves exactly like its Linux siblings raw TCP, same frame, same trust model.

## Feeding it a payload

With the emulated panel in place, the remaining question was what code execution actually looks like. Rather than deliver unknown second-stage content or weaponised shellcode, we assembled our own benign x64 payload 435 bytes, position-independent, resolving `LoadLibraryA` and `GetProcAddress` from the PEB with the same rotate-13 hashing the stager itself uses, then calling `WinExec` and `MessageBoxA` by name.

The emulated C2 logged the beacon, served the payload XOR-encoded with `0x99`, and closed the connection. The stager decoded it, called it, and the payload ran:

- `whoami /all` output written to disk by a `cmd.exe` the served code had spawned — **observed**, in the artifact pulled back from the guest.
- Process context: `FOR710-WIN-VM\rem`, member of **Administrators**, **High mandatory level**, BATCH logon type. On a real victim, everything the user can touch, the stager can touch, with no elevation step.
- The implant then parked inside the `MessageBoxA` call still alive at collection, waiting for input on a desktop nobody could see returning only when the served code decided to. The C2 owns the thread for as long as its payload wants it.

One connection, one download, one execution, and then silence: staging is one-shot. Any persistence or sustained channel is the second stage's problem which is what a VShell core is for.

## What the public record says

With the family identified, the picture assembles quickly:

- **SNOWLIGHT** was named by Mandiant tracking **UNC5174**, a China-nexus access broker, in campaigns against F5 BIG-IP and ScreenConnect devices. Sysdig documented the actor's shift to **VShell**, an open-source Go RAT published by GitHub user "veo" in 2024, loaded filelessly through SNOWLIGHT.
- Sekoia's configuration-extraction series dissected the ELF loader; Talos covered SNOWLIGHT-delivered VShell under **UAT-8302**; Google Threat Intelligence Group documented SNOWLIGHT-delivered VShell from actors exploiting React2Shell, associating the ecosystem with **UNC6586**; EclecticIQ tied it to SAP NetWeaver exploitation; SOCRadar analysed an exposed staging server containing the full toolkit.
- The important correction came from Trend Micro: a SNOWLIGHT-to-VShell intrusion initially assigned to UNC5174 was re-attributed to **Earth Lamia** on packaging artifacts, with the explicit warning that SNOWLIGHT alone is unreliable for attribution — because it is the **default stager the VShell panel generates**. Cracked and leaked VShell builds have since spread the framework well beyond its original users. Google describes VShell as publicly available and used by actors with varying motivations.

Our sample's infrastructure fits the commodity end of that ecosystem. The C2 host, `49.232.183.87`, is Tencent Cloud (AS45090, block allocated 2010, registered to Tencent Cloud Computing (Beijing)). ThreatFox carried the IP with port 18080 on 2026-09-01\. A Joe Sandbox analysis of a larger Windows loader from the same naming series samples arrive as ten random characters plus an extension, with `windows_amd64.exe` as a recurring internal name recorded **bidirectional traffic with this exact IP:port on 2026-09-22**, and extracted a VShell configuration:

```json
{"server": "49[.]232.183.87:18080", "type": "tcp", "vkey": "qwe123qwe",
 "salt": "qwe123qwe", "proxy": "", "l": false, "e": false, "d": 30, "h": 10}

```

Authentication key and salt set to `qwe123qwe`. A panel operator who used a keyboard walk for their credentials is not behaving like an espionage contractor, and we draw no attribution from the tooling. The same infrastructure served Linux ELF droppers in adjacent sandbox analyses the campaign is cross-platform, as the panel's staged-delivery design implies. A sibling loader with the same technique stack (PEB walking, ROR-13 resolution, XOR `0x99`) used a different C2 (`216[.]126.225.156`) over HTTP with a spoofed Firefox user agent, consistent with operators rotating infrastructure per batch.

## What we would tell a defender

- The reliable network indicator is the destination pair `49[.]232.183.87:18080`, but the more durable detection is the beacon shape: a TCP payload of exactly 40 bytes beginning with `"w64 "` (or its platform siblings), sent immediately after a connection to a non-standard port, repeated on a ten-second cycle until answered. That rule survives infrastructure rotation.
- On the host, the marker file check is a cheap tripwire: `%TEMP%\log_de.log` appearing in process-access telemetry around an unsigned small binary is a strong SNOWLIGHT signal and planting the file pre-empts this loader family entirely.
- The RWX 30,000,000-byte allocation followed by socket-to-memory streaming is a host-side signature in its own right, and it will not change until the panel's stager generator does.
- Do not attribute on the stager. The architecture tag tells you which platform the operator selected in a panel, not who was using it.

## Indicators

```text
C2 (this sample)    49[.]232.183.87:18080/tcp   SNOWLIGHT staging + VShell panel
Sibling C2          216[.]126.225.156           same loader series, HTTP variant
Sample SHA-256      e08d62943df1d69416e4a0511a157b1b994577f86a05fb8de4e8f7cb5ece09b3
Sibling SHA-256     ab6677fcbbb1ff4a22cc3e7355e1c36768ba30bbf5cce36f4ec7ae99f850e6c5
Larger loader       a5888f690801f422a9da5bfc2604c9a9205a12d10e33741e8a5eef997be52cb3
Imphash             e82dd51b077167be63c004bed23d0c1e
Kill switch         %TEMP%\log_de.log  (presence terminates the Windows stager)
Beacon              40 bytes: "w64   " + port + C2 IP + zero padding
Stage obfuscation   single-byte XOR, key 0x99

```

## Sources

- Sysdig Threat Research "UNC5174's evolution in China's ongoing cyber warfare: From SNOWLIGHT to VShell" (2025-04-15)
- Himanshu Anand "A fake resume invoked China's defence-tech elite, then installed VShell" (2026-08-01)
- SOCRadar Threat Research "Tracing SNOWLIGHT: A Government-Targeted Chinese Campaign" (2026-07-31)
- Sekoia "Advent of Configuration Extraction, Part 3: SNOWLIGHT loader" (2025-12-15)
- Malpedia `elf.snowlight`, `win.rozena` (Fraunhofer FKIE)
- Joe Sandbox analyses 1975906, 1976046 (sample `a5888f690801f422a9da5bfc2604c9a9205a12d10e33741e8a5eef997be52cb3` ELF variants)
- OffSeq Threat Radar ThreatFox IOC digest for 2026-09-01
- VirusTotal file
- `e08d62943df1d69416e4a0511a157b1b994577f86a05fb8de4e8f7cb5ece09b3`, IP `49.232.183.87`, file `ab6677fcbbb1ff4a22cc3e7355e1c36768ba30bbf5cce36f4ec7ae99f850e6c5`