typeanalysisfamily54e64econfidencemediumpecompilersigningevasiongolangobfuscationc2infostealer
SHA-256: cc4aa789cf0c80b32004b90be6be0ad80944ad85730c6095cc3ca29469059503

54e64e (misattributed): cc4aa789 — Go 1.25.4 x64 signed infostealer, randomized main functions, no hardcoded C2

Executive Summary

A ~1.9 MB Go 1.25.4 PE64 signed with a Google Trust Services DV certificate (CN=askart.com). The OpenCTI/MalwareBazaar family label 54e64e is here a misattribution — the two prior analysed siblings are MSVC C++ droppers (null-padded and UPX-packed), whereas this sample is a pure-Go binary with randomized main.* function names, GUI subsystem, and runtime-resolved C2. It matches the golang-stealer-build-pattern observed in the unclassified-go-pe64 cluster. No browser-credential strings or hardcoded C2 recovered statically; the threat functionality is almost certainly runtime-decoded or fetched.

What It Is

Attribute Value
SHA-256 cc4aa789cf0c80b32004b90be6be0ad80944ad85730c6095cc3ca29469059503
File type PE32+ executable (GUI) x86-64, 8 sections ^[file.txt]
Size 1,993,344 bytes
Timestamp 0x00000000 (zeroed) ^[pefile.txt:34]
Linker v3.0 (Go internal linker) ^[pefile.txt:46]
Go version go1.25.4 ^[strings.txt:5306]
Build ID txvtqfmPRoj5TvQrtT8l/... ^[strings.txt:9]
Subsystem Windows GUI ^[pefile.txt]
CGO Disabled (pure Go, no C runtime dependency)
Trimpath Inferred — no absolute module paths in strings
Certificate CN=askart.com, issuer=WE1 (Google Trust Services), 4096-bit RSA, SHA-256, serial CDDA1164C88E40890E189788E7C9F32B ^[binwalk.txt]
Resources None ^[pefile.txt]
.rsrc icon Absent (distinguishes from ACR/Lumma siblings that embed PNG icons)

Family ascription — contested. OpenCTI labels this 54e64e + dropped-by-amadey + signed. The two confirmed 54e64e siblings (3b13b28c, c8db13c1) are MSVC C++ droppers with very different build stacks. This Go binary does not share compiler, language, or payload architecture with them. I treat this as a third morph under the same opaque OpenCTI label, functionally belonging to the Go infostealer cluster documented at unclassified-go-pe64.

How It Works

Entry point flow (decompiled from radare2):

  1. PRNG seeding — time.Now → nanoseconds since epoch → math_rand.Seed. The seed is derived from real-time, not hardcoded, producing non-deterministic runtime behaviour. ^[r2:sym.main.main]
  2. Timing measurement — time.Now is captured again after all staged calls; the delta is accumulated in a global counter at 0x140209350. ^[r2:sym.main.main]
  3. Staged function dispatch — main.main calls 24 randomized main.* functions in strict sequence, each performing opaque operations (slice allocations, XOR loops, mutex locks, PRNG draws). No single function name gives away its purpose. ^[strings.txt:5029-5067]
  4. Fingerprinting / environment sampling — Before exit, the binary calls os.hostname, getCurrentProcessId, and Getpagesize, then formats them through a mangled fmt.Sprintf format string. This is consistent with host-fingerprinting or heartbeat-payload construction. ^[r2:sym.main.main]

Anti-analysis features observed:

  • Randomized identifiers — every main package function is a 10–20 character alphanumeric noise string (e.g. Eohbqlwblkqqeo, Cibtvhipz). These are generated at build time; they do not appear in any dictionary. ^[strings.txt:5029-5067]
  • Execution-time gate — The delta between the two time.Now calls is accumulated and presumably checked against a threshold. If the binary runs under a slow debugger or sandbox, the accumulated time may trigger altered behaviour (standard Go anti-sandbox). ^[r2:sym.main.main]
  • No .rsrc section — The binary does not embed an icon or version-info masquerade, unlike the ACR/Lumma cluster which uses 256×256 PNG icons. This may be a stripped-down variant.

Decompiled Behavior

main.main (0x1400a5e80) Initialises a global PRNG from wall-clock time, seeds it, then iterates through ~24 opaque helper functions. After the loop it collects system fingerprint data (hostname, PID, page size), accumulates a timing counter, and outputs via fmt.Sprintf. ^[r2:sym.main.main]

main.Eohbqlwblkqqeo (0x1400a3440) Small utility: draws 100 random integers via math_rand.Intn, sums them, and if the sum exceeds 0xc350 (50,000) adds the difference to the global timing counter. Functions as a PRNG-based delay / noise generator. ^[r2:sym.main.Eohbqlwblkqqeo]

