DASCTF & 0X401:EzFlask
DASCTF 2023 & 0X401:EzFlask
打开靶机之后直接给了源码
1 | import uuid |
代码审计
黑名单
此时在代码中定义了check()
函数
1 | def check(data): |
此时会对其做一个过滤;若是在黑名单中变会return Flase
;这也间接的告诉我们存在过滤点
合并函数merge
1 | def merge(src, dst): |
此时出现了合并函数,我们就可以把思路往Ptyhon原型链污染上面靠
注册路由
1 | def register(): |
此时出现了一个注册路由;并且在该路由中使用了合并函数
登录路由
1 | def login(): |
根路由
1 | def index(): |
此时根路由会返回__file__
的文件内容;这也是为什么我们一进去就直接将源码返回给我们的原因
非预期解一:污染为环境变量
此时我们将源码审计完之后思路大致也出来了;既然在根路由return open(__file__, "r").read()
会直接返回__file__
的内容;那么此时我们直接将__file__
污染掉我们想读取的值即可
payload
1 | { |
但是此时发现Register Failed
那么问题应该是出在关键词被过滤的情况
json识别unicode绕过过滤
此时我们再次回到源码发现在注册路由data = json.loads(request.data)
;此时会将数据json
化;我们又知道json识别unicode;所以我们将__init__
进行unicode
编码进行绕过
1 | { |
此时再次刷新触发根路由即可发现污染成功。
非预期解二:static静态目录污染
参考文章:https://boogipop.com/2023/07/22/DASCTF%202023%20&%200X401%20Web%20WriteUp/#EzFlask
_static_url_path
这个属性中存放的是flask
中静态目录的值,默认该值为static
。访问flask
下的资源可以采用如http://domain/static/xxx
,这样实际上就相当于访问_static_url_path
目录下xxx
的文件并将该文件内容作为响应内容返回
payload
1 | { |
app 全局变量
app是 Flask 应用的实例,是一个 Flask 对象。通过创建 app 对象,我们可以定义路由、处理请求、设置配置等,从而构建一个完整的 Web 应用程序。
Flask 应用实例是整个应用的核心,负责处理用户的请求并返回相应的响应。可以通过 app.route 装饰器定义路由,将不同的 URL 请求映射到对应的处理函数上。
app 对象包含了大量的功能和方法,例如 route、run、add_url_rule 等,这些方法用于处理请求和设置应用的各种配置。
通过 app.run() 方法,我们可以在指定的主机和端口上启动 Flask 应用,使其监听并处理客户端的请求。
static_folder 全局变量
static_folder 是 Flask 应用中用于指定静态文件的文件夹路径。静态文件通常包括 CSS、JavaScript、图像等,用于展示网页的样式和交互效果。
静态文件可以包含在 Flask 应用中,例如 CSS 文件用于设置网页样式,JavaScript 文件用于实现网页的交互功能,图像文件用于显示图形内容等。
在 Flask 中,可以通过 app.static_folder 属性来访问 static_folder,并指定存放静态文件的文件夹路径。默认情况下,静态文件存放在应用程序的根目录下的 static 文件夹中。
Flask 在处理请求时,会自动寻找静态文件的路径,并将静态文件发送给客户端,使网页能够正确地显示样式和图像。
预期解:PIN码的计算
此时可以通过dirsearch
扫出一个console
后台
此时的考点就很清楚了;我们需要拿到这个PIN
码才可以接管控制台进而实现rce
;PIN码
也就是flask在开启debug模式下,进行代码调试模式的进入密码,需要正确的PIN码才能进入调试模式
PIN码的计算
PIN码生成六要素
1 | username:可以在任意文件读取下读取 /etc/password 进行猜测 |
PIN码计算脚本
1 | import hashlib |
读取username
payload
1 | { |
username = root
读取moddir
moddir是flask库下app.py的绝对路径,可以通过报错拿到,如传参的时候给个不存在的变量
payload
1 | { |
moddir = /usr/local/lib/python3.10/site-packages/flask/app.py
读取uuidnode
uuidnode:mac地址的十进制:任意文件读取/sys/class/net/the0/address
payload
1 | { |
uuidnode = 121451721339492
读取machine_id
machine_id
机器码,有两个值拼接而成。分别是在/etc/machine-id
和/proc/self/cgroup
其中以docker
为分界
paylaod
1 | { |
machine_id = 96cec10d3d9307792745ec3b85c89620docker-20d650c86c61450efe2a7758e70c0ca3deb6f737281eceee65c9f40abaed161d.scope
利用脚本计算出PIN码
rce
1 | [console ready] |
I-SOON x D0g3:Swagger docs
1 | #coding=gbk |