JavaScript原链型污染详解

admin 2024年5月27日12:07:42评论8 views字数 2587阅读8分37秒阅读模式

JavaScript原链型污染详解

前言

本文为玲珑安全原创,未经授权不可转载。请进行合法的渗透测试,玲珑安全公众号、芳华绝代安全团队公众号及文章作者不承担任何因利用本文分享的内容而造成的任何后果。

漏洞原理

在 JavaScript 中,使用原型继承模型与许多其他语言所采用的基于类的继承模型有着明显的区别。
在 JavaScript 中,对象是由一组称为“属性”的键值对构成的集合。举例来说,可以定义一个包含用户名和用户标识的 user 对象:

const user = {    username: "ice",    useridentify: 1001,    addOrder: function() {        // 执行添加订单操作的函数    }};

在 JavaScript 中,每个对象(如 B)都链接到另一个对象(如 A),A 被称为 B 的原型。当对象 B 分配了原型之后,它会自动继承其指定原型的所有属性。

JavaScript原链型污染详解

举个例子,当 myString 对象继承了 String.prototype 原型之后,由于该原型中包含 toLowerCase() 方法,因此 myString 对象也可以直接调用该方法:

let myString = "Ice";Object.getPrototypeOf(myString);    // String.prototypemyString.toLowerCase();             // ice

JavaScript原链型污染详解

在 JavaScript 中,当引用对象的属性时,JavaScript 引擎首先尝试直接在对象本身上查找该属性。如果对象本身没有匹配的属性,JavaScript 引擎会在对象的原型链上继续查找。
在 JavaScript 中,由于对象 B 的原型是另一个对象 A,因此对象 A 也可能有自己的原型,以此类推。由于 JavaScript 中几乎所有的东西都是对象,所以原型链最终会回溯到顶层的 Object.prototype,而其原型则是 null。

JavaScript原链型污染详解

总结来说:通过原型链的机制,JavaScript 实现了对象之间的继承关系,使得对象可以共享和继承其原型链上的属性和方法。这种原型继承模型为 JavaScript 带来了灵活性和强大的功能。
JavaScript 的原型链污染思路即为:指向全局对象原型添加任意属性,然后这些属性可能会被用户定义的对象继承,从而实现敏感操作。
而恰好,由于每个对象都有一个特殊的属性 __proto__我们可以使用它来访问其原型及其属性,实现自定义或覆盖内置方法,甚至可以添加新方法。
举例如下:

// 使用 __proto__ 属性回溯原型链myString.__proto__                        // String.prototypemyString.__proto__.__proto__              // Object.prototypemyString.__proto__.__proto__.__proto__    // null

JavaScript原链型污染详解

漏洞危害

原型链污染虽然通常无法作为独立漏洞被利用,但它能够让我们控制本来无法访问的对象属性。如果应用程序随后以不安全的方式处理用户控制的属性,则可能与其他漏洞相互影响。在客户端 JavaScript 中,这将导致 DOM XSS,而服务器端原型污染甚至有可能导致远程代码执行。

JavaScript原链型污染详解

漏洞利用

我们通常在以下污染源中实现污染:
1、URL 中的查询字符串或片段字符串(哈希)
2、基于 JSON 的输入
3、Web消息

No.1

通过URL进行原链型污染

当 URL 中包含像 ?__proto__[evilProperty]=payload 这样的恶意构造的查询字符串时,URL 解析器可能会将 __proto__ 解释为字符串:

{    string1: 'ice',    string2: 'JavaScript',    __proto__: {        evilProperty: 'payload'    }}

但在执行递归合并操作时,URL解析器会使用类似于 targetObject.__proto__.evilProperty = 'payload' 的语句来分配 evilProperty 的值。
在这个赋值过程中,原型对象的evilProperty属性将被覆盖或添加(如果不存在)。假设目标对象使用默认的 Object.prototype,那么 JavaScript 运行时,所有对象都会继承这个 evilProperty 属性,除非它们已经拥有了相同名字的属性。

No.2

通过JSON输入造成原链型污染

用户可控制的对象通常是通过 JSON 字符串使用 JSON.parse() 方法派生而来的。而JSON.parse() 也将 JSON 对象中的任何键都视为任意字符串,包括像 proto 这样的键,这为原型污染提供了另一个潜在的途径。

假设通过网页消息注入了以下恶意的 JSON:

jsonCopy Code{    "__proto__": {        "evilProperty": "payload"    }}

如果这个 JSON 经过 JSON.parse() 方法转换为 JavaScript 对象,得到的对象实际上将具有一个键为 __proto__ 的属性:

const objectLiteral = {__proto__: {evilProperty: 'payload'}};const objectFromJson = JSON.parse('{"__proto__": {"evilProperty": "payload"}}');



objectLiteral.hasOwnProperty('__proto__');     // falseobjectFromJson.hasOwnProperty('__proto__');    // true

JavaScript原链型污染详解

通过 JSON.parse() 创建的对象随后被合并到现有对象时,可能导致原型污染。

漏洞实例

定义user对象,它从父对象 Object.Prototype 继承了所有属性:

let user = {'name': 'mayank', 'age': 25} user.name user.name.toString()

JavaScript原链型污染详解

覆盖上层对象的toString()属性:

user.name.__proto__.toString = ()=>{alert('ice')}

JavaScript原链型污染详解

访问用户属性,实现XSS:

user.name.toString()

JavaScript原链型污染详解

缓解措施

1、确保用户输入不包含影响原型链的 __proto__、构造函数或原型。


2、使用 Object.freeze(Object.prototype) 冻结 Object.prototype(由于兼容性问题,不推荐使用)

原文始发于微信公众号(芳华绝代安全团队):JavaScript原链型污染详解

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年5月27日12:07:42
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   JavaScript原链型污染详解https://cn-sec.com/archives/2782797.html

发表评论

匿名网友 填写信息