如何实现Edge CVE-2017-0234 漏洞复现与利用


如何实现Edge CVE-2017-0234 漏洞复现与利用,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。首先clone并切换到漏洞所在的源码版本Chakra.Core.sln文件在Build目录下。推荐使用VS2015生成解决方案,新版VS可能会遇到缺少运行库的问题。下面分析仅针对Release配置下编译生成的Chakra,Debug配置中会启用一些额外的检测。使用VS或者Windbg调试都可以,设置可执行文件为ch.exe,参数为js文件。首先对POC内容简单分析一下buffer申请了一块0x10000的内存作为缓冲区view是以buffer为缓冲区的Uint32变量类型的数组自定义的write函数对view数组进行了一个循环赋值的操作第二次write显然超出了0x10000缓冲区的范围,但js中的数组越界赋值,通常会直接忽略但是Windbg捕获到了一个异常:观察相关寄存器及其指向内存区域的情况,其详细内容如下:显然rsi指向buffer,r9是write中进行的数组赋值操作中的数组下标i,乘以4是因为Uint32成员单位大小是4字节越界后的数组下标指向的这块内存不具有RW权限,因此产生了异常关注点:R9的值并不是第一次越界写入时的数组下标,并且JS正常情况下数组越界并不应该产生异常查看异常发生时的调用栈由此可得,是for循环达到一定次数后触发了JIT机制,而异常就发生在通过JIT编译后执行的越界写入中。显然此处JIT生成的汇编代码缺少数组下标的越界检测,通过patch代码的分析来探寻其中的原因。patch的内容:针对三个标志位的设置与否,添加了额外的检测此外,这个漏洞还有一个特点,JIT中数组越界产生的异常会被chakra自己处理,并不会引发crash,理论上这对漏洞利用的稳定性会有所帮助。(但最后写出的Exp其实并没有用上这个机制)POC中ArrayBuffer申请的长度0x10000并不是随便选的,这个长度将会决定是由AllocWrapper还是malloc申请内存由上方可知0x10000是满足调用AllocWrapper的最小长度再来看看AllocWrapper的逻辑,实际上还是使用VirtualAlloc进行内存申请与管理:其中VirtualAlloc申请的大小MAX_ASMJS_ARRAYBUFF-ER_LENGTH是固定值,直接一次性申请4GB大小这下我们就可以尝试解释JIT中忽略异常并不设置下标检测的原因了:这块4G的缓冲区中仅会作为一个数组对象的缓冲区chakra中数组下标是uint32类型,因此其最大值是2^32-1假设数组成员变量是单字节大小,那刚好无法越过4G的范围在4G的范围内进行越界读写,并不会产生危害关闭下标检测可以提升性能但POC中已经给出了答案,若数组成员变量大于1字节,则可以跨越4G的安全区去进行越界读写。只要利用堆喷射等方式申请到4G的正后方内存,就可以劫持对象的数据结构从而间接实现任意读写。windows环境下的利用相比linux会复杂一些,首要目标大多是先尝试达成任意地址读写,再往后一般也就只是时间问题了。首先观察一下与后续利用相关的数据结构:chakra中数组是基于B Tree的数据结构,大体上我们需要了解其是将数组分部在多节点内存存储每个节点称之为segment,其中length代表已存储的成员数量,size代表这个seg的大小left代表B tree中左节点next指向下一个segment0x80000002是MissingItem,简单可以理解为未初始化时的默认值。segment中head的偏移是0x20,存放数组成员的地方从0x38偏移处开始;next指向的是下个segment.head进行数组查询时,会根据length与size判断是否要去next的下一个节点,如果我们通过POC中的越界写入修改了length与size并改得很大,那就可以通过该数组进行越界读写。EXP Step1:成功分配两个数组的buffer到4G空间后方通过调试观察可得arr2因为内存对齐,实际位于arr1+0x3000处,中间存在无效数据这一步实际上是将myobj的地址作为指针存储在了数组中,不过正常情况下无法将这个指针的值直接leak出来,但利用越界读等特殊方式就可以做到。这是利用过程中最复杂的操作。首先总结一下目前拥有的能力:通过JIT漏洞越界写arr1及其高地址的内容通过arr1越界读写高于arr1地址的内容,如arr2任意对象地址leak而我们现在想伪造一个array对象,通过控制其buffer的方式来实现任意读写,并且buffer以外的对象数据也必须设置得合法。显然目前所拥有的能力很有限,但是上文提到的seg.next在此刻派上了大用场。调试观察可得,view对象大小为0x40字节上文指出,next指向的是head,而head与数组成员间还相隔0x38-0x20=0x18要想通过伪造的next越界读写,必须要知道fake head.left来确定数组下标index0x28偏移处是指向buffer1对象的指针,可以通过任意对象leak来获取综上,将next设置为view1+0x28,则left就是buffe免费云主机域名r1地址的低4字节,并且数组成员起始区域是view1+0x28+0x18,刚好是view2对象的地址Tips:arrint当前是int32类型数组,因此数据若大于0x7fffffff,应先转为负数再传给arrintarrint本身有length属性,必须大于访问的index,直接设置为0xffffff00即可现在buffer1中已经有了一个完整且合法的数组对象,通过view1[0xe&0xf]即可修改fake buffer来实现任意读写。最后的一步就是让解释器也把这块内存上的数据当作对象处理关于如何让chakra将指针认为是对象,暂未能深入探究,仅通过不断修改代码测试得出可行的方法由于笔者能力有限,本文对chakra数组实现的分析仅深入到能理解Exp利用方式的程度,关注点在于left,size,length,next这四个变量的作用。常规思路有泄露栈地址然后ROP等,但windows下的栈稳定性不像linux,即使泄露stack base也难以确认返回地址所在的位置,此处选择的方法是虚表劫持。上文提到view对象0偏移处即为该类数组对象的虚表,类似于linux pwn中常见的IO_FILE利用中可劫持的vtable因此我们只要将view对象的虚表指针修改到我们可控的区域,就可以劫持控制流了由于windows下并没有one_gadget这种方便的存在,劫持控制流后还需要结合其他利用技术才能进行下一步,寻找合适的gadget往往也会是个不小的难题。本机环境的ntdll与kernel32.dll中,能直接控制RSP并且ret的只有mov rsp, r11。通过push rxx;pop rsp这种间接控制的gadget笔者也没有找到,因此思路转向寻找会使r11数值可控的数组方法经过很多次尝试后,发现arr1==arr2会将r11设置为arr2对象地址因此可以直接将对象区域破坏,用于存放ROP chainwindows有个特性,短时间内模块的基址是不会变的,利用这点可以让调试过程更加方便通过对象的虚表指针,减去偏移可以得到ChakraCore.dll的基址通过ChakraCore.dll的IAT表,leak其他模块基址windows中的底层api往往需要很多参数,大多不像linux下的system/execve那么好用,而且还散布在不同的dll中。此处推荐kernel32!WinExec,仅需控制两个参数并且位于kernel32模块,非常方便。windows64位下api使用寄存器传参通过RCX, RDX, R8, R9,RSP+0x20….传递ntdll中一般会存在很多好用的gadget用于控制参数寄存器本地环境测试中,唯一的不稳定因素是arr1能否占位到4GB后,成功率大约有80-90%尝试在开头就大量new Array来占位4GB后,经测试绝大多数情况都是第一次分配就占位成功,若不成功则后续也难以占位到这处位置。若要达成100%成功率,需在此处进一步研究。其他环境复现,需要修改ROP中用到的gadget偏移实际上要在Edge上成功利用的话,还需要绕过CFG机制,也就是说无法通过劫持虚表指针直接ROP。看完上述内容是否对您有帮助呢?如果还想对相关知识有进一步的了解或阅读更多相关文章,请关注云编程开发博客行业资讯频道,感谢您对云编程开发博客的支持。

相关推荐: Oracle数据库中如何限定特定IP访问

本篇内容介绍了“Oracle数据库中如何限定特定IP访问”的有关知识,免费云主机域名在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成![A]可以利用登录触发器、cmgw或者是在$…

免责声明:本站发布的图片视频文字,以转载和分享为主,文章观点不代表本站立场,本站不承担相关法律责任;如果涉及侵权请联系邮箱:360163164@qq.com举报,并提供相关证据,经查实将立刻删除涉嫌侵权内容。

(0)
打赏 微信扫一扫 微信扫一扫
上一篇 02/05 08:59
下一篇 02/05 08:59