A reverse shell gives an attacker interactive command-line access to a compromised machine by making the target reach out first. Instead of the attacker connecting inward to a listening port on the victim, the compromised system connects outward to the attacker’s listener. That single inversion is what makes reverse shells so effective: it turns the firewall’s own trust model against the network it is supposed to protect.
Why Reverse Shells Work Where Bind Shells Fail
The older approach, a bind shell, requires an attacker to connect inbound to an open port on the compromised machine. Perimeter firewalls and NAT devices block exactly that kind of connection by default. Many targets sit behind a router with no publicly routable IP address at all, making inbound connectivity impossible without prior exploitation of the network edge.
Reverse shells invert the problem. The victim’s machine connects outward, which firewalls treat as trusted traffic. Aqua Security’s attack documentation summarises the advantage directly: “firewalls primarily filter incoming traffic, so outgoing connections to the receiving server are usually successful.” Attackers pick ports 80 or 443 to blend the connection with legitimate web traffic, further reducing the chance of an alert.
The Attack Setup: Listener and Payload
Before exploiting the target, the attacker starts a listener. Netcat is the standard choice:
nc -nlvp 4444
This command binds to port 4444, listens for an incoming connection, and prints whatever it receives. When the reverse shell payload connects, the attacker’s terminal becomes a remote shell on the target.
The payload itself can take many forms, depending on what the attacker can execute on the target. A Bash one-liner uses the built-in /dev/tcp virtual device to open a TCP connection and redirect the shell’s I/O through it. Python implementations call socket.connect() and then os.dup2() to wire stdin, stdout, and stderr to the socket before spawning /bin/sh. Imperva’s technical overview explains this file descriptor wiring in detail. PHP, Perl, Ruby, and PowerShell all have equivalent one-liners.
Getting the Shell: Delivery and Execution
Landing a reverse shell requires first achieving code execution on the target. Common entry points include:
- Command injection in a web application parameter that gets passed to an OS function without sanitisation.
- Remote code execution vulnerabilities in web frameworks, CMS platforms, or server-side software.
- File upload abuse: uploading a PHP or JSP web shell that then connects back.
- Phishing payloads that execute on a user’s machine and call home to the attacker’s listener.
- Exploitation of unpatched services reachable over the network.
Once execution is achieved, the payload runs, the outbound connection goes through, and the attacker’s Netcat session shows a shell prompt. The whole sequence from triggering the payload to receiving the shell typically takes seconds.
Upgrading the Shell to a Proper TTY
A raw reverse shell connection lacks basic terminal features. Arrow keys move the cursor rather than cycling through history. Ctrl+C kills the session rather than the running process. Tab completion does not work. Attackers who need to work quickly fix this before doing anything else.
The standard fix on Linux is to spawn a proper PTY using Python:
python3 -c 'import pty; pty.spawn("/bin/bash")'
Then background the session with Ctrl+Z, run stty raw -echo on the local machine to disable local echo processing, and foreground the session again. The result is a fully interactive shell with history, tab completion, and proper signal handling. Pentesters typically do this within the first minute of getting a shell.
What Happens After the Shell Lands
The reverse shell is a means, not an end. Once established, an attacker’s workflow typically follows a recognisable pattern.
Local Enumeration
The first task is understanding the environment. The attacker checks which OS and kernel version is running, which users exist, what services listen on internal ports, what network interfaces are present, and whether any credentials or config files are accessible on the filesystem. Tools like uname -a, id, ss -tlnp, and find / -name "*.env" 2>/dev/null give a rapid picture of what has been landed on.
Privilege Escalation
Most initial shell access arrives as a low-privilege user. Escalation paths include kernel exploits, misconfigured SUID binaries, writable cron jobs, services running as root, and weak file permissions on sensitive scripts. On Windows, token impersonation and SeImpersonatePrivilege abuse are common. Automated enumeration scripts surface the most common paths quickly.
Persistence
A raw reverse shell connection drops the moment the exploit process is killed or the server reboots. Persistence mechanisms ensure continued access: cron jobs that reconnect, SSH authorised keys added to a user’s profile, a web shell planted in the document root, or a systemd service added with elevated privileges. Attackers also add a second listener on a different port as a backup.
Lateral Movement
The compromised host rarely holds the most valuable data or access. Using it as a pivot to reach adjacent systems, internal services, and cloud management APIs is the next priority. SSH tunneling, SOCKS proxy chaining, and credential reuse are the standard techniques. Because internal systems are often less hardened than internet-facing ones, the initial compromise of a low-value edge host frequently leads to far more sensitive targets once lateral movement begins.
Reverse Shell Detection: What Defenders Look For
Defenders have reliable signals to work with if they know what to monitor.
The strongest host-based indicator, as Wiz’s detection guidance identifies, is a process with standard input mapped to a network socket. A shell process (bash, sh, cmd.exe) should never have its stdin wired to an external connection. EDR platforms with behavioral analysis catch this pattern. They also flag:
- Web server processes spawning shell children (Apache spawning bash, Nginx spawning sh).
- Scripting interpreters making unexpected outbound TCP connections.
- Base64-encoded PowerShell commands (
-EncodedCommand) executed as child processes. - Unusual file descriptor configurations on running processes.
On the network side, egress monitoring catches reverse shells when they reach uncommon destinations or when the traffic volume and timing match command-and-control patterns. Advanced eBPF-based tooling can correlate the process making a connection with the socket it opened, giving much better context than traditional flow logging.
Stopping Reverse Shells Before They Land
Prevention combines two strategies: close the initial exploitation path and restrict what code can do once it executes.
Patching promptly removes the RCE vulnerabilities that provide the initial foothold. Input sanitisation and a WAF stop command injection at the application layer. Removing interpreters with no legitimate role on a server (Python on a web server that runs Java, for example) reduces the options for reverse shell payloads that rely on specific runtimes.
Egress control is where defenders recover from a successful exploit. A strict outbound allowlist restricts servers to only the external addresses they genuinely need. This forces attackers to route through an approved proxy, which is harder to set up quietly and leaves more detectable evidence. As ThreatLocker’s analysis notes, application allowlisting blocks compiled payloads that do not appear in the approved software catalog. Running services as low-privilege users makes privilege escalation a required additional step rather than an automatic outcome.
