
Dear blog readers,
Continuing the "When Data Mining Conti Leaks Leads to Actual Binaries and to a Hardcoded C2 With an Encryption Key on Tripod.com - Part Four" blog post series in this post I'll continue analyzing the next malicious software binary which I obtained by data mining Conti Leaks with a lot of success.
The actual malicious software binary location URL:
hxxp://www.delwarren.com/backup/nowin.exe
MD5: 320dd151aed6a181d84e63f78cf801f0
SHA-1: 573e93bb5075ec74ec3c45eaf4190af8e315a429
SHA-256: c366c4e26ec3d2698a94dc04afb58dad429d6c28dff1820d53e277e108103f8f
Here's the analysis.
High-confidence classification
nowin.exe is a Windows x86 network backdoor whose primary behaviors are:
- persistent/repairable multi-threaded C2 beacons (keeps up to 3 concurrent worker threads),
- a custom C2 application protocol (length-framed + lightweight obfuscation using a constant marker),
- remote command execution (via system() with captured output),
- interactive command shell (cmd.exe) over the network,
- a secondary, more complex relay-based shell channel negotiated using a SOCKS-like control exchange.
The overall design is typical of a small bespoke RAT/backdoor: connect to a hardcoded controller, identify/beacon, then loop receiving commands which dispatch into a few core capabilities.
Runtime / threading model
Process start and initialization
Worker thread redundancy (up to 3 concurrent)
This provides resilience: if a connection drops or a thread exits, the malware will try to maintain a small pool of active connections.
C2 infrastructure and basic socket operations
Hardcoded controller address
- C2 IP: 88.214.27.52, constructed at 0x401adc (sprintf("%d.%d.%d.%d", 0x58, 0xd6, 0x1b, 0x34)).
- Port: 443 (htons(0x1bb)), set in connect_to_c2 (0x402aa0).
- Creates TCP socket (via WSASocketA(AF_INET, SOCK_STREAM, IPPROTO_TCP)).
- Uses a non-blocking connect pattern:
- ioctlsocket(FIONBIO, 1) → nonblocking,
- connect,
- select(... writefds ..., timeout=10s) to detect connection completion,
- ioctlsocket(FIONBIO, 0) restore blocking.
- Returns boolean-style success.
This is a common technique for implementing a connect timeout on Windows.
Primary C2 protocol (framing + “AssHole” obfuscation layer)
The malware’s main message channel uses:
- 4-byte length prefix
- encoded payload (obfuscated, not encrypted)
Framing
“AssHole” wrapper purpose and mechanics
- Literal marker: "AssHole" at 0x405558.
- Alphabet used by transform: "0123456789abcdef" at 0x405544.
Both send_data_to_c2 and recv_command_from_c2 incorporate "AssHole" directly into the transform pipeline:
What this achieves
- It is a lightweight obfuscation/encoding layer that:
- makes on-the-wire command tokens/results non-plaintext,
- provides a trivial shared constant that must match between sides (a weak “key”/salt),
- reduces accidental decoding of arbitrary traffic into meaningful commands.
- This is not cryptography; it behaves like reversible per-character nibble transformations over hex-like text.
Command protocol: exact tokens and behaviors
After initial beaconing, backdoor_worker_thread continually:
- recv_command_from_c2 → decodes into a command string
- compares equality against several hardcoded tokens
- dispatches behavior per match
Exact command tokens (as used in comparisons)
The decoded command string is compared against these literal tokens:
Also present in the initial beacon string:
- NUDEew97834g at 0x405244 (0x4070fc) (used as part of the initial identification string, not a compare token in the dispatch shown).
Command behaviors (as implemented)
- Shell/relay initiation
- Remote exec with output capture
- Direct interactive cmd.exe
- Drop/write payload to disk
- Self-move and exit
Reverse shell subsystem: two distinct modes
Mode A: inherited-handle cmd.exe over the connected socket
spawn_reverse_shell (0x402ba0) does the classic redirected-shell pattern:
- Builds command line "cmd.exe",
- Creates process with bInheritHandles=1,
- Sets STARTUPINFOA.hStdInput/hStdOutput/hStdError to the socket handle,
- Waits for process termination.
This provides a direct interactive shell if the controller can speak to the socket as a console stream.
Mode B: relay-based “secondary shell channel” with control handshake
handle_shell_io (0x403360) implements a more complex path that looks like it supports dynamic connection/relay behavior rather than only reusing the initial C2 socket.
On-wire control header:
#pragma pack(push, 1)
typedef struct {
uint8_t magic; // must be 0x05
uint8_t len; // number of payload bytes
uint8_t payload[len]; // expected to include a NUL terminator
} ShellCtrlHeader;
#pragma pack(pop)
Behavior:
- reads 2 bytes + len payload bytes,
- validates magic==0x05 and len!=0,
- validates payload “looks like a C-string” by searching for '\0' from the end,
- sends 2-byte ack: [0x05][0x00] if NUL found else [0x05][0xff].
This is a synchronization trigger for the next-stage negotiation.
Immediately after step 1, it reads and validates a structure that is strongly SOCKS5-inspired:
#pragma pack(push, 1)
typedef struct {
uint8_t ver; // must be 0x05
uint8_t cmd; // saved as `useRelay`
uint8_t rsv; // must be 0x00
uint8_t atyp; // 0x01 IPv4, 0x03 DOMAIN, 0x04 IPv6(16B)
// dstaddr follows (size depends on atyp)
// dstport follows (2 bytes)
} ShellRelayReqHdr;
#pragma pack(pop)
- If atyp==0x01: reads 4 bytes IPv4 into controllerIp.
- If atyp==0x03: reads 1 byte domainLen, reads domainLen bytes, resolves via gethostbyname(), stores first IPv4 into controllerIp.
- If atyp==0x04: reads 16 bytes (IPv6-like); downstream connect-back code still appears IPv4-specific.
- Reads 2 bytes port into controllerPort.
This function also performs response sends (including a distinct error response sequence when domain resolution fails), consistent with a mini-proxy/SOCKS-style negotiation.
Step 3 — connect-back and relay loop
If useRelay == 1, handle_shell_io:
- calls connect_back_to_controller (0x402e80) to create a new socket and connect to the controller-provided endpoint.
- Notable detail: it uses *0xffff0000 as the IP source (a global/shared location used as a scratch/parameter channel) and controllerPort for the port.
- on success, sends a 10-byte “event packet” via send_shell_event (0x402e20), flips both sockets to non-blocking, and enters socket_relay_loop (0x402cf0) to relay data bidirectionally.
Relay implementation details:
Shell event packet (10 bytes)
send_shell_event (0x402e20) sends exactly 10 bytes:
#pragma pack(push, 1)
typedef struct {
uint32_t magic_and_type; // (arg3 << 8) | 0x01000005 => low byte
0x05, next byte = type
uint32_t ip_be; // 32-bit IPv4 value
uint16_t port_be; // 16-bit port
} ShellEventPacket;
#pragma pack(pop)
Used types observed in handle_shell_io:
- type 0 on successful connect-back path,
- type 7 on the failure/alternate path.
Operational picture: full C2 communication process
- Worker thread starts (backdoor_worker_thread), increases global thread count.
- Creates TCP socket → connects to 88.214.27.52:443 with timeout.
- Sends initial beacon string (contains NUDEew97834g and local config values separated by |) using the primary framed+obfuscated protocol.
- Enters command recv loop:
- receive length-prefixed payload,
- decode using "AssHole"-salted obfuscated-hex scheme,
- compare decoded command token to known strings, execute handler.
- Depending on command:
- run cmd.exe over the C2 socket,
- run a relay-negotiated shell channel using a secondary SOCKS-like control exchange,
- execute arbitrary commands via system() and return output,
- drop data to file,
- self-move and exit,
- or spawn additional workers to maintain 3 connections.
Key takeaways for defenders / responders (from a RE standpoint)
- Primary network indicators:
- 88.214.27.52:443 TCP.
- Length-prefixed binary messages (4-byte length) containing obfuscated hex-like content salted with "AssHole".
- Secondary shell negotiation begins with a 2-byte control header starting with 0x05 and then a SOCKS5-like request (ver=0x05, rsv=0, atyp in {1,3,4}).
- The command channel is token-driven; tokens are not human-readable but are fixed literals and can be used for detection after decoding.
- The reverse shell path is strong evidence: CreateProcessA("cmd.exe") with stdio set to the socket and inheritable handles.