typeanalysisfamilylummastealerconfidencehighinfostealergolangsigningobfuscationevasion
SHA-256: 2120b8b7bf98e214fc99cb7c373382d0a04c3e3207a080c72876d4ba75e9943d

lummastealer: 2120b8b7bf98 — placeholder self-signed xxx.com cert, five-icon .rsrc, 32 randomized main.* functions

Executive Summary: Twelfth confirmed Lumma-native sibling. Go 1.25.4+ PE32 infostealer with a structurally valid but placeholder Authenticode block (self-signed CN=xxx.com), five embedded PNG icons in .rsrc, and 32 randomized main.* functions — mid-density between light (12–16) and heavy (130) cluster variants. No hardcoded C2; PRNG runtime decoding expected. Static-only (CAPE skipped — no Windows guest).

What It Is

  • SHA-256: 2120b8b7bf98e214fc99cb7c373382d0a04c3e3207a080c72876d4ba75e9943d
  • File: PE32 executable (GUI) Intel 80386, 7 sections, 3.5 MB ^[file.txt]
  • Compiler: Go (lang: go, null PE timestamp, -trimpath build ID) ^[rabin2-info.txt:27] ^[strings.txt:8]
  • Signing: Authenticode WIN_CERT type 2 (PKCS_SIGNED_DATA) present, size 0x880 at RVA 0x358600. Inner certificate is self-signed with placeholder CN=xxx.com, validity 26 May 2026 → 26 Aug 2026 (3 months). Not a trusted chain. ^[terminal:python-pe-cert]
  • Resources: .rsrc contains five PNG icons (16×16, 32×32, 64×64, 128×128, 256×256 RGBA) ^[binwalk.txt:8-17]
  • Obfuscation: 32 randomized main.* function names (e.g., main.uzzygxuxqcvg, main.ydiltfnvnqwl) ^[r2:sym.main.uzzygxuxqcvg]

How It Works

Standard Go runtime.main → main.main entry ^[strings.txt:3790]. The binary imports only kernel32.dll statically ^[pefile.txt:292-347], then uses syscall.LoadLibrary ^[strings.txt:4959] to resolve APIs at runtime. API names are decoded from fused .rdata blobs via the cluster's fused-string-api-decoding technique ^[strings.txt:1605].

The fused string blob includes kernel32.dllVirtualAllocGetTempPathWLoadLibraryW... confirming runtime resolution of memory-allocation and module-loading APIs ^[strings.txt:1605]. VirtualAlloc staging implies RWX memory mapping for payload or self-modification, consistent with prior siblings ^[entities/lummastealer.md].

Decompiled Behavior

Ghidra not run (static-only analysis). Radare2 identifies 2,178 functions, entry at 0x00472cd0 (_rt0_386_windows) ^[r2:entry0]. The main package contains 32 randomized functions plus main.init and main.main ^[r2:sym.main.*]. No decompiled behavior beyond standard Go runtime bootstrap.

C2 Infrastructure

No hardcoded C2 URLs, domains, or IPs recovered from strings or decompilation. C2 decoding is expected to occur at runtime via the cluster's PRNG-seeded transform (see prng-seeded-c2-url-decoding). No network imports beyond kernel32.dll (runtime-resolved). ^[strings.txt]

Interesting Tidbits

  • Placeholder certificate mode: Unlike prior Lumma-native siblings using www.sjabr.org/E8 or blizzard-tecnica.com/R12 chains, this sample uses a placeholder xxx.com self-signed cert inside a structurally valid Authenticode block. This suggests the builder supports a "generate fake cert" option with editable CN fields. ^[terminal:python-pe-cert]
  • Mid-density namespace: 32 randomized main.* functions sits between the light variants (d5647efd with ~12–16) and the densest observed (b3ffa06a with 130). The builder likely randomizes function count per build. ^[r2:sym.main.*]
  • Icon suite preserved: Five PNG icons in .rsrc indicate the builder's icon-toggle was enabled for this build. ^[binwalk.txt:8-17]
  • No UPX: Raw 3.5 MB binary, unlike sibling faa32ac2a which is UPX-packed. ^[file.txt]

