虽然弄出来的,但是感觉不是预期解,所以直接去看的wirteup
,之前没弄过python
框架的站,学习复现一波,学习之路途漫长。。。
一打开就看到这个,可能是爆破的,因为名字都告诉你了,但是还点了几下,发现有登陆和注册功能。
在登陆处,尝试了下万能密码啥的,除了括号也不能用起来的特殊字符,不然就直接返回错误
然后看到了注册页,第一次反应莫不是二次注入
?注入学疯了,然后注册了个用户admin)#
,登陆后,还真有一个修改密码的页。
更加兴奋了。。于是想各种可能是什么SQL
语句,进行构造,但是大量尝试后发现,无法成功,只好安慰自己,一般情况下,都需要引号吧,但是引号不让用。。。
于是回头用burpsuite
跑了一波。。
拦截的时候也很奇怪,居然是以form-data
的格式提交数据,不知道是不是有啥讲究。。。
吃个东西上个厕所,回来就有了。密码居然是123
。。。
登陆后就有flag
了。。。
看大佬们说这个题有3
个答案,不过目前也就看到了前两个成功了,我这里也就尝试抄答案吧
flask中session是存储在客户端cookie中的,也就是存储在本地。flask仅仅对数据进行了签名。众所周知的是,签名的作用是防篡改,而无法防止被读取。而flask并没有提供加密操作,所以其session的全部内容都是可以在客户端读取的,这就可能造成一些安全问题。
github
上有直接的工具可以进行使用,https://github.com/noraj/flask-session-cookie-manager
另外生成admin
的session
还需要一个key
。
这里有存在源码泄露,我是真的没注意到。。。在修改密码的页面中。
下下来以后,就可以做源码审计了,找到key
为ckj123
。
直接运行py
对自己session
进行解密
D:\Tools\01-Hack Penetration\02-Vulnerabilty Analysis\flask-session-cookie-manager>python3 flask_session_cookie_manager3.py decode -s "ckj123" -c "".eJw9kE1rAjEURf9KSVcFFxrrRnBhyRiUvhciqcPLRqwZTeLEwqjMh_jfO7Tg6i4uHM69d7Y9VMXFs-m1uhUDtg2OTe_s5ZtNGUjgKoexTV8dmc0J47xPF5TwAbjm1lhP-SKgXERItlTGnazQLYh1sGbfgqQhRphQWg6VJG6lbpW0CYUvMR5HaKDBnBoUGbcx42SgxugSRSzR6LHN15H4yvesdzC9i9lEJbK6d-JWLBsyH5E6DJhnM_YYsP2lOmyvP6fi_JyAueYUnaduVSq5rKGjFo1PVlCjxML3Ol6ZVcLORxB6QlF3UM_-cCHtjsWT5JL7hPl_c96lvmA7l8L57ZUN2O1SVH_PsdGIPX4BQmpuAA.XoWPQA.O1niFFvonAMPmtrHyBuoo94WVms""
{'_fresh': True, '_id': b'0c69c7fe3a5d603a7b88b3d6e6aaab4ac2fe97dd4204be720f4639bb48f6dd28ff48e6855315f1416f16a3067fb3e547edccbae7813695c8109c6d21a0cc3b5a', 'csrf_token': b'5d6b7ac2e8b036258fd6181a8fa92f78c049b433', 'image': b'vgK0', 'name': 'admin)#', 'user_id': '11'}
然后将名字改成admin
以后,重新生成一次session
D:\Tools\01-Hack Penetration\02-Vulnerabilty Analysis\flask-session-cookie-manager>python3 flask_session_cookie_manager3.py encode -s "ckj123" -t "{'_fresh': True, '_id': b'0c69c7fe3a5d603a7b88b3d6e6aaab4ac2fe97dd4204be720f4639bb48f6dd28ff48e6855315f1416f16a3067fb3e547edccbae7813695c8109c6d21a0cc3b5a', 'csrf_token': b'5d6b7ac2e8b036258fd6181a8fa92f78c049b433', 'image': b'vgK0', 'name': 'admin', 'user_id': '11'}"
.eJw9kE1rAjEURf9KydqFxroRXFgyBqXvhUjq8LIRNaNJnFgYlfkQ_3sHC67u4sLh3Ptg22NVXD2b3qp7MWDb4Nj0wT72bMpAAlc5jG366chszhjnfbqghA_ANbfGesoXAeUiQrKlMu5shW5BrIM1hxYkDTHChNJyqCRxK3WrpE0ofInxNEIDDebUoMi4jRknAzVGlyhiiUaPbb6OxFe-Z32C6V3MJiqR1b0Tt2LZkPmK1GHAPJux54AdrtVxe_s9F5f3BMw1p-g8datSyWUNHbVofLKCGiUWvtfxyqwSdj6C0BOKuoN69sKFtDsVb5JL7hvm_81ll_qC7VwKFzZg92tRvX5joxF7_gFrJm20.XoWYLQ.5dJ1xJ7ymw2q6FrCCTT0e18qGms
这个解法好像才是这个题目想要考查的点,我们可以发现,不管是login、register还是change页面,只要是关于session[‘name’]的操作,都先用了strlower函数将name转成小写,但是python中有自带的转小写函数lower,这里重写了一个,可能有点猫腻,于是找到strlower函数的定义。
def strlower(username):
username = nodeprep.prepare(username)
return username
这里用到了nodeprep.prepare
函数,而nodeprep
是从twisted
模块中导入的from twisted.words.protocols.jabber.xmpp_stringprep import nodeprep
,在requirements.txt
文件中,发现这里用到的twisted
版本是Twisted==10.2.0
,而官网最新版本为19.2.0(2019/6/2)
,版本差距这么大,估计是存在什么漏洞,于是搜索一下nodeprep.prepare
,找到一篇unicode
安全的文章,https://paper.tuisec.win/detail/a9ad1440249d95b
这里原理就是利用nodeprep.prepare
函数会将unicode
字符ᴬ
转换成A
,而A
在调用一次nodeprep.prepare
函数会把A
转换成a
。
所以当我们用ᴬdmin
注册的话,后台代码调用一次nodeprep.prepare
函数,把用户名转换成Admin
,我们用ᴬdmin
进行登录,可以看到index
页面的username
变成了Admin
,证实了我们的猜想,接下来我们就想办法让服务器再调用一次nodeprep.prepare
,其实就是再修改一次密码就可以了,这时就可以把admin
的密码改为任何自己想要改的值。
实际测试了下,确实是可以的。
第三种就没测试了,总结下吧
web
框架