Javascript原型链攻击与防御

admin 2021年11月22日03:38:20评论78 views字数 2627阅读8分45秒阅读模式

“ NaN!=NaN


在讲这个漏洞之前我们来理解一下Javascript。与其他的语言不同的是,Js在Es6之前是没有class的,他更多的是一个原型语言,在Js里有一句话很有名——"一切皆对象"


01

什么是原型语言


  1. 只有对象,没有类;对象继承对象,而不是类继承类。

  2. “原型对象”是核心概念。原型对象是新对象的模板,它将自身的属性共享给新对象。一个对象不但可以享有自己创建时和运行时定义的属性,而且可以享有原型对象的属性。

  3. 每一个对象都有自己的原型对象,所有对象构成一个树状的层级系统。root节点的顶层对象是一个语言原生的对象,只有它没有原型对象,其他所有对象都直接或间接继承它的属性。


02

关于Function.prototype和Object.__proto__


  1.     对象有__proto__属性,函数有prototype属性;

  2.      对象由函数生成;

  3.   生成对象时,对象的__proto__属性指向函数的prototype属性。

 

在没有手动修改__proto__属性的指向时,以上三条便是JavaScript默认原型链指向逻辑。如果要更形象的去理解这个就可以看下下图的这个结构

Javascript原型链攻击与防御


03

什么是JavaScript原型链污染


原型链污染来自一个CVE(https://github.com/jquery/jquery/pull/4333),这个CVE是一个在jquery中修复的漏洞,但是这个漏洞广义的推广的话,受影响的范围应该是一切使用了ecmascript的应用,无论前后端。关于这个漏洞,是修复了jQuery的$.extend(true…)方法,在jQuery中,这个方法用于将一个或多个对象的内容合并到目标对象。所以你永远不知道有不有人会不会写出一些类似以下的代码


for(  var i = 0 ;i < datas.length; i++ ) {
     $.extend( true, allNode, datas[i] )
 }

当我们可控$.extend的参数的时候,我们就可以覆盖对象的__proto__或者prototype方法从而控制整个原型链的最顶端的方法,重写该方法将覆盖子对象或者函数的方法,从而导致污染原本的方法意图。

在npmjs官方搜下对象操作的库可以看到一大堆,例如“xtend”、 “deepmerge”、 “webpack-merge”、 “merge2”、 “lodash.merge”。假如一些应用使用了这些方法,但是对参数没做任何处理。


04


漏洞范围影响


提出这个Javascript原型链污染攻击的作者写了一个pdf,在该pdf中,作者不仅做了漏洞的成因分析,还针对此漏洞做了受害范围分析,他在github上搜索了部分的组件,这些组件都是可以操作对象,一般都是对象合并操作的,较为底层,因此也会有大量的应用基于这些组件。例如“hoek”,“lodash”,“defaults-deep”等修复了这个原型链污染的可能性,当然还有一些组件他没统计到,例如“xtend”之类的,光weekly download的数量就有“12,097,425”。

笔者在npm上搜索了基于xtend的一些应用,找到一个language-exec这样的一个组件。这个组件是一个基于xtend的,不过这个组件好像年久失修而且没啥人用,看了源代码其中就有这样的一句话

return exec(cmd, extend({

    cwd:  path.dirname(file)

  }, opts), done);

可以看到类似的写法都是存在问题的(主要是我没找到具体的基于xtend的受影响应用)。

所以基于这个,大家不是有了刷CVE的思路了?没错…只要你敢花时间去爬全部的dependence就可以有机会获得javascript pollutionattack CVE。


05


案例一远程命令执行


作者在github上搜到了一款叫做ghost cms的应用,当然这个漏洞已经修复,当黑客发送以下请求即可实现控制任意方法或者对象的任意属性。当然也就是rce了

Javascript原型链攻击与防御


06


案例二 DOS



在一切皆对象的JavaScript中,所有对象都可以调用toString和valueOf方法,当你通过__proto__重写这2个方法的时候,就容易在express等web框架中产生dos,导致服务无法正常运行。类似以下的写法就容易产生拒绝服务

Javascript原型链攻击与防御


07


案例三 任意文件读取


如果你可以通过污染原型链来重写一些“私有属性”的话(Javascript没有私有属性),可能可以重写那些在WEB中用来定义渲染模板文件的属性值,就有可能产生任意文件读取了,如以下这个图片

Javascript原型链攻击与防御


08


如何防御


在这里我们了解下这类攻击,如何从代码上更安全的编写,更好的防御这类漏洞。漏洞发现的作者给出了2个解决方案,先来看看我是如何防御的。

如果是我来解决这个问题的话,我会选择迭代对象的属性,直到查找到__proto__和prototype这2个属性名,如果出现就干掉。但是这个方法还是有缺陷,一个是建立于黑名单,需要列入的属性太多了,例如Dos的话就要把tostring和valueof等方法列入,而且遇到私有属性覆盖的话,怎么确保参数,接口很多。


原作者提出了3点:

1、使用Object.freeze来冻结对象,几乎所有的 JavaScript对象都是 Object的实例。所以冻结Object.prototype即可。具体大家可以去了解下es5就新增的Object.freeze方法,使用了这个方法,那么黑客就无法对prototype新增或者重写对应原型链上的方法,不过这样可能会导致一些隐性的bug产生,而且可能还不知道是哪里出错了。


2、用map数据结构来代替自带的对象结构。Es6就有map结构啦,这个map和Object的区别就是map的键可以是任意的对象类型,数组也好,对象也好。

 

3、使用Object.create(null)强烈推荐, 使用这个方法就可以更好的防御原型链污染攻击了,因为Object.create(null)使得创建的新对象没有任何的原型链,是null的,不具备任何的继承关系,当你接受一个客户端的参数并且打算merge的话,可以使用此方法后去merge,这样的对象是比较安全的,客户端没办法通过原型链来污染攻击(因为压根就没原型链通往其他的对象)。我们可以简单的通过一个实验来看下。


Javascript原型链攻击与防御

Javascript原型链攻击与防御


Javascript原型链攻击与防御

本文始发于微信公众号(xsser的博客):Javascript原型链攻击与防御

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2021年11月22日03:38:20
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Javascript原型链攻击与防御https://cn-sec.com/archives/481996.html

发表评论

匿名网友 填写信息