main.Cibtvhipz (0x1400a3560) Allocates a 50-element slice of structs (likely 3×int64 per element), performs unknown index arithmetic. Appears to be a data-structure setup routine. ^[r2:sym.main.Cibtvhipz]

main.Hjimvyukurnuhf (0x1400a3700) Allocates an 8 KB slice, performs per-byte XOR-like mutation, locks a sync.Mutex, and appends to a dynamically-growing slice. The lock + growslice pattern suggests a buffered data collector (possibly clipboard or file content staging). ^[r2:sym.main.Hjimvyukurnuhf]

main.Fgreozkvjbhg (0x1400a3fe0) Allocates 80-element arrays, fills them with linear combinations of indices, then XORs each element with 0xff. This is a lightweight obfuscation/transformation routine, not cryptographic — consistent with hiding a small payload or string blob. ^[r2:sym.main.Fgreozkvjbhg]

No hardcoded C2 recovered. The standard Go net/http, crypto/tls, and crypto/x509 packages are absent from the string table, but syscall and internal/poll are present, so the binary can perform raw Winsock calls. C2 is either:

  • Fetched from a remote configuration at runtime (common in Go stealers), or
  • Encrypted / XOR-decoded inside one of the opaque helper functions.

C2 Infrastructure

Indicator Value Confidence
Hardcoded IPs None recovered —
Hardcoded domains None recovered —
Hardcoded URLs None recovered —
Certificate CN askart.com High
Likely C2 mechanism Runtime resolver or encrypted config (no HTTP package strings) Medium

The askart.com certificate is the only persistent attribution marker. The domain is a throwaway DV cert from Google Trust Services (WE1), valid Apr–Jul 2026. This is identical in intent to the maybe.us cert used by sibling 589af0f8 in the unclassified-go-pe64 cluster.

Interesting Tidbits

  • Family-label pollution. This is the third distinct build morph tagged 54e64e by OpenCTI. The label is effectively an opaque bucket, not a true family. Analysts relying on OpenCTI family labels for clustering will get misleading results. ^[triage.json]
  • No external Go dependencies. Zero github.com/... or golang.org/x/... strings. The binary uses only the Go standard library. This limits fingerprinting but also means the builder is intentionally minimal — no third-party obfuscation frameworks. ^[strings.txt]
  • .symtab retained. Unlike the ACR/Lumma cluster where .symtab is sometimes stripped, this binary keeps its symbol table. 6,832 function symbols remain. Go binaries strip poorly; retaining .symtab suggests either laziness or the build pipeline does not run strip.
  • GUI subsystem with no window code. The PE header declares SUBSYSTEM_WINDOWS_GUI, yet no Win32 window-creation APIs are imported and no window-class strings exist. The binary runs silently in the background. ^[pefile.txt]
  • Certificate serial parity. Serial CDDA1164C88E40890E189788E7C9F32B — 32 hex chars, Google Trust Services standard. Not yet seen in other corpus samples.

How To Mess With It (Homelab Replication)

Reproduce a comparable binary on a research VM:

# Requires Go 1.25.4+
go version

mkdir /tmp/go-stealer-repro && cd /tmp/go-stealer-repro
go mod init xJkLmNpQrStUvWxYz

# main.go — skeleton matching observed patterns
cat > main.go << 'EOF'
package main

import (
    "fmt"
    "math/rand"
    "os"
    "syscall"
    "time"
)

func a1() {}
func a2() {}
func a3() {}
// ... mimic randomized function count

func main() {
    rand.Seed(time.Now().UnixNano())
    for i := 0; i < 100; i++ {
        _ = rand.Intn(1000)
    }
    a1(); a2(); a3()
    host, _ := os.Hostname()
    pid := syscall.Getpid()
    fmt.Printf("%s %d", host, pid)
}
EOF

# Build with matching flags
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build \
  -trimpath \
  -ldflags="-s -w -H windowsgui" \
  -o repro.exe

Verification:

  • rabin2 -I repro.exe → lang: go, subsys: Windows GUI
  • strings repro.exe | grep 'go1.25' → should hit
  • Function names will NOT be randomized unless you additionally use a build script that renames source identifiers, or use a commercial Go obfuscator such as garble.

What you'll learn: How trivial it is to produce a signed-looking silent Go binary that evades family clustering based only on compiler artifacts.

Deployable Signatures

YARA Rule

