平时接触到的 python 项目并不多,对 python 的代码审计更是没有接触,偶然朋友发来了一个漏洞 Flask send_file函数导致的绝对路径遍历 ,感觉打开了新世界的大门,于是就以一个初学者的角度,进行复现分析一下。详情也可以根据 Python : Flask Path Traversal Vulnerability 进行分析学习
send_file 的妙用
在以 flask 框架开发的系统中,为了直接实现用户访问某一个 URL 时就可以下载到文件,我们就使用 send_file 来实现- from flask import Flask<br>from flask import send_file<br><br>app = Flask(__name__)<br><br><br>@app.route('/download')<br>def downloadFile():<br> path = "test.txt"<br> return send_file(path)<br><br><br>if __name__ == '__main__':<br> app.run()
复制代码 [img=720,320.8781558726674]https://www.hetianlab.com/headImg.action?news=74f22eab-959f-495b-af77-db123b0d950e.png[/img]
我们看到 如此运行的效果是直接返回了文件的内容,浏览器并没有识别成一个文件下载下来。
要想让浏览器识别成为文件下载的话,只需要加上 as_attachment=True- from flask import Flask<br>from flask import send_file<br><br>app = Flask(__name__)<br><br><br>@app.route('/download')<br>def downloadFile():<br> path = "test.txt"<br> return send_file(path, as_attachment=True)<br><br><br>if __name__ == '__main__':<br> app.run()
复制代码
[img=720,200.67226890756302]https://www.hetianlab.com/headImg.action?news=59a7fead-9117-495d-990b-bd243dd915d9.png[/img]
当下载的文件名是中文时- from flask import Flask<br>from flask import send_file<br><br>app = Flask(__name__)<br><br><br>@app.route('/download')<br>def downloadFile():<br> path = "测试.txt"<br> return send_file(path, as_attachment=True)<br><br><br>if __name__ == '__main__':<br> app.run()<br>
复制代码 [img=720,240.8261617900172]https://www.hetianlab.com/headImg.action?news=7ebb54dc-09a9-466b-9212-11c626d9fe0a.png[/img]
Content-Disposition:
Content-Disposition
在常规的 HTTP 应答中,Content-Disposition 响应头指示回复的内容该以何种形式展示,是以内联的形式(即网页或者页面的一部分),还是以附件的形式下载并保存到本地。其可以是inline(默认值,所以可以不指定)或者是attachment,attachment表示附件,浏览器看到这个值一般会弹出一个保持文件的确认框,或者像chrome直接下载。
[img=720,340.86614173228344]https://www.hetianlab.com/headImg.action?news=c91999b7-cd43-4584-95f0-9fc1fe08c650.png[/img]
[img=720,481.174168297456]https://www.hetianlab.com/headImg.action?news=bf2d86b0-041e-4f8f-a33e-552f78d17448.png[/img]
【----帮助网安学习,以下所有学习资料免费领!加vx:yj009991,备注 “博客园” 获取!】
① 网安学习成长路径思维导图
② 60+网安经典常用工具包
③ 100+SRC漏洞分析报告
④ 150+网安攻防实战技术电子书
⑤ 最权威CISSP 认证考试指南+题库
⑥ 超1800页CTF实战技巧手册
⑦ 最新网安大厂面试题合集(含答案)
⑧ APP客户端安全检测指南(安卓+IOS)
漏洞分析
漏洞的触发是在 send_file 中,我们跟进看一下
flask.helpers.send_file
[img=720,506.6181818181818]https://www.hetianlab.com/headImg.action?news=8008577a-d159-4e0a-811e-d8d9ffc0df20.png[/img]
继续跟进查看
werkzeug.utils.send_file
[img=720,363.43949044585986]https://www.hetianlab.com/headImg.action?news=782b0f8f-e3ba-4e2e-b10e-644904ee67ea.png[/img]
我们在本地构造一个简单的语句进行尝试- >>> import os.path<br>>>> _root_path = "path/to/mySafeStaticDir"<br>>>> path_or_file = "/../../../../../../../etc/passwd"<br>>>> os.path.join(_root_path,path_or_file)<br>'/../../../../../../../etc/passwd'
复制代码 [img=720,150.55762081784385]https://www.hetianlab.com/headImg.action?news=676ad329-3cb7-44a9-8e65-ba24be876a14.png[/img]
我们发现 os.path.join 使用不受信任的输入调用时不安全的。当 os.path.join 调用遇到绝对路径时,它会忽略在该点之前遇到的所有参数并开始使用新的绝对路径。当参数可控时,我们控制恶意参数输入绝对路径,os.path.join 会完全忽略静态目录。所以,当 os.path.join 来获取来自 flask.send_file 的不受信任的输入时,可能会目录遍历攻击。
漏洞复现
我们在本地构造简单的代码进行测试,获取从外部传入的参数 filename- from flask import Flask, request<br>from flask import send_file<br><br>app = Flask(__name__)<br><br><br>@app.route('/download')<br>def downloadFile():<br> filename = request.args.get('filename')<br> return send_file(filename, as_attachment=True)<br><br>if __name__ == '__main__':<br> app.run()
复制代码 通过控制 filename 为绝对路径,就实现了目录穿越漏洞
[img=720,330.37714285714287]https://www.hetianlab.com/headImg.action?news=0b66a0a9-14b7-452c-9285-64b16204ce2a.png[/img]
[img=720,154.28571428571428]https://www.hetianlab.com/headImg.action?news=8159a9d4-b783-4c55-83ad-868dae93a892.png[/img]
总结反思
这个漏洞非常的有趣,漏洞的修复是可以使用flask.safe_join加入不受信任的路径或用flask.send_file调用替换flask.send_from_directory调用。
这个漏洞虽然很简单,但是在 github 上很多用 python 开发的项目都用了这个函数,如果不加以修复,会造成很大的危害。
更多靶场实验练习、网安学习资料,请点击这里>>
搜索
复制
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |