漏洞描述
该漏洞是以CVE-2011-1999漏洞为原型来进行讨论。select元素结构中存在一个option cache结构,该结构是option兀素的指针数组,该数组存在数组越界漏洞。将option元素添加到select元素过程中,如果添加的索引是负值,那么会覆盖数组前方的数据。浏览器的数组越界漏洞属于高风险漏洞,可以同时绕过ASLR 和 DEP,能够稳定执行类似的漏洞还有:CVE-2011-1999,CVE-2010-1883,CVE-2008-3475。之所以说能够绕过ASLR和DEP,因为它能准确的获得mshtml.dll的基地址,但是有时利用mshtml.dll不能构造出合适的rop链。我的思路是通过一些变换来获得ntdll.dll中的rop链。
本文为网络安全技术研究记录,文中技术研究环境为本地搭建或经过目标主体授权测试研究,内容已去除关键敏感信息和代码,以防止被恶意利用。文章内提及的漏洞均已修复,在挖掘、提交相关漏洞的过程中,应严格遵守相关法律法规。
漏洞利用简述
首先,数组越界漏洞本身具有向任意地址写固定数据的能力。利用该数组越界漏洞,更改sela rray元素中option cache前方的某个字符串的长度位,将长度位改为较大数值,这样该字符串就可以读取该字符串后面的所有数据。通过获得该功能,先将该字符串所在虚拟空间的准确位置测算出。通过获得的准确位置和内存任意地址读取功能,获得读取内存中任意地址数据的功能。
通过获得的读取内存中任意地址数据的功能,读取option对象的虚函数表的基地址,进而获得mshtml.dll模块的基地址。为rop chain做铺垫。(可选)
具备了读写功能后,伪造对象,来触发漏洞。具体为:使用optarray中的option的指针来替换option cache中的option元素中的CTreeNode指针,然后立即删除该option元素,导致原CTreeNode指针的位置指向的内存是待释放内存,触发内存回收,然后使用恶意数据填充到该内存处,该位置处是一个伪造的CTreeNode结构对象,这样当执行corru ptedoption.rentNode.click(),即执行了CTreeNode结构对象指向的父对象的虚函数。
我的方法是通过对string字符串的调整,读取飞地中的ntdll.dll函数地址,进而获得ntd¨.dll模块的基地址。为rop chain做铺垫。
关键知识点
· 覆盖字符串长度位
· 利用该漏洞同时具备读写功能
· 内存构造对象数据结构
· 利用飞地地址
js中存在字符串,字符串在内存中的表示是前4个字节是长度位,后面是字符串内容。字符串内容的读取受到字符串长度位的限制,如果长度位足够大,那么字符串可以读取其后用户空间的所有内容。
这里和普通的漏洞触发不同,这里是手工构造出触发漏洞的条件。有一种use-after-free现在已经不可能存在了,那就是:同时有两个地方引用到某个对象,如果删除某个引用和对象,并在该对象位置放入其他恶意数据,那么另一个引用将能引用到该恶意数据。使用optarray中的option的指针来替换option cache中的option元素中的CTreeNode指针,然后立即删除该option元素,导致原CTreeNode指针的位置指向的内存是释放内存,然后使用恶意数据填充到该内存处。
用户空间的最后一块内存中存在“飞地地址”。飞地区域指的是SharedUserData内存区
早期系统调用
Ntdll中的存根函数调用ShareserData内存区的SystemCaIIStub代码。ntdll.dll中的存根函数内的代码为call edx,其中edx存储着SystemCaIIStub的地址,执行call edx将使程序转移到“飞地区域”执行程序代码。
后来系统调用
后来SharedUserData内存区没有了可执行权限,也不存放执行代码,而是仅仅用来存放地址,存放的是一个指向ntdll.d¨中的ntd¨.KiFastSmCall的地址。并且ntd¨.dll中的存根函数内的代码不是call edx,而是call [edx],SharedUserData内存区内不是SystemCaIIStub的地址,而是放入了一个指向ntdll.dll中的ntdII.KiFastSystemCall的地址。ntd¨.KiFastSystemCall在ntdll.dll中的位置固定,因此通过该地址可以得到ntdll.dll模块的首地址。伪造对象(创造触发条件)
步骤1
将selarray[99]中的option cache 指针数组中的第61个option的指针赋值给corruptedoption, option cache指针数组中的元素删除函数
- corrupption\=reem(optarryaddr+60*4); - corptedoption=selarray[99].options[60]; - selaay[99].options.remove(60); - corrptaddr=corruptedoionaddr+Ox14;
步骤2
另一个options对象畸形添加给selarray[99]中的option cache指针数组中,覆盖了之前option对象中的CTreeNode指针函数
- overwrite(corrutaddr);
步骤3
因为之前是畸形添加,导致selarray[99]遗忘了添加的option元素,空间最终被回收函数
- selarray[99].opion.remove(0);
步骤4
函数
- elms[i].classNae=fakeobj;
步骤5
parentNode即CTreeNode指针指向的对象已经被字符串替换,调用parentNode的click方法时,系统底层就会寻找该对象的虚函数表,并执行其中相关的函数
- corruptedoptin.parentNode.click();
上图中绿色部分的数值为下面的fa keobj对象。
fakeobj= u nescape("%u4141%u4141%u0024%ulclc' )+u nescape("%u4141%u4141%u414l%u4141%U 4141%U 4141%u 4141%U 4141%u 4141%U 4141%U 4141%U 4141%U 4141%u4141%u4141%u4141%u4141%u 4141%u4141%u 4141%u 4141%u 4141");
通过指针Oxlclc0024,指向了下面构造的rop链。