首页
社区
课程
招聘
[原创]Chrome v8 Issue 1203122: Security: Type confusion bug in LoadSuperIC
发表于: 2023-5-29 17:53 21168

[原创]Chrome v8 Issue 1203122: Security: Type confusion bug in LoadSuperIC

2023-5-29 17:53
21168

写在前面

   问题出现场景:

    假设对象A,其偏移+10的地方有一个属性x,这个属性为数字,同时存在一个B对象,这个对象偏移+10的地方是一个Object对象地址。(v8在性能优化的时候会使用对象地址加偏移的方法来直接获取属性,比如在IC内联缓存,还有JIT优化以后。)

    实际处理中如果AB对象出现混淆,

    例如在v8在JS函数调用期待的是处理对象A的属性x,并且x为一个数字类型,如果实际上处理却传入了对象B,就会根据B的基址+10偏移取值,并将其当作A的数字属性x返回,这样造成的结果就会将B+10偏移的对象地址当作A的属性x数字返回给JS调用函数,出现信息泄露。

   

                                                                                           如图1

     反过来,如果JS函数调用期待的是处理A对象的偏移+10的属性x,并且x为一个对象,如果实际上处理却传入的是对象B,那么就会根据B的基址+10偏移取值,并当作A的属性x返回,这样造成的结果就会将B+10偏移指向的数字,当成A的属性x对象返回给JS调用者,如果B偏移+10的这个地址指向我们预先设定的数据,就可以伪造一个对象结构。

                                                                                         如图2

比如函数:

v8在开始处理这个foo(a)的时候,会进行profiling data和feeback进行收集,然后根据profiing data和feedback的信息进行内联缓存优化。

比如我们一直使用 a={x:1}进行foo(a)运算,那么v8会在处理这个foo(a)运行到一定次数后,记录下a的数据结构,然后下次如果再碰到这种foo(a)运算时,直接使用a的地址加上a对象地址与x属性的偏移来进行x属性数据的索引,提升v8运行的效率。

比如上面这段JS代码里面,class A里面定义了prop函数,class B继承了class A,v8是通过super属性来获取class A中的属性x,严格来说,是获得A.prototype.x,然后返回给调用者的,v8有针对这种super索引的父类的情况有做专门的优化处理,这个处理阶段叫做superIC。

在这段JS代码中b.m()返回的是class B的super.prop,根据super关键字,v8会去去寻找父对象class A,然后根据class A prototype返回x属性。

也就是说在v8的处理中,b.m()会从class B再找到class A,再从class A的prototype里面找到x属性。

      理想的v8 superIC处理过程中,这个发起寻找属性的对象,以这个例子来说,这段JS代码中的b对象实例在v8中叫做receiver,然后用一个叫lookup_start_object的对象来标识进行这个寻找过程所用的对象,lookup_start_object先为class B,然后为class A,最后为A.prototype,最后根据class A的prototype中找到x属性,并返回给调用程序。

之后如果出现同样的运算,v8会根据lookup_start_object的数据数据结构,利用lookup_start_object加上lookup_start_object与属性x的偏移,并将这个偏移的值取出返回。

     这里可以看到,receiver和lookup_start_object并不是一个东西,在实际的js中,我们可以通过B.__proto__这样的运算来修改掉B对象里面的super关键字指向的对象,这样可以造成receiver.x和lookup_start_object.x内存布局不一致。

如下JS代码:

如果每次传入的obj都为对象a,那么v8 IC之后,会标记该属性为MONOMORPHIC。如果传入的obj有a对象,b对象两种情况,会标记为POLYMORPHIC,如果大于4种情况,则会标记为MEGAMORPHIC。

如上述代码所示,2.1.1,一开始运行的时候,因为没有feedback,会命中miss[6],随后随着调用的增多,代码路径为[0]=>[1]=>[2]。创建feedback,然后执行LoadSuperIC_NoFeedback。

                           2.1.2,接着由于feedback的增多,代码执行路径为[1]=>[4]=>[5]。这里的[5]注释已经说明lookup_start_object!=receiver。而在一开始命中miss的时候,输入的参数中有p->receiver(),和p->lookup_start_object()。这里标示了LoadIC_Noninlined(p,lookup_start_object_map,....)也就是期待使用的是lookup_start_object。

