绕过
常见绕过
os.path.join()
如果一个参数是以/
符号开头的,就将这个参数作为开头继续向后拼接。
os.path.join('uploads/', '/flag') => '/flag'
render_template()
模板渲染,缓存机制:首先会检查是否有缓存,如果缓存可用就使用缓存,缓存不可用就加载模板。
Cache_size
默认是 400,使用 LRUCache,默认将最常用的页面缓存起来,便于之后的使用,每次访问页面都会将这个页面放到cache的最前方,同时,处于cache后方的页面,由于长期得不到访问,在超过cache规定的最大限制之后,将会被移除出缓存中。
SSTI
见SSTI。
session伪造
在Flask中,session是保存在Cookie中,也就是本地,所以可以直接读取其内容,也就产生了Flask伪造session的漏洞。
工具
加密:
flask_session_cookie_manager{2,3}.py encode [-h] -s <SecretKey> -t <SessionCookieStructure>
解密:
flask_session_cookie_manager.py decode [-h] [-s <Secretkey>] -c <Session CookieValue>
加密:
flask-unsign --sign --cookie "<Session CookieValue>" --secret '<Secretkey>'
解密:
flask-unsign --decode --cookie '<SessionCookieStructure>'
爆破key:
flask-unsign --unsign --cookie '<SessionCookieStructure>'
解密脚本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32import sys
import zlib
from base64 import b64decode
from flask.sessions import session_json_serializer
from itsdangerous import base64_decode
def decryption(payload):
payload, sig = payload.rsplit(b'.', 1)
payload, timestamp = payload.rsplit(b'.', 1)
decompress = False
if payload.startswith(b'.'):
payload = payload[1:]
decompress = True
try:
payload = base64_decode(payload)
except Exception as e:
raise Exception('Could not base64 decode the payload because of '
'an exception')
if decompress:
try:
payload = zlib.decompress(payload)
except Exception as e:
raise Exception('Could not zlib decompress the payload before '
'decoding the payload')
return session_json_serializer.loads(payload)
if __name__ == '__main__':
print(decryption(sys.argv[1].encode()))参考
Flask debug PIN
PIN码是Flask在开启debug模式下,进行代码调试模式的进入密码,需要正确的PIN码才能进入调试模式。
计算逻辑位于 python3.x/site-packages/werkzeug/debug/__init__.py#get_pin_and_cookie_name
,版本不同的区别在于3.6与3.8的md5加密和sha1加密不同。
PIN生成要素:
username
用户名。通过
getpass.getuser()
读取,通过文件读取/etc/passwd
。modname
模块名。通过
getattr(mod,"file",None)
读取,默认值为flask.app
。appname
应用名。通过
getattr(app,"name",type(app).name)
读取,默认值为Flask
。moddir
Flask库下
app.py
的绝对路径。通过getattr(mod,"file",None)
读取,实际应用中通过报错读取。uuidnode
当前网络的mac地址的十进制数。通过
uuid.getnode()
读取,通过文件/sys/class/net/eth0/address
得到16进制结果,转化为10进制进行计算。machine_id
docker机器id。每一个机器都会有自已唯一的id,linux的id一般存放在
/etc/machine-id
或/proc/sys/kernel/random/boot_id
,docker靶机则读取/proc/self/cgroup
,其中第一行的/docker/
字符串后面的内容作为机器的id,在docker环境下读取后两个,非docker环境三个都需要读取。
PIN生成脚本:
1 | # <3.8 MD5 |
1 | # >=3.8 sha1 |
参考:
ctfshow - web 801
GYCTF 2020 - FlaskApp
*CTF - oh-my-notepro