Skip to content
shellcodes

Reverse TCP shellcode: the lab checklist I actually use

A practical reverse TCP lab workflow for authorized testing: listener setup, byte checks, and failure modes before you paste shellcode anywhere.

Published on 3 min read

Most reverse TCP tutorials stop at "generate bytes, run exploit". Real labs fail earlier: wrong endianness in the port, a firewall rule you forgot, or shellcode that dies on the first connect because the sockaddr struct is wrong by two bytes.

I treat reverse TCP as a plumbing problem first, shellcode second.

Start with the listener, not the payload

Before you touch a builder, stand up the listener and prove it accepts a connection from the target network path.

nc -lvnp 4444
# or
rlwrap nc -lvnp 4444

If you cannot get a plain TCP connect from the target host to your listener IP, no shellcode variant will save you. I have burned hours tuning encoders while the real issue was a security group blocking egress on non-HTTP ports.

Write down three values and do not improvise them later:

  • listener IP (lab interface, not "whatever my laptop has today")
  • port in host order and network order
  • protocol family (IPv4 vs IPv6)

Shellcode encodes the sockaddr blob. One typo propagates into every encoder pass.

Validate the mission preset against reality

A reverse TCP preset is a template, not permission. Match OS, architecture, and payload type to the binary you control in the lab. Linux x64 reverse TCP against a Windows target is not a clever shortcut. It is a silent waste of time.

In shellcodes, the "Reverse shell lab" preset sets Linux / X64 / ReverseTcp. Good for a clean lab VM. Bad if your exercise is a 32-bit binary or a staged loader with size limits.

Byte-level checks that matter

Copying shellcode is where people get sloppy. I always check:

  1. Null bytes if the delivery path is stack-based or string-sensitive
  2. Bad chars required by the target parser (HTTP, JSON, argv, etc.)
  3. Length relative to the buffer you actually have, not the theoretical maximum

A reverse shell that connects but gets killed by SIGPIPE because stdout is not a TTY is still a win for the lab. You learned the network path works. Do not confuse "no interactive shell" with "bad shellcode".

Operational failure modes

From the attacker side (authorized lab, same mindset):

  • Immediate exit: wrong syscall ABI, wrong stack alignment on x64 Linux
  • Hang with no callback: blocked egress, wrong IP embedded in shellcode
  • Connect then die: listener not ready, port already used, SELinux or AppArmor killing the child process

Logs on the target beat guessing. strace -f ./vuln_binary is ugly and useful.

A minimal runbook I reuse

  1. Listener up and tested with nc from the target subnet
  2. Build reverse TCP with fixed LHOST/LPORT
  3. Export as C array or raw hex depending on the injector
  4. Run bad-char pass before exploit integration
  5. One controlled test fire, capture pcap on the listener interface

Repeatable beats clever. The checklist is boring on purpose.

Where browser-side generation helps

Generating in the browser avoids dragging raw payload bytes through CI logs or ticket systems. That does not remove the need for scope paperwork. It just removes an entire class of accidental leaks from your dev machine clipboard history.

If your lab requires evidence, export the config and hash the byte output. Same bytes tomorrow, same hash. That is how you defend a retest.

Related articles

When to use exec-style shellcode versus reverse TCP in authorized labs, and why the flashy option is often the wrong one.
Why 0x00 breaks strcpy-style delivery, how nulls sneak into reverse TCP structs, and what to do when your encoder pass lies to you.