freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

点我创作

试试在FreeBuf发布您的第一篇文章 让安全圈留下您的足迹
我知道了

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

浅谈原型污染
RachDou 2025-02-25 19:51:49 88380
所属地 四川省

什么是原型污染?

原型污染是一种JavaScript安全漏洞,它允许攻击者向全局对象原型中添加任意属性,这些属性随后可能会被用户定义的对象继承。
尽管原型污染本身通常无法作为独立漏洞被利用,但它允许攻击者控制那些原本无法访问的对象属性。如果应用程序随后以不安全的方式处理攻击者控制的属性,这可能会与其他漏洞串联起来。在客户端JavaScript中,这种情况通常会导致DOM型跨站脚本攻击(DOM XSS),而在服务器端,原型污染甚至可能引发远程代码执行。

原型污染漏洞是如何产生的?

原型污染漏洞通常发生在JavaScript函数将包含用户可控属性的对象递归合并到现有对象中时,而没有事先对键进行清理。这可能会让攻击者注入一个键名为__proto__的属性,以及任意嵌套的属性。

由于__proto__在JavaScript上下文中具有特殊含义,合并操作可能会将嵌套属性分配到对象的原型上,而不是目标对象本身。因此,攻击者可以通过注入包含恶意值的属性来污染原型,而这些属性可能会被应用程序以危险的方式使用。

虽然任何原型对象都可能被污染,但这种情况最常发生在内置的全局Object.prototype上。

成功利用原型污染漏洞需要以下关键要素:

  • 原型污染源——这是任何能够让你通过注入任意属性来污染原型对象的输入点。

  • 污染接收点(Sink)——换句话说,是一个能够导致任意代码执行的JavaScript函数或DOM元素。

  • 可利用的工具(Gadget)——这是任何未经适当过滤或清理就被传递到污染接收点的属性。

原型污染源

原型污染源是任何用户可控的输入,它允许你向原型对象中添加任意属性。最常见的来源包括:

  1. 通过查询字符串或片段字符串的URL

  2. 基于JSON的输入

  3. Web消息

通过URL的原型污染
考虑以下包含攻击者构造的查询字符串的URL:

https://vulnerable-website.com/?proto[evilProperty]=payload

当将查询字符串分解为键值对时,URL解析器可能会将__proto__解释为一个普通的字符串。但如果随后将这些键值对作为属性合并到一个现有对象中,情况会如何呢?

你可能会认为,__proto__属性及其嵌套的evilProperty属性,只是简单地被添加到目标对象中,如下所示:

{

​ existingProperty1: 'foo',

​ existingProperty2: 'bar',

proto: {

​ evilProperty: 'payload'

​ }

}

然而,事实并非如此。在某个时刻,递归合并操作可能会使用类似于以下语句的赋值操作来设置evilProperty的值:

targetObject.__proto__.evilProperty = 'payload';

在这个赋值过程中,JavaScript引擎将__proto__视为原型的访问器。因此,evilProperty会被赋值给返回的原型对象,而不是目标对象本身。假设目标对象使用默认的Object.prototype,那么在JavaScript运行时中,所有对象都将继承evilProperty,除非它们自身已经拥有一个同名的属性。

在实际中,注入一个名为evilProperty的属性不太可能产生任何影响。然而,攻击者可以利用相同的技术,用应用程序或任何导入的库所使用的属性来污染原型。

通过JSON输入的原型污染

用户可控的对象通常通过JSON.parse()方法从JSON字符串中生成。但是,JSON.parse()同样会将JSON对象中的任何键视为普通字符串,包括类似__proto__这样的键。这为原型污染提供了一个潜在的攻击向量。

假设攻击者通过Web消息注入以下恶意JSON,例如:

{

​ "proto": {

​ "evilProperty": "payload"

​ }

}

如果通过JSON.parse()方法将此内容转换为JavaScript对象,得到的对象实际上会有一个键为__proto__的属性。

const objectLiteral = {proto: {evilProperty: 'payload'}}; const objectFromJson = JSON.parse('{"proto": {"evilProperty": "payload"}}'); objectLiteral.hasOwnProperty('proto'); // false objectFromJson.hasOwnProperty('proto'); // true

如果通过JSON.parse()创建的对象随后在没有适当键清理的情况下被合并到现有对象中,这也会在赋值过程中导致原型污染,正如我们在前面基于URL的示例中所看到的那样。

原型污染接收点

原型污染接收点本质上是一个JavaScript函数或DOM元素,你可以通过原型污染访问它,从而执行任意JavaScript代码或系统命令。我们在关于DOM XSS的主题中已经详细讨论了一些客户端接收点。

由于原型污染让你能够控制那些原本无法访问的属性,这可能会让你接触到目标应用程序中的一些额外接收点。对原型污染不熟悉的开发人员可能会错误地认为这些属性不受用户控制,这意味着可能只会有很少的过滤或清理措施。

原型污染工具

原型污染工具(Gadget)是将原型污染漏洞转化为实际攻击的手段。它是指任何满足以下条件的属性:

  • 被应用程序以不安全的方式使用,例如在传递给接收点时未进行适当的过滤或清理。

  • 可通过原型污染被攻击者控制,即该对象能够继承攻击者添加到原型中的恶意版本的属性。

如果一个属性直接定义在对象本身上,那么它不能成为工具(Gadget),因为对象自身的属性版本会优先于你添加到原型中的任何恶意版本。一些健壮的网站可能会显式地将对象的原型设置为null,以确保它不会继承任何属性。

原型污染工具的示例

许多JavaScript库接受一个对象,开发人员可以使用它来设置不同的配置选项。库代码会检查开发人员是否明确向该对象添加了某些属性,如果是,则相应地调整配置。如果代表特定选项的属性不存在,通常会使用预定义的默认选项。一个简化的示例可能如下所示:

let transport_url = config.transport_url || defaults.transport_url;

现在想象一下,库代码使用这个transport_url来向页面添加一个脚本引用。

let script = document.createElement('script');

script.src =$

可试读前30%内容
¥ 19.9 全文查看
9.9元开通FVIP会员
畅读付费文章
最低0.3元/天
# 漏洞 # web安全 # 漏洞分析 # 网络安全技术
免责声明
1.一般免责声明:本文所提供的技术信息仅供参考,不构成任何专业建议。读者应根据自身情况谨慎使用且应遵守《中华人民共和国网络安全法》,作者及发布平台不对因使用本文信息而导致的任何直接或间接责任或损失负责。
2. 适用性声明:文中技术内容可能不适用于所有情况或系统,在实际应用前请充分测试和评估。若因使用不当造成的任何问题,相关方不承担责任。
3. 更新声明:技术发展迅速,文章内容可能存在滞后性。读者需自行判断信息的时效性,因依据过时内容产生的后果,作者及发布平台不承担责任。
本文为 RachDou 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
RachDou LV.2
这家伙太懒了,还未填写个人描述!
  • 12 文章数
  • 2 关注者
JWT安全风险全解析:攻击手段与防护要点
2025-03-11
Web缓存欺骗:潜藏的安全陷阱与应对策略
2025-03-11
HTTP走私:原理、技术与防范
2025-03-05
文章目录