nodejs 原型链污染新视角
字数 1435 2025-09-23 19:27:46

Node.js 原型链污染新视角

原型链污染基础概念

原型链污染是Node.js中一种常见的安全漏洞,其基本原理如下:

  1. 原型链机制

    • 对象的__proto__是原型,原型也是一个对象,也有__proto__属性
    • 原型的__proto__又是原型的原型,这样一直向上查找直到找到Object的原型
    • 当在一个对象中寻找属性时,如果对象没有该属性,就会沿着原型链向上查找
  2. 污染原理

    • 通过直接污染Object对象的属性值,使得目标对象在查找该属性时返回被污染的值
    • 示例代码:
      const foo = { bar: 1 };
      foo.__proto__.bar = 2;
      console.log(foo.bar); // 1 (foo本身有bar属性)
      const zoo = {};
      console.log(zoo.bar); // 2 (zoo没有bar属性,从原型链找到被污染的bar)
      

原型链访问方式

通常有三种方式可以访问对象的原型:

  1. objectname["__proto__"]
  2. objectname.__proto__
  3. objectname.constructor.prototype

实际案例分析

案例背景

分析一个基于Express的Node.js应用,主要功能包括:

  1. 用户注册(/register)
  2. 用户登录(/login)
  3. 主题配置(/theme)

关键代码分析

  1. 用户注册逻辑

    app.post('/register', (req, res) => {
      const { username, password } = req.body;
      users[username] = {
        password: password,
        isAdmin: false,  // 默认设置为false
        themeConfig: { /* 主题配置 */ }
      };
    });
    
  2. 用户登录逻辑

    app.post('/login', (req, res) => {
      const { username, password } = req.body;
      const user = users[username];  // 关键点:会查找原型链
      if (user && user.password === password) {
        req.session.userId = username;
        res.redirect('/');
      }
    });
    
  3. 主题配置逻辑

    app.get('/theme', (req, res) => {
      // 将用户提交的参数合并到themeConfig中
      // 存在原型链污染风险点
    });
    

安全限制

应用中存在WAF过滤,阻止了以下关键词:

  • __proto__
  • prototype
  • constructor

创新攻击思路

传统思路的限制

传统原型链污染需要访问Object原型,但这里无法通过常规方式(__proto__等)访问原型。

新思路:利用Object已有属性

  1. 绕过登录验证

    • 使用Object已有的方法名作为用户名(如isPrototypeOf)
    • 由于users[username]会查找原型链,Object.isPrototypeOf存在
    • 不提供密码,使user.password === undefined === password
  2. 新型污染方式

    • 无法直接污染Object.prototype.isAdmin
    • 改为污染Object.prototype.isPrototypeOf.isAdmin
    • 通过主题配置接口传入isPrototypeOf.isAdmin=true
  3. 条件满足逻辑

    • users[req.session.userId].isAdmin => users["isPrototypeOf"].isAdmin
    • users对象没有isPrototypeOf属性,查找原型链
    • 找到被污染的Object.isPrototypeOf.isAdmin=true

攻击步骤

  1. 访问/theme路由,传入参数isPrototypeOf.isAdmin=1进行污染
  2. 使用用户名isPrototypeOf和空密码登录
  3. 访问/flag路由获取flag

防御建议

  1. 避免使用用户输入直接修改对象属性
  2. 使用Object.create(null)创建无原型的对象
  3. 对用户输入进行严格过滤
  4. 使用Object.hasOwnProperty检查属性是否存在
  5. 避免使用不安全的对象合并操作

总结

本案例展示了一种新型的原型链污染利用方式:

  1. 当无法直接访问Object原型时,可以利用Object已有的属性进行间接污染
  2. 通过污染Object已有属性的子属性,实现类似原型链污染的效果
  3. 结合JavaScript原型链查找机制,实现权限绕过

这种技术扩展了原型链污染的利用场景,即使在常规污染方式被防御的情况下,仍可能找到新的攻击路径。

Node.js 原型链污染新视角 原型链污染基础概念 原型链污染是Node.js中一种常见的安全漏洞,其基本原理如下: 原型链机制 : 对象的 __proto__ 是原型,原型也是一个对象,也有 __proto__ 属性 原型的 __proto__ 又是原型的原型,这样一直向上查找直到找到 Object 的原型 当在一个对象中寻找属性时,如果对象没有该属性,就会沿着原型链向上查找 污染原理 : 通过直接污染 Object 对象的属性值,使得目标对象在查找该属性时返回被污染的值 示例代码: 原型链访问方式 通常有三种方式可以访问对象的原型: objectname["__proto__"] objectname.__proto__ objectname.constructor.prototype 实际案例分析 案例背景 分析一个基于Express的Node.js应用,主要功能包括: 用户注册( /register ) 用户登录( /login ) 主题配置( /theme ) 关键代码分析 用户注册逻辑 : 用户登录逻辑 : 主题配置逻辑 : 安全限制 应用中存在WAF过滤,阻止了以下关键词: __proto__ prototype constructor 创新攻击思路 传统思路的限制 传统原型链污染需要访问 Object 原型,但这里无法通过常规方式( __proto__ 等)访问原型。 新思路:利用Object已有属性 绕过登录验证 : 使用 Object 已有的方法名作为用户名(如 isPrototypeOf ) 由于 users[username] 会查找原型链, Object.isPrototypeOf 存在 不提供密码,使 user.password === undefined === password 新型污染方式 : 无法直接污染 Object.prototype.isAdmin 改为污染 Object.prototype.isPrototypeOf.isAdmin 通过主题配置接口传入 isPrototypeOf.isAdmin=true 条件满足逻辑 : users[req.session.userId].isAdmin => users["isPrototypeOf"].isAdmin users 对象没有 isPrototypeOf 属性,查找原型链 找到被污染的 Object.isPrototypeOf.isAdmin=true 攻击步骤 访问 /theme 路由,传入参数 isPrototypeOf.isAdmin=1 进行污染 使用用户名 isPrototypeOf 和空密码登录 访问 /flag 路由获取flag 防御建议 避免使用用户输入直接修改对象属性 使用 Object.create(null) 创建无原型的对象 对用户输入进行严格过滤 使用 Object.hasOwnProperty 检查属性是否存在 避免使用不安全的对象合并操作 总结 本案例展示了一种新型的原型链污染利用方式: 当无法直接访问 Object 原型时,可以利用 Object 已有的属性进行间接污染 通过污染 Object 已有属性的子属性,实现类似原型链污染的效果 结合JavaScript原型链查找机制,实现权限绕过 这种技术扩展了原型链污染的利用场景,即使在常规污染方式被防御的情况下,仍可能找到新的攻击路径。