rule Go_Signed_Infostealer_Askart_2026 {
    meta:
        description = "Go 1.25.4+ signed PE with randomized main functions, no .rsrc, askart.com certificate cluster"
        author = "PacketPursuit"
        date = "2026-06-05"
        hash = "cc4aa789cf0c80b32004b90be6be0ad80944ad85730c6095cc3ca29469059503"
    strings:
        $go_ver = "go1.25." ascii
        $go_build = "Go build ID:" ascii
        $askart = "askart.com" ascii
        $main_pattern = /main\.[A-Za-z]{10,25}/
    condition:
        uint16(0) == 0x5A4D and
        uint32(uint32(0x3C)) == 0x4550 and
        $go_ver and $go_build and
        $askart and
        #main_pattern >= 15 and
        filesize < 3MB
}

Behavioral Hunt Query (Sigma-like pseudocode)

detection:
  selection:
    - Image|endswith:
        - '\repro.exe'
    - CommandLine|contains:
        - 'askart.com'
  # Actual hunt: correlate process creation of Go-signed PE with
  #   (1) no .rsrc section
  #   (2) GUI subsystem
  #   (3) subsequent network connections to non-standard ports
  condition: selection

IOC List

Type Value Context
SHA-256 cc4aa789cf0c80b32004b90be6be0ad80944ad85730c6095cc3ca29469059503 Sample
SHA-1 0a0fc3b88c7e68e4c5c0fdaf9fe29f2b8f4e6e2e (from ssdeep.txt source)
ssdeep 24576:2HU9ZZh3yCLw2NhyZVMXyZvxhxNhiuvcF3A/l2YfTV4ldJBeletL9SryqFpyX2:2HUrX3Xc2+VMXM7b92I66YG Clustering
TLSH T76953A0B7CE508FAD4AAA33289B761917B75BC060F3263C72A90767C2F726E09D75744 Clustering
Cert CN askart.com Attribution marker
Cert issuer CN = WE1 Google Trust Services
Cert serial CDDA1164C88E40890E189788E7C9F32B Revocation check target
Cert SHA1 fingerprint 62:86:CA:BB:F3:42:A1:FD:0C:35:0C:78:66:42:6E:40:C4:C8:CD:58 IOC
Build ID txvtqfmPRoj5TvQrtT8l/xbygvUzLqCWG850ZBN3t/YxLJC9FAisLfnYW-8RPE/e159SqX628yK1-f7dTgz Go build artefact

Behavioral Fingerprint Statement

This binary is a Go 1.25.4 PE64 compiled with CGO_ENABLED=0 and -trimpath, signed with a Google Trust Services DV certificate issued to askart.com. It has no .rsrc section, no embedded icon, and no hardcoded C2 strings in the static image. At runtime it seeds math/rand from wall-clock time, executes ~24 opaque helper functions with randomized names, measures its own execution duration, and samples os.hostname and process ID before formatting the result with fmt.Sprintf. Network activity is expected to be runtime-resolved or encrypted. The certificate and build pattern strongly associate it with the unclassified Go PE64 infostealer cluster.

Detection Signatures (ATT&CK Mapping)

Technique ATT&CK ID Evidence
Obfuscated Files or Information: Software Packing T1027.002 Randomized main.* function names (compile-time identifier obfuscation) ^[strings.txt:5029]
Virtualization/Sandbox Evasion: Time Based Evasion T1497.001 time.Now delta accumulated across function calls; PRNG delay loops ^[r2:sym.main.main]
Masquerading: Match Legitimate Name or Location T1036.005 Authenticode-signed PE with DV cert on throwaway domain askart.com; GUI subsystem with no visible window ^[binwalk.txt]
Ingress Tool Transfer T1105 Inferred — Go infostealer cluster typically fetches stage-2 payload or C2 config at runtime
Exfiltration Over C2 Channel T1041 Inferred — encrypted/synthesised C2 expected from cluster behaviour

References

  • 54e64e — OpenCTI opaque label; prior siblings are MSVC C++ (not Go).
  • unclassified-go-pe64 — Cluster entity for Go-signed infostealers with this build pattern.
  • golang-stealer-build-pattern — Recurring Go infostealer build artefacts.
  • OpenCTI label source: 54e64e, dropped-by-amadey, signed, exe, malware-bazaar ^[triage.json]

Provenance

Static analysis performed on 2026-06-05 using:

  • file v5.44, exiftool v12.76, pefile (Python), rabin2 v5.9.8
  • strings (GNU), floss (attempted — CLI error), capa (signatures missing — error)
  • radare2 v5.9.8 with aa; aang; afl analysis pipeline (2,232 functions recovered)
  • binwalk v2.3.4 — certificate extraction at offset 0x1E6208
  • openssl v3.0.15 — certificate parsing (PKCS#7 DER)
  • No dynamic analysis available — CAPE skipped (no Windows guest online)

No destructive operations were performed.