如上述代码所示,在随后的操作中:

                    2.1.3:[6]在exit_point->ReturnCallStub()中,却使用p->receiver()来加入具体的函数执行,但如我前面2.1.2所说,v8使用的是lookup_start_object_map,期待的是lookup_start_object,出现了类型混淆(个人认为是因为v8的程序员认为使用p->receiver()和p->lookup_start_object()结果没什么差别)。

这个poc构造过程如下:

    2.2.1创建一个class C,然后创建一个函数m()返回其super对象的prototype属性,也就是执行C.__proto__.prototype运算。

    2.2.2将C.__proto__改为指向f函数对象,当执行一定次数的main()以后,就会进行IC优化,此时进行c.m()运算,就会从class C中的m()成员函数进行super.prototype进行访问,最终访问到C的父类Object的prototype,然后会将C.__proto__,也就是函数f标记为lookup_start_object,然返回其prototype,并将lookup_start_object提供给后续的m()调用使用。

    2.2.3main中每次都function f(){}然后通过f.prototype来对prototype这个属性进行访问,制造出这个属性MEGAMORPHIC的情况。

    2.2.4添加x0,x1,x2,x3,x4属性添加给c。也就是上文所说的receiver,改变receiver的内存结构,使得和lookup_start_object不一致。

    2.2.5在触发内联缓存后,使用c.m()访问C.__proto__.prototype,v8正确的做法是使用lookup_start_object也就是函数f返回f.prototype来返回给JS,但实际上我们可以通过上面漏洞的代码片段看出,是使用receiver进行属性的查找,就会将我们设定的0x42424242 / 2代替f.prototype进行返回,并作为f.prototype的类型解析,最终出现了类型混淆报错。

但是单靠这点问题没法RCE,这个POC更多的是验证这种代码的问题。

如上所示如果receiver为String对象,在SuperIC过程中,会将receiver传进去,然后执行的为LoadIC_StringWrapperLength。


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2023-5-30 11:30 被苏啊树编辑 ,原因:
收藏
免费 4
支持
分享
最新回复 (7)
雪    币: 530
活跃值: (906)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
2
后续的利用也是ArrayBuffer和Wasm的套路吗
2023-6-10 13:42
0
雪    币: 5317
活跃值: (3318)
能力值: ( LV9,RANK:250 )
在线值:
发帖
回帖
粉丝
3
可以去我给的链接看一下,伪造的是Funtion.prototype,和ArrayBuffer不太一样
2023-6-12 20:15
0
雪    币: 3059
活跃值: (30876)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
感谢分享
2023-11-8 09:29
1
雪    币: 6008
活跃值: (2585)
能力值: ( LV9,RANK:250 )
在线值:
发帖
回帖
粉丝
5
请问该漏洞必须在 LoadSuperIC 触发吗?我在其它函数中也看到了该该逻辑,但是触发不了,ICs 一直都是多态
2024-4-2 10:16
0
雪    币: 6008
活跃值: (2585)
能力值: ( LV9,RANK:250 )
在线值:
发帖
回帖
粉丝
6
XiaozaYa 请问该漏洞必须在 LoadSuperIC 触发吗?我在其它函数中也看到了该该逻辑,但是触发不了,ICs 一直都是多态
我懂了
2024-4-2 11:08
0
雪    币: 6008
活跃值: (2585)
能力值: ( LV9,RANK:250 )
在线值:
发帖
回帖
粉丝
7
还是想问下   f.prototype//制造prototype属性MEGAMORPHIC的情况,与这个poc触发的混淆代码路径有关。 这个到底是咋影响的呢?
2024-4-2 16:58
0
雪    币: 6008
活跃值: (2585)
能力值: ( LV9,RANK:250 )
在线值:
发帖
回帖
粉丝
8
XiaozaYa 还是想问下 f.prototype//制造prototype属性MEGAMORPHIC的情况,与这个poc触发的混淆代码路径有关。 这个到底是咋影响的呢?
我似乎明白了,打扰了
2024-4-3 15:10
0
游客
登录 | 注册 方可回帖
返回
//