关于CVE-2018-4901的研究
作者:admin | 时间:2018-3-24 12:05:06 | 分类:黑客技术 隐藏侧边栏展开侧边栏
0. 前言
上个周末在 FreeBuf 上看到Adobe Acrobat Reader中存在远程代码执行漏洞 这篇文章后,决定自己尝试去复现一下这个漏洞,至少能弹个计算器吧,结果一些事情出乎意料,这里把自己的研究过程写下来。
1. POC构造
根据国外的一篇文章 talos 中介绍,漏洞原理是在 pdf 中 trailer 内部的ID字段如果过长,在执行JavaScript脚本this.docID的时候会触发漏洞,漏洞模块位于一个dll文件EScript.api中。那么,是应该先构造javaScript还是先构造trailer后面的ID呢?javaScript我是通过Acrobat Pro DC添加上去,如果先构造trailer,那么会被Acrobat Pro DC修复,所以先构造javaScript。另外,最初的文档怎么才能包含trailer呢?说实话之前并不熟悉pdf文件格式,在进行了很多尝试之后,发现使用wps将空白doc文档转化为pdf之后,文档很简洁,并且包含有trailer。那么流程就很清晰了:
1.1 生成包含trailer的pdf
1.2 javaScript的构造
使用Acrobat Pro DC编辑刚刚生成的文件,使用javaScript工具,在保存pdf文件的这个动作的时候添加javaScript命令this.docID即可。
1.3 trailer的构造
在保存上面的文档后,使用notepad打开文档,将trailer后面的ID改为 ,需要更改的地方有两处。
1.4 poc效果
注意前面构造的javaScript是在保存文档的时候触发,但是如果开启沙盒,保存文档时就总是弹出另存为进而无法触发漏洞,所以要先设置Adobe,ADOBE 保存PDF文件,总是弹出另存为的解决办法
测试:在文档中添加注释,然后点击保存,Adobe崩溃,模块为EScript.api
2. 调试分析
2.1 崩溃原因
使用OD载入AcroRd32.exe,并打开文档,之后就在模块中就可以看到EScript,根据TALOS的那篇文章,在其中搜索触发漏洞的代码。
这段代码简单的说就是,我们构造的样本中ID的字符串已经被转化为16进制数了,hexStr(“AAAAAA..”) -> hexArray(0xAA 0xAA….),而触发漏洞的这一块是将hexArray(0xAA 0xAA….)又转为hexStr(“AAAAAA..”) .
但是漏洞具体是如何触发的需要结合动态调试,在循环开始出下断点,和之前触发崩溃的方式进行相同的操作,程序会断在断点处,可以获得如下图所示的初始信息。
一开始,edx指向hexStr,edi指向hexArray,并且hexStr的首地址就在hexArray首地址上方0×100的地方。esi是循环的次数。
具体看看每一项的数据的情况:
hexStr是目的地,也就是它没过返回地址;
hexArray很奇怪,只有0×80个0xAA,我们传入了0×200个‘A’,那么理应由0×100个0xAA;
esi是循环次数,值为0×100,正好符合我们的预期。
假如没有啥保护机制,我们要淹没的返回地址是0x2Bc8c8处的0x693a3168
进一步观察,0×80个0xAA正好转化为0×100个‘A’,那么执行0×80次,就应该会到hexArray首地址之前了。这里下一个条件断点,让它执行0×80次
但是一切还会往后继续,如果再执行0×40次,那么hexArray就会被自己后面的数据给覆盖。同样下条件断点,再执行0×40次
记得之前要淹没的返回地址吗,它在这个地方
那么只要再执行0xC次,它就会被覆盖了
同样是下条件断点,继续执行
地址被覆盖为0×30303030了
而触发漏洞代码片段下方的两个函数分别是string()和__security_check_cookie,这里先不去管它。因为我们能控制的只有0×80,是真的只有0×80吗?
2.2 疑问
结合IDA来分析分析
可以看到,在漏洞触发之前HexArray的数据来源有两种情况:
1.memcpy(&v17, v14, (size_t )&v15[1]);
2.nCircleIndex = ((int (__cdecl **)(int, int, char , signed int))(dword_23A59CB0 + 320))(a2, a3, &v17, 0×80);
对于1,(size_t )&v15[1]在其上的if判断中被限制为<=0×80.
对于2,其中的参数被设置为0×80.
对于第2种情况,我们还需要调试来验证是否是这个参数限制了hexArray
2.3 OD动态调试验证
我们在push 0×80下断点重新触发漏洞中断下来了,说明hexArray的数据来源是第二种情况,然后我们将push 0×80改为push 0×100
执行到漏洞开始处,内存转到edi,发现现在有0×100个0xAA了,说明之前的判断是正确的
3. 结论
我们能够控制的只有拷贝的次数和拷贝的前0×80个字节HexArray的内容。而函数分配给HexStr 0×100固定大小的栈空间,程序流程是HexArray转化到HexStr,所以我们可控的能覆盖的空间也就只有HexStr那一块空间。以上是我关于CVE-2018-4901的研究。另外,经过尝试,不是trailer,其他标签下的ID如果超长也会出发漏洞。行文匆匆,如果有误,还请多多指正。
*本文作者:TueurCalme