Flash 0day CVE-2018-15982利用代码赏析(上)

华盟原创文章投稿奖励计划

文章来源于网友投稿

文章作者:FPX_niupi

     Flash 0day CVE-2018-15982利用代码赏析(上)
FLASH是什么: FLASH是一种已死的东西.但这并不妨碍我们学习一门技术。本着学习的态度,我们分析在flash环境中是如何利用UAF漏洞的。同时,我们这次面对的是一个0day漏洞,这次我们就模拟一名样本分析人员的角色,坚决不看网上已有分析,从零开始到弹出记事本全局独立分析。我们本次分析的利用样本来自GIT:https://github.com/Ridter/CVE-2018-15982_EXP。windows系统为win10 1809  32位版本,IE为系统自带的IE 11,生成后即可弹出记事本,且相当稳定。顺带说一下我这里的FLASH编译软件使用FlashDevelop,另外下载PSDK指定目录。
SWF反编译后代码复制出来,这些不必多说,我当时倒还有些许意外,反编译出来的代码可以直接顺利编译。在反编译时,就发现嵌入了另外两个文件,可能是我们指定的shellcode文件,于是暂且不管。直接EXP本身。
查看Main.as,找到入口发现并没有什么特别,不管是事件触发还是直接调用,总之就是执行起了Var17这个函数,看了一眼Var17,这才是真正干事的函数,于是改名为triger_vul:
Flash 0day CVE-2018-15982利用代码赏析(上)
这里trigger_vul函数太长不便截图,除去创建各种对象和初始化后,关键代码如下:
Flash 0day CVE-2018-15982利用代码赏析(上)
大致读一下代码,loc4是一个metadata对象,之后一个循环调用setObject,之后又新建了一些列class5对象实例,而之后560行,就通过循环判断loc5是否为24。先看一眼Class5的定义:
Flash 0day CVE-2018-15982利用代码赏析(上)
可以看到Class5有两个成员变量,第一个初始化为24,第二个为2200。这里我们根据定义,更改了变量名为m1和m2,而为之后分析辨别属于哪个类,加上了class5_m1。另外,我们代码中还出现了一个com.adobe.tvsdk.mediacore.metadata.Metadata对象即loc4,于是我们把Loc4可以改名成metadata了,但是这个对象是个什么对象呢?一番搜索后,在这个链接中有它的说明,https://help.adobe.com/en_US/primetime/api/psdk/asdoc-dhls_2.3/com/adobe/tvsdk/mediacore/metadata/Metadata.html
Flash 0day CVE-2018-15982利用代码赏析(上)
我们的trigger_vul中使用到了setObject方法和key_set属性:
Flash 0day CVE-2018-15982利用代码赏析(上)Flash 0day CVE-2018-15982利用代码赏析(上)
看起来这个setObject就是添加一个新项的,而每一项就是一个key:value的键值对,其中key是一个字符串,value可以是任意对象。而key_set是返回了一个所有的key的集合。这些都很好理解。我们再回头过来看看trigger_vul的截图,你会发现很奇怪(为了方便阅读,再贴一次图):
Flash 0day CVE-2018-15982利用代码赏析(上)
546行的while循环调用setObject就添加了很多项,之后550行获取到keySet集保存在了loc5变量中,之后就“毫不相关”得创建了一堆Class5的对象,我们也知道Class5实例的第一个成员为24,下面560行就奇怪了:按理说,你keySet获取到的集合,应该是一堆字符串的集合,这就是adobe那个网页所说明的keySet属性的意义,但是代码中却要把集合中元素的字符串Length和24比较,我们在前面添加项的时候,key字符串是loc2.toString,而这个key字符串怎么也不可能有24个字符,并且为何就是24?而不是23,25,26呢?而恰恰在Class5的定义中,第一个成员就是24。继续往下看代码(原代码红框中的是一样,太长了),如果等于24,则会读取这个字符串的第5、6、7、8个字节(下标从0开始)组装成一个dword与0x80000作比较,这又是比较奇怪了,字符串中的某个字节不就是字符吗?怎么就成了DWORD。
Flash 0day CVE-2018-15982利用代码赏析(上)
所以单从这代码上来看,我们可以大致判断这是个UAF:那“毫不相关”的创建Class5实例的骚操作,很可能占用了原来keySet中的元素的位置,至少是Class5的创建影响了keySet元素,或者说他们之间有某种联系。而且之后的代码,就是设置了一个变量,然后根据这个变量值调用不同的函数,看起来漏洞原因就这里了。而具体原因,我们需要证据,调试一番才能确定。
我们知道,这里很可能是keySet集中的某个元素的长度出现了被更改的情况。印证就需要找到这个元素的内存地址。由于这个元素不是孤立的,它的地址可在keySet中找到,那么keySet在哪?也就是我们需要知道loc5(下文称ks)。
要知道一个变量(结构体)所处的内存地址,我们有AVMPLUS源码可以辅助。但也仅限于辅助,我们加载不了符号,并不知道在编译好的FLASH模块中某个函数的位置。经过研究,本人总结了如下方法:
首先在byteArray中,有一个readUTFBytes方法,该方法在AVMPLUS中如下实现:
Flash 0day CVE-2018-15982利用代码赏析(上)
该函数中,红线处标记了一些判断,而这些判断是与一个立即数比较,这可以作为一个很好的记号,作为用来在FLASH模块中找到此函数:
Flash 0day CVE-2018-15982利用代码赏析(上)Flash 0day CVE-2018-15982利用代码赏析(上)这样就可以直接在任何AS3代码断到调试器(当然这个说法并不严谨)。例如下面这样:
Flash 0day CVE-2018-15982利用代码赏析(上)Flash 0day CVE-2018-15982利用代码赏析(上)
当然,如果你想让FLASH的运行暂停以便附加调试器,那么可以使用FLASH和JS交互来暂停:ExternalInterface.call('alert', 'xx');。现在可以在任何汇编层面断点,那么我们可以利用function来获取到某个对象地址,以获取ks变量地址为例:
Flash 0day CVE-2018-15982利用代码赏析(上)Flash 0day CVE-2018-15982利用代码赏析(上)
我们根据function会被JIT为汇编代码的特点,当我们在test函数中断时,我们处于test函数所生成的汇编代码中的调用。如图:
Flash 0day CVE-2018-15982利用代码赏析(上)
注意箭头所指向的那次调用,他的返回地址是一个不在FLASH模块中的地址,那么这就是一次FUNCTION调用造成的结果:
Flash 0day CVE-2018-15982利用代码赏析(上)
使用WINDBG ga命令运行到这里后,可以反汇编查看接下来的代码。在上图红框处,exc的值就是第二个参数arg对象的地址。这里因为我例子是返回的arg[0],所以会看不到偏移的代码:
Flash 0day CVE-2018-15982利用代码赏析(上)
附带一张带偏移时的截图:
Flash 0day CVE-2018-15982利用代码赏析(上)Flash 0day CVE-2018-15982利用代码赏析(上)       这样,我们就可以查看keySet中到底发生了什么事,就像这样:
       Flash 0day CVE-2018-15982利用代码赏析(上)
