源代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| const express = require('express') const fs = require('fs') var bodyParser = require('body-parser'); const app = express() app.use(bodyParser.urlencoded({ extended: true })); app.use(bodyParser.json());
app.post('/plz', (req, res) => {
venom = req.body.venom if (Object.keys(venom).length < 3 && venom.welcome == 159753) { try { if(venom.hasOwnProperty("text")){ res.send(venom.text) }else{ res.send("no text detected") } } catch { if (venom.text=="flag") { let flag=fs.readFileSync("/flag"); res.send("Congratulations:"+flag); } else { res.end("Nothing here!") } } } else { res.end("happy game"); } })
app.get('/', function(req, res, next) { res.send('<title>oldjs</title><a>Hack me plz</a><br><form action="/plz" method="POST">text:<input type="text" name="venom[text]" value="ezjs"><input type="submit" value="Hack"></form> '); });
app.listen(80, () => { console.log(`listening at port 80`) })
|
分析
从以上代码可以得知,想要得到flag,要经过三重判断:
1、venom这个对象的键不能超过3个,且venom.welcome = 159753
2、venom中不能含有text这个键
3、venom.text = ‘flag’
看起来2和3好像是互斥的条件
解题
由于venom.hasOwnProperty是由传入的参数可以决定的,所以传入venom[hasOwnProperty]=1覆盖掉原有的自带函数,就可以绕过条件2并且进入异常语句块
1
| POST:venom[hasOwnProperty]=1&venom[text]=flag&venom[welcome]=159753
|
POST尝试一下,就会发现此时与条件1发生了冲突,此时venom对象中出现了3个键,这时候自然而然的可以想到用nodejs的原型链污染(如果之前学过的话)
1
| POST:venom[__proto__][text]=flag&venom[hasOwnProperty]=1&venom[welcome]=159753
|
得到flag!
原理
覆盖掉hasOwnProperty是用的用户传入的参数,如果不想被覆盖的话可以用venom原型中的hasOwnProperty()去检查或者其他安全的方法检查
传入参数中的原型链污染是express4.17.2及以下出现的漏洞,通过数组形式可以污染对象的原型链
1 2 3
| 参考链接(照着官方wp写是吧): https://github.com/ChaMd5Team/Venom-WP/tree/main/2024VenomCTF/2024_vctf_web_hackjs/writeup https://www.xujun.org/note-155443.html
|
碎碎念
本地打的时候一定要注意版本,不然就会出现本地打过不了的情况,特么的怀疑人生