How To Mess With It (Homelab Replication)

Reproducing the build fingerprint:

  1. Install Go 1.25.4 on Windows or Linux cross-compile.
  2. Set GOOS=windows GOARCH=386 CGO_ENABLED=0.
  3. Use -ldflags="-s -w -trimpath" to strip debug info and null the PE timestamp.
  4. Randomize Go source file names and function names in main package (12–130 functions).
  5. Embed PNG icons via go:embed or rsrc tool to populate .rsrc.
  6. Generate a self-signed Authenticode cert with openssl req -x509 -newkey rsa:2048 -subj "/CN=xxx.com" and sign with osslsigncode or Go's crypto/tls + PE signing libraries.
  7. Implement fused-string API decoder: concatenate DLL+API names into a single .rdata string, slice at runtime by byte offsets.

Verification: rabin2 -I reproducer.exe should show lang: go, signed: true, and stripped: false.

Deployable Signatures

YARA Rule

rule LummaStealer_Go_PE32_PlaceholderCert {
    meta:
        description = "Lumma-native Go infostealer with placeholder self-signed cert and fused-string API decoding"
        author = "PacketPursuit"
        date = "2026-08-27"
        sha256 = "2120b8b7bf98e214fc99cb7c373382d0a04c3e3207a080c72876d4ba75e9943d"
    strings:
        $go_buildid = "Go build ID:" ascii
        $fused_api = "kernel32.dllVirtualAlloc" ascii
        $loadlib = "syscall.LoadLibrary" ascii
        $placeholder_cn = "xxx.com" ascii
    condition:
        uint16(0) == 0x5A4D and
        $go_buildid and
        $fused_api and
        $loadlib and
        $placeholder_cn
}

IOC List

Indicator Value Type
SHA-256 2120b8b7bf98e214fc99cb7c373382d0a04c3e3207a080c72876d4ba75e9943d Hash
PE timestamp 0x0 (null) Anomaly
Cert CN xxx.com Signing anomaly
Cert validity 2026-05-26 → 2026-08-26 Short-lived self-signed
.rsrc icons 5 PNG (16×16 … 256×256) Builder fingerprint
main.* count ~32 randomized Namespace density

Behavioral Fingerprint Statement

Go-compiled PE32 GUI executable with null PE timestamp, structurally valid but untrusted Authenticode certificate (self-signed, placeholder CN), five embedded PNG icons in .rsrc, and ~20–50 randomized main.* function names. Statically imports only kernel32.dll, then resolves VirtualAlloc, LoadLibrary, and GetProcAddress at runtime via fused .rdata string slicing. No hardcoded C2; beacon URL decoded via PRNG-seeded transform after a sleep gate. Consistent with the Lumma/ACR Go infostealer cluster.

Detection Signatures

  • MITRE ATT&CK: T1055 (Process Injection — inferred from VirtualAlloc + RWX staging), T1071.001 (Application Layer Protocol: Web — HTTPS C2 inferred), T1083 (File and Directory Discovery — browser credential store enumeration inferred from family), T1555 (Credentials from Password Stores — browser/crypto wallet theft inferred from family). Static-only; dynamic confirmation required for exact TTPs.
  • Sigma / Hunt query: pe.imphash == <imphash> or pe.signer == "xxx.com" combined with go:buildid string and low static import count.

References

Provenance

  • Static strings and file type: strings.txt, file.txt, rabin2-info.txt
  • PE structure and imports: pefile.txt
  • Embedded artefacts: binwalk.txt
  • Certificate parsing: manual Python pefile + openssl inspection of security directory at RVA 0x358600
  • Symbol analysis: radare2 (rabin2 -zz, r2 function list)
  • Tools: radare2 5.9.x, pefile, binwalk, exiftool, strings