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 seedingtime.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 measurementtime.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 dispatchmain.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.exelang: 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.