断下后:
Flash 0day CVE-2018-15982利用代码赏析(上)
我们走过那些验证参数和CFG的过程后,
Flash 0day CVE-2018-15982利用代码赏析(上)
继续运行两行,看看eax真貌:
Flash 0day CVE-2018-15982利用代码赏析(上)

www.idc126.com

注意图中绿线标注的值,全是0x107d8ecc。根据这个虚表指针,可看出这个对象总大小为0x18。其中唯一有可能是个指针的就是object+8的值,下面的db结果可看出,这些都是字符串—--虽然每个字符串都只有一个字符。也就是obj+8的地方就是String对象的m_buffer。另外也可以看到object+0x10的地方为1,也就是字符串长度m_buffer_length。上图中的3、4、5、6、7、8就是这里:
Flash 0day CVE-2018-15982利用代码赏析(上)
但从key_set[3]这个String上来看,并没有什么不正常的。我们再看看key_Set集中的其他元素就会发现(这里截图时重新运行了,故元素地址并不完全一样):
Flash 0day CVE-2018-15982利用代码赏析(上)
比如0xa1f90e0处:
Flash 0day CVE-2018-15982利用代码赏析(上)
可看到,红框处的值并不是0x107d8ecc这个String类的虚表指针,再来一张0xa1f9100处的:
Flash 0day CVE-2018-15982利用代码赏析(上)
可看到前4字节也不是0x107d8ecc,同时我们也可以看到后面的内容也全部变成了0,object+8的地方也不再是一个指针。这意味着key_Set集中的存储的某些String元素的String类指针指向的内存已经不再是String类。但是为什么我们查看到的key_Set[3]却正确呢?到底是哪些元素错误呢?仔细看看整个对象的元素列表会发现,key_Set的前10个元素都放在了0x0c4b8000这个0x1000大小的页面中,而我们出错的都是在0x0a451000这个页面中,验证一下:
Flash 0day CVE-2018-15982利用代码赏析(上)
果然也错误,这个String对象甚至整个都是0。再次验证一下页面最起始位置的那个元素:
Flash 0day CVE-2018-15982利用代码赏析(上)
可看到0xa451000这个页面最小的对象是0xa45105a&0xfffffff8:
Flash 0day CVE-2018-15982利用代码赏析(上)
所以我们有理由相信,是AVM虚拟机在执行this.conn()中,按照页面使用情况,回收了String对象所在的页面,造成key_Set中存在悬挂指针。
之后代码会创建一系列的Class5对象,创建对象需要内存,于是Class5占用了原String对象所在的内存:
Flash 0day CVE-2018-15982利用代码赏析(上)       Flash 0day CVE-2018-15982利用代码赏析(上)
在第一次断下时0x0c52de38已经释放(这里又重新运行了)。在Class5创建完后第二次中断下:
Flash 0day CVE-2018-15982利用代码赏析(上)
可看到该String对象已经被重新占用,且不再是String类对象,而红线处的两个DWORD,表明该地址已经变成了Class5对象。而原来object+0x10处m_buffer_length的值已经改成了Class5的成员Class5_m1的值。所以之后AS3代码中,通过循环遍历key_Set集找到这个被改写了的元素。这里说明一下,在上面分析中,我们知道被回收的是整个页面,所以不只一个元素被Class5所占用,而是整个页面中的String对象均被改写,只不过构建任意读写只需要一个就足够了:
Flash 0day CVE-2018-15982利用代码赏析(上)
上面我们知道,String+0x8的地方为指向字符串内存的m_buffer,而现在被改写为Class5之后,object+8的地方也还是一个指针,只不过这个指针不再指向字符串缓冲区,而是:
Flash 0day CVE-2018-15982利用代码赏析(上)
从红框中的0x1042c3a0可以看出,这是另一个对象:
Flash 0day CVE-2018-15982利用代码赏析(上)
所以AS3代码中,可以通过获取String字符串来读取”m_buffer”所指向的缓冲区内容:
Flash 0day CVE-2018-15982利用代码赏析(上)
读取的每个字符组装成一个DWORD即可得到一个指针。我们知道对象的最前面一个成语是虚表指针,所以读取第5-8个byte组装起来的。这里如果得到的DWORD小于0x80000则表示是当前是在64位进程,因为这里是QWORD的有符号高32位值:
Flash 0day CVE-2018-15982利用代码赏析(上)
之后根据是32位还是64位来调用不同的函数完成利用。而利用的构建,我们将在下篇中来分析学习。

本文原创,作者:张,其版权均为华盟网所有。如需转载,请注明出处:https://www.77169.net/html/268019.html

发表评论