前言
这题的三种方法都是姿势盲区。。。。第三种方法只给个介绍。。因为好像复现的话不能成功,但是学习学习这种方法的思想。
姿势总结
- flask session伪造
- unicode欺骗
- 条件竞争
方法一:flask session伪造
我做题目的时候一直以为这题应该是SQL注入。。。在登录那里被卡了好久。。最后发现屁用都没有。。
首先!我们先注册一个再登录,在change password那里查看源码,可以看到有提示:
但是我并没有看到。。。这题也深深的教会了我,虽然页面可能有点多,源码还是要好好看看。。自己以后一定要注意这个,f12看源码的时候一定要仔细而且看全,一定不要漏掉了某个页面。
我们进入这个github,把文件下载下来,发现是flask模板。
然后就引入我们的第一种解法,flask session的伪造。因为flask的session是在客户端的,因此可以尝试进行伪造。破解不难,但是伪造需要密钥。正好密钥就在我们下载的文件夹里:
密钥是ckj123。因此可以进行伪造。
首先是解密,解密脚本如下:
#!/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()))
把name改成admin,再进行加密。加密的脚本这样获取:
git clone https://github.com/noraj/flask-session-cookie-manager
然后进行加密:
再利用伪造的session,成功登录admin账号:
方法二:Unicode欺骗
说实话真的是知识盲区。。。能想出来的大师傅真的是太强了叭。。
首先注意:
更改密码的里面有这样一句代码:
name = strlower(session['name'])
注意strlower:
def strlower(username):
username = nodeprep.prepare(username)
return username
这个nodeprep.prepare存在漏洞。我们还会发现,login的时候又strlower一次。这个本来是转小写的,但是如果我们注册的用户名是这个:
ᴬᴰᴹᴵᴺ
login的时候会经过一次strlower会编程ADMIN,在change password的时候会变成admin。因此可以更改admin的密码,从而完成登录。
具体可查Unicode字符表
ᴀʙᴄᴅᴇꜰɢʜɪᴊᴋʟᴍɴᴏᴘʀꜱᴛᴜᴠᴡʏᴢ
只能说太巧妙了。。。ORZ ORZ ORZ ORZ ORZ
方法三:条件竞争
原理如下:
这个主要就是因为再session赋值的时候都是直接进行赋值,而并没有进行验证,也就是说,比如我们随便注册个用户123,然后进程1再使用用户123重复的进行登录,改密码操作,进程2重复进行注销登录,同时用admin用户和进程2修改的密码进行登录,然后某个时刻进程1刚好要修改密码,进程2恰好要登录,就将进程2 admin的session给了进程1,从而改掉了admin的密码
具体可以参考下面的文章:
一题三解之2018HCTF&admin