CVE-2010-2883 从漏洞分析到样本分析
Posted TimeShatter
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CVE-2010-2883 从漏洞分析到样本分析相关的知识,希望对你有一定的参考价值。
本文章将从漏洞利用分析开始,到样本分析结束,其中涉及到的知识点有PDF格式、TTF字体格式、缓冲区溢出漏洞利用、PE文件格式、软件脱壳和恶意代码分析。其中会演示一些基本操作,方便初学者进行复现。
前置知识
要学习本文章,需要下面的前置知识
- C语言。可以看《C程序设计语言》。
- 汇编语言。可以看《深入理解计算机系统》第三章。
- 缓冲区溢出漏洞利用。可以看《0day安全:软件漏洞分析技术》。
- 软件脱壳、PE文件格式。可以看《加密与解密》。
- 恶意代码分析(可选)。可以看《恶意代码分析实战》。
漏洞信息
漏洞名称:Adobe Reader TTF 字体 SING 表栈溢出漏洞
漏洞编号:CVE-2010-2883
漏洞类型:缓冲区溢出
漏洞描述:Adobe Reader 是流行的PDF阅读软件。CVE-2010-2883 Adobe Reader TTF 字体 SING 表栈溢出漏洞的成因是Adobe Reader和 Acrobat 9.3.4中的 CoolType.dll 在解析 PDF 中的字体时未检查数据的长度,导致缓冲区溢出。
分析环境
操作系统:Windows XP SP3
漏洞软件:Adobe Reader 9.3.4
调试工具:吾爱破解OllyDbg
反汇编器:IDA 7.5
样本 md5
名企面试自助手册.pdf: 3f41dc8e22deca8302db1207e5cdc11c
svrhost.exe: 56e6d9b07c8e9e71224c0741566c3eac
msxml0r.dll: dd48f45c9418da8eb89dfcae894d5b93
本次实验的所有资料可以在公众号回复 CVE-2010-2883 获取
漏洞复现
本次分析中的样本主要使用漏洞战争里面提供的 名企面试自助手册.pdf, 该 pdf 文件在漏洞利用成功后,会修改系统文件,释放恶意程序,然后再打开一个正常的面试手册 pdf 文件,让用户感觉就是打开了一个正常的 pdf 文件,它是一个完整的利用链。为了获取明显的漏洞效果,可以使用 msf 生成漏洞利用的pdf 文件,打开pdf文件会弹一个计算器或者反弹一个shell 。
在 kali linux 虚拟机终端中输入下面命令启动 msf
msfconsole
输入下面命令搜索 CVE-2010-2883 漏洞利用模块
search CVE-2010-2883
使用下面命令生成 pdf 漏洞利用文件
use exploit/windows/fileformat/adobe_cooltype_sing
set payload windows/exec
set cmd calc.exe
exploit
pdf文件生成在 /root/.msf4/local/msf.pdf ,在另一个终端输入下面命令复制到 /root/ 目录,从 kali 虚拟机复制出来,然后复制进 windows xp 虚拟机
cp /root/.msf4/local/msf.pdf /root/
安装 Adobe Reader 9.3.4
安装完后,双击 pdf 文件,会弹出计算器
漏洞分析
PDF 格式和 TTF SING 表
在分析漏洞前,先了解下 pdf 文件的格式和其中的 ttf sing 表的格式。
PDF 全称为 (Portable Document Format) 可移植的文档格式,可以在下面地址获取 PDF 文件的详细定义。
https://www.adobe.com/content/dam/acom/en/devnet/pdf/pdfs/PDF32000_2008.pdf
可以使用 010editor 的 pdf 文件模板和 PDFStreamDumper 来解析 PDF 文件
pdf 模板文件从下面地址下载
https://www.sweetscape.com/010editor/repository/files/PDF.bt
PDFStreamDumper从下面地址下载
http://sandsprite.com/CodeStuff/PDFStreamDumper_Setup.exe
PDF的文件结构如下图
PDF文件结构上主要有四部分组成:
• Header:文件头部,用来注明 PDF 文件的版本号,其值为 %PDF-版本号,如 %PDF-1.5
• Body: 主体,主要由组成文件的对象组成,如图片、文字等。
• Cross-reference table: 交叉引用表,用于存放所有对象的位置偏移,可以方便地随机访问 PDF 中的任意对象。
• Trailer: 文件尾,给出了交叉引用表的位置和一些关键对象的信息,以%%EOF结尾。
可以用 010 Editor 解析 PDF 文件的格式。把样本 PDF 文件拖到 010 editor 中,在 View -> Edit As -> Hex ,使用十六进制视图查看文档。
在 Templates 处打开下载的 PDF.bt 模板文件
点击 Run Template 运行模板文件
点击下面解析结果的相应部分,可以在编辑视图处高亮该部分,可以看到样本的 Header 中版本号是 1.5
中间是 PDF 的 body 部分
接下来是交叉引用表
最后是尾部
PDF的 Body 可以看成一个树状的层次结构组成,其中的每个节点都是一个对象。由根节点 Document catalog 开始,其页节点包括文档的内容(页树)、大纲、文章线索、等其他属性
以 Page tree 为例,其下面的页节点是 Page 节点,也就是每一个页面,Page 节点又由内容流、缩略图、注解等元素组成。
可以使用 PdfStreamDumper.exe 来解析和导出 PDF 文件中的对象。在菜单 Load -> Pdf File 中加载样本文件。
点击第一个对象,/Type 指定了该对象的类型是 Catalog,也就是根对象。
/Pages 指向一个对象 2 0 R , 2是对象的序号,0是生成号,R代表引用一个对象,该对象其实是一个 Pages 对象。/OpenAction 指向了 11 0 R 对象,该 对象指定了打开文档时要进行的操作。
接下来看看 2 0 R 对象,也就是序号为 2 的对象。其中 /Resources 指向一个资源对象 4 0 R。 /Kids 是它的叶节点 5 0 R,其实就是一个 page 节点。/Type 指定该对象是 Pages 对象。
我们重点看看 /Resources 指向的一个资源对象 4 0 R,它是漏洞触发的对象。其对象序号为 4,其中 /Font条目指向了一个字体字典对象 6 0 R 。
继续查看序号为 6 的对象。/F1代表了使用Type 1字体技术定义字形形状的字体。该字体的详细信息可以从以下地址获得
https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/minuxs/TrueType%201.0%20Font%20Files.pdf
继续查看 7 0 R,其中的 /FontDescriptor 指向了一个字体描述器 9 0 R,用于描述字体各种属性。
继续查看 9 0 R ,该对象中的 /FontFile2 指向一个流对象 10 0 R,该对象就是触发漏洞的字体对象。
其中的 00 01 00 00 是 ttf 字体文件的开始标志。
在 PDFStreamDumper 中右键选择 Save Decompressed Stream, 把该 TTF 内容存在到 txt 文件中。
接着下载 TTF 文件的 010editor 解析模板。
https://www.sweetscape.com/010editor/repository/files/TTF.bt
使用 010editor 打开导出的 ttf 文件和 ttf 解析模板
ttf 文件全名 The TrueType Font File,是定义字体的文件,其详细的文档如下:
https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/minuxs/TrueType%201.0%20Font%20Files.pdf
TrueType 字体文件以表格格式包含构成字体的数据。下面是各表的作用
展开 010editor ttf 文件中的表,可以看到有一个 SING 表,该表就是漏洞触发点。但在字体文档里面没有这个表的资料,github 上的开源库中有这个表的定义。
https://github.com/adobe-type-tools/afdko/blob/develop/c/spot/sfnt_includes/sfnt_SING.h
#ifndef FORMAT_SING_H
#define FORMAT_SING_H
#define SING_VERSION VERSION(1, 1)
#define SING_UNIQUENAMELEN 28
#define SING_MD5LEN 16
typedef struct
{
Card16 tableVersionMajor;
Card16 tableVersionMinor;
Card16 glyphletVersion;
Card16 permissions;
Card16 mainGID;
Card16 unitsPerEm;
Int16 vertAdvance;
Int16 vertOrigin;
Card8 uniqueName[SING_UNIQUENAMELEN];
Card8 METAMD5[SING_MD5LEN];
Card8 nameLength;
Card8 *baseGlyphName; /* name array */
} SINGTbl;
其中的 Card16 就是 USHORT 类型,16位大小,Card8 就是 byte 类型或 char 类型,8位大小。其中的 uniqueName 字段长度为 28 字节,漏洞触发的原因是 CoolType.dll 在复制 uniqueName 字段到缓冲区时,没有检查 uniqueName 字段的长度,导致缓冲区溢出。
先看看样本中的 SING 表,可以看到 SING 表在文件中的偏移是 0x11C,
SING 表中偏移 16 字节的位置是 uniqueName 字段。可以看到样本中的 uniqueName 在超出 28 字节的长度后,仍然没有结束符 \\x00 。因此样本中 SING 表的 uniqueName 是一个超长字符串。
对 PDF 文件和 TTF 文件的 SING 表介绍完了,对样本生成感兴趣的,可以详细查看 PDF 和 TTF 的文档,以及 msf 的样本生成代码,位置如下:
/usr/share/metasploit-framework/modules/exploits/windows/fileformat/adobe_cooltype_sing.rb
静态分析
存在漏洞的 dll 文件复制出来,用 ida 打开进行反汇编。打开 ida 的导入表视图,ctrl+f 搜索 strcat 函数,双击函数
在 strcat 函数处按 X 打开交叉引用表
在 sub_803DCF9+B2 处的引用就是存在漏洞的地方
汇编代码中在 803DD74 处引用了 SING 字符串,在 803DDAB 处调用了 strcat 函数。
strcat 函数的定义如下:
char *strcat(char *dest, const char *src);
【参数】dest 为目的字符串指针,src 为源字符串指针。
strcat() 会将参数 src 字符串复制到参数 dest 所指的字符串尾部;dest 最后的结束字符 NULL 会被覆盖掉,并在连接后的字符串的尾部再增加一个 NULL。
注意:dest 与 src 所指的内存空间不能重叠,且 dest 要有足够的空间来容纳要复制的字符串。
【返回值】返回dest 字符串起始地址。
按下 F5 ,把这段代码反编译成 C 代码。可以看到 strcat 把 v18 变量偏移为 16 地址的字符串复制到缓冲区中,而偏移 16 处刚好是 SING 表的 uniqueName 字段。如果对 SING 表熟悉,就可以确认 v18 就是 SING 表的结构体。
把 github 上的头文件下载下来
https://github.com/adobe-type-tools/afdko/blob/develop/c/spot/sfnt_includes/sfnt_SING.h
修改下数据类型:
#ifndef FORMAT_SING_H
#define FORMAT_SING_H
#define SING_VERSION VERSION(1, 1)
#define SING_UNIQUENAMELEN 28
#define SING_MD5LEN 16
typedef struct
{
USHORT tableVersionMajor;
USHORT tableVersionMinor;
USHORT glyphletVersion;
USHORT permissions;
USHORT mainGID;
USHORT unitsPerEm;
USHORT vertAdvance;
USHORT vertOrigin;
BYTE uniqueName[SING_UNIQUENAMELEN];
BYTE METAMD5[SING_MD5LEN];
BYTE nameLength;
BYTE *baseGlyphName; /* name array */
} SINGTbl;
#endif /* FORMAT_SING_H */
在 IDA 中按 Ctrl + F9 导入头文件
接下来在 v18 处右键,选择 Convert to struct。输入 sing,选择导入的结构体。
再在 v18 处右键重命令变量名成 singTable ,操作完后可读性就高了很多, ida 可以自动识别结构体的字段。
动态调试
单靠静态分析由于缺少运行时的数据,不方便分析每个代码的用途,所以需要使用动态调试和静态分析相结合的方式来分析漏洞。
这里使用 吾爱破解专用版Ollydbg , 里面内置了很多好用的插件。可以到吾爱破解爱盘上下载,下载地址如下:
https://down.52pojie.cn/Tools/Debuggers/%E5%90%BE%E7%88%B1%E7%A0%B4%E8%A7%A3%E4%B8%93%E7%94%A8%E7%89%88Ollydbg.rar
用 ollydbg 打开
C:\\Program Files\\Adobe\\Reader 9.0\\Reader\\AcroRd32.exe
加载后按 F9 运行程序,以便加载所需的 dll 库。
先在三个关键位置下断点,首先在引用 singTable 处下个断点,便于观察内存中 singTable 的内容。在 IDA 的 singTable 变量处,右键选择 Synchronize with -> IDA View-A, Hex View-1 ,这样可以把反编译代码与汇编代码窗口同步,这样只要把鼠标放在引用 singTable 变量的地方,即可在 View-A 窗口同步到该处的汇编代码。
所以第一处断点地址为 0x0803DD82 。在 ollydbg 界面上按 Ctrl + g, 输入 803DD82 ,点击确定,跳到该地址的汇编代码
在该处的汇编代码左边的十六进制显示区域双击下一个断点。
接着在调用 strcat() 函数溢出前下一个断点,地址为 0x0803DDAB
接下来在触发漏洞的位置下一个断点,该位置从溢出处一直跟踪即可发现,也是关键的一个点,下面会进行介绍,地址为 0x0808B308
设置好断点后,可以加载样本文件进行漏洞分析了,把样本文件复制一份到 C 盘根目录,重命名为 a.pdf ,方便后续分析。
用 ollydbg 打开的 Adobe Reader 打开 a.pdf 文件
打开后等几秒,会断在了第三个断点处
此时 eax 寄存器的值为 0x12E6D0,也就是栈上的一个地址,此时栈顶为 0x12E2D8。会取 eax 指向的地址的值来作为函数调用,在 eax 处右键,选择堆栈窗口中跟随
可以看到 0x12E6D0 处存放着的值为 0x080833EF ,意味此处代码的跳转会跳到 CoolType.dll 的 0x080833EF 处执行。因此,如果我们在栈溢出时可以覆盖 0x12E6D0 处的值,就可以跳到任意地址去执行 shellcode。
在 ida 处按 g 键,输入 0x080833EF ,回车,跳到该处的代码,
这似乎是一个根据 switch 语句的值进行相应处理的函数。到这里可以确定的, 栈上的 0x12E6D0 地址存放着一个函数指针,在处理 SING 表时,会调用该函数指针。
按 F9 继续运行程序,断在第一个断点处,此处是引用 singTable 的地方,按 F8 运行到下一行代码,此时 eax 指向 SING 表在内存中的位置。在 eax 处右键在数据窗口跟随。可以看到左下角的数据窗口中看到 SING 表的内容,eax 指向的内存地址的 0x10 偏移处即为 SING 表的 uniqueName。可以看到 SING 表的 uniqueName 字段相当长。
一直按 F8 运行到 0x0803DD9F 处,此处把 eax 加 0x10, 取到 uniqueName 的地址,用于调用 strcat()。
继续运行到第二个断点 0x803DDAB 处,也就是调用 strcat() 函数处。在右下角的栈窗口上可以看到 strcat 复制的目的地址是栈上的缓冲区 0x12E4D8。
在运行 strcat 函数之前,我们先观察一下栈上 0x12E6D0 处附近的数据是什么。在栈窗口上按 ctrl + g 输入 0x12E6D0
此时 0x12E6D0 处的值仍然为之前的 0x80833EF
再看看缓冲区 0x12E4D8 附近的值
按 F8 单步步过 strcat 函数,来到下一行,可以看到 uniqueName 的值已经复制到栈缓冲区 0x12E4D8 处
再来看看 0x12E6D0 处的值,已经被覆盖成 0x4A80CB38,该处为
icucnv36.dll 的代码。
在汇编代码窗口按 ctrl+g 跳到 0x4A80CB38 处的代码,该处的代码会调整栈顶并返回,明显是一个使用 ROP 技术绕过 DEP 保护的技术。
这里简单介绍下 GS、DEP 、ROP 和 ASLR,详细的内容请查看 《0day安全:软件漏洞分析技术》
GS 保护,在编译时可以选择是否开启GS安全编译选项。这个操作会给每个函数增加一些额外的数据和操作,用于检测栈溢出。在函数开始时,会在返回地址和EBP之前压入一个额外的Security Cookie。在函数返回时,系统会比较栈中的这个值和原先存放在.data中的值做一个比较。如果两者不相等,则说明栈中发生了溢出。因为溢出时会覆盖返回地址,而 security cookie 位于返回地址前,所以覆盖返回地址的方法不可行了。这就是为什么该漏洞利用时,会选择覆盖栈上的一个函数指针,然后在调用该函数时跳转到 shellcode 执行。
切换到 IDA 的汇编代码窗口,可以看到在函数开始前往栈压入了 security cookie 。
在函数返回前检查 security cookie 是否被覆盖掉
DEP(Data Execution Prevention) 是数据执行保护,是 windows 防止溢出利用的系统保护机制,系统会标记哪些内存地址可以执行代码,在开启 DEP 后,栈处的内存会被标记为不可执行,因此,除非有办法修改内存的属性,否则不可以在溢出时把 shellcode 布置在栈来运行。支持 DEP 的程序,会把 IMAGE_DLLCHARACTERISTICS_NX_COMPAT 标志设为 1
可以在 ollydbg 中按 alt + m 来查看内存属性,可以看到栈区的属性为 RW 读写权限,而 AroRd32.exe 的 text 节才是 RWE 读写执行权限。
ROP(Return Oriented Programming)是用来绕过 DEP 保护的技术,既然栈上的内存不可执行,那么可以通过执行程序自身的代码来达到目的,把一连串的代码片段组合起来,执行一个片段返回,再执行另一个片段,从而实现某种功能。0x4A80CB38 处的代码的功能就是调整栈顶,先添加 ebp 的值,然后把 ebp 的值赋值给 esp ,从而实现把栈地址往高地址调整的目的,然后通过 return 重新获取控制权。要实现这个功能的时候,都可以跳转到这里执行,然后返回。
溢出时,为什么选择 icucnv36.dll 的内存地址呢?是因为 Adobe Reader 大部分库都开启了 ASLR,包括 CoolType.dll ,而 icucnv36.dll 没有开启。
ASLR(Address Space Layout Randomization) 地址空间随机化,在加载程序的时候不再使用固定的基址加载,支持ASLR的程序在其PE头中会设置
IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE标识来说明其支持ASLR。例如,如果 icucnv36.dll 开启了 ASLR,那么同一个代码的地址,可能是 0x4A80CB38,也可能是 0x5A80CB38。由于无法知道准确的地址,所以也就无法跳转到想要执行的代码。
下面通过一个工具找到 Adobe Reader 中所有没开启 ASLR 或 DEP 的库。下载链接。
http://www.scriptjunkie.us/files/pefinder.zip
使用下面命令来获取 Adobe 目录下没开启保护的库
dir /b /w /s "C:\\Program Files\\Adobe\\*.dll" | pefinder.exe -
CVE-2010-2883 漏洞样本绕过了所有上述的保护,所以很值得研究分析。GS保护通过覆盖函数指针来绕过,DEP 保护通过 ROP 技术来绕过, ALSR 通过堆喷来绕过(后面介绍)。
上面说到漏洞触发点是 0x0808B308 处的 call [eax] ,怎么发现此处呢,那就需要从调用 strcat 函数开始,一步一步的步入代码去寻找了,在寻找的过程中,可以使用 ida 的反编译窗口来加强理解这些汇编代码的作用。
在返回函数前,为了寻找覆盖栈后,可能会导致程序崩溃的子函数,可以在每次函数调用前,都下个断点,然后 F8 步过直接执行完该函数,如果程序退出,证明这个函数里面可能引用到覆盖后的数据。然后用 ollydbg 重新运行到该断点处,用 F7 步入函数继续跟踪到触发点。
在开始操作前,先打个虚拟机快照,因为该样本的触发点运行后,会释放恶意代码,运行过一次恶意代码后会影响后续的样本分析,所以在找到触发点后,需要恢复下快照,把系统恢复到恶意代码释放前。
一路按 F8,运行到调用函数时,下一个断点
然后按 F8 步过该函数,发现程序没有崩溃,删除上面的断点,继续往下测试,直到调用 0x08016BDE 函数处,F8 会直接跑到 call [eax] 处,显然通过该函数会直接运行到触发点。
这里可以 ctrl+F2 重新打开程序,加载程序,运行到断点处,按 F7 步入 0x08016BDE 函数,并在 IDA 反编译窗口中跟进该函数。重复上面的操作,在 0x08016C56 地址处调用 0x0801BB21 函数后会跑到 call [eax] 处。
F7 继续跟进这个函数,在 0x0801BB2D 处把 ecx 指向的值移动到 eax
在 ecx 上右键,在数据窗口中跟随
在数据窗口中右键 -> 长型->地址,以地址形式显示数据,发现 ecx 处的值也是一个指针,指向 0x081A601C
在数据窗口中 ctrl+g 输入 0x081A601C,跳转到该地址,发现该地址处存放着很多函数指针,显然是一个 C++ 类的虚表。而 0x081A601C 则是一个虚表指针,指向该虚表。
在 IDA 中查看该地址,可以看到该类是 StreamHandler,应该是处理解析 PDF 中流对象的类。
在反编译窗口中修改下变量名,该函数的功能也就是取 StreamHandler 的第一个虚函数 0x0808B116 ,然后运行该函数。
注意下此时的栈情况,分别对应 0x0808B116 函数的 7 个参数,第一个参数是 StreamHandler 对象。也就是 0x12E718 处的对象
在查看该地址的数据时,发现该对象偏移 0x3C 处,存放了 0x12E6D0,该地址刚好存放了后面要调用的函数指针,在缓冲区溢出时,很可能是覆盖了 StreamHandler 的一个成员变量,该变量是一个函数指针,指向一个处理函数。
继续 F7 跟进 0x0808BB16 函数,在 0x0808B2E3 处调用处取了
0x12F718 + 0x3C 处的值放到 eax,也就是 StreamHandler 对象偏移为 0x3C 处的值,该值为 0x12E6D0
接下来在 0x0808B308 处 call [eax] 取 0x12E6D0 处的值作为函数进行调用,该值为 icucnv36.dll 中的地址 0x4A80CB38
按 F7 步入后,就到了 ROP 链,到此,从 strcat 溢出到进入 ROP 链的过程分析就结束了。
ROP链分析
接下来分析如何通过 ROP 链来跳到 shellcode 中运行的。
首先是跳到 0x4A80CB38 处运行。
add ebp, 0x794 调整了 ebp,加了 0x794,从0x12DD48 调整到 0x12E4DC
接下来的 leave 指令相当于 mov esp,ebp pop ebp。也就是把 ebp 的值复制到 esp,也就达到了调整栈顶的目的,运行完后, esp 指向 0x12E4E0,而缓冲区溢出时的地址是 0x12E4D8,该地址刚好在后面8个字节,是我们可以控制的栈区。所以这段汇编代码的作用是把栈顶调整到可以控制的栈区。
接下来根据栈上的返回地址返回,到达下一段 ROP 代码。该处 pop esp 把 esp 修改到 0x0c0c0c0c 地址,也就是堆喷常用的地址(后面再介绍是如果进行堆喷的)
运行完后,栈顶来切换成 0x0c0c0c0c,通过堆喷技术,已经提前在此处布置好了 shellcode,此处是布置好的栈数据,用来控制 ROP 链。
继续执行返回,下一段把 0x4A8A0000 地址出栈到 ecx 。
接下来保存 eax 处的值到 0x4A8A0000 处。
接下来的栈顶存放了 CreateFileA 函数的地址,通过 pop eax 赋值给 eax,然后返回。
返回到 jmp [eax], 也就是直接跳转到 CreateFileA 函数中执行,此时栈上是已经构造好的参数
继续按 F7 步入 CreateFileA ,该函数会在本地打开一个文件,如果不存在则创建。在栈上已经构造好所需的参数,FileName 参数为 iso88591 ,也就是在本地创建一个名为 iso88591 的文件,下面的
Attributes 参数指明该文件是一个隐藏文件和临时文件。要在文件夹中开启显示隐藏文件才可以查看。
按 Ctrl + F9 执行至返回,在桌面上可以看到这个文件。
接下来把 eax 和 edi 的值交换,此时 eax 保存的是 CreateFileA 函数调用后返回的文件句柄
接下来把 8 赋值给 ebx
接着把 edi 的值放到 esp + ebx * 2 处 , 也就是 0x0c0c0c6c ,此处原来的值是 0xFFFFFFFF, 通过 and 操作可以把 edi 的值放到此处,该处刚好为接下来要调用的 CreateFileMappingA 函数的第一个参数位置。这样操作应该是没找到直接把 eax 的值放到栈上指定位置的指令,只找到了把 edi 的值放到栈上指定位置的指令
按下来 Ctrl + F9 运行到返回, 接下来把 CreateFileMappingA 函数地址放到 eax 中
按 F7 步入,直接跳转到 CreateFileMappingA 函数运行
在栈上可以看到 CreateFileMappingA 函数的参数,该函数为指定的文件创建文件映射对象。其中第一个参数是上面保存的文件句柄。内存属性为读写执行,意味着可以把 shellcode 复制到此处执行。
按下来 Ctrl + F9 运行到返回,继续运行,后面的运行和前面的运行很相似,也把 CreateFileMappingA 返回的句柄 0x370 保存到栈上,作为 MapViewOfFile 函数的第一个参数。
先交换 eax,edi
保存到栈上,以便下个函数调用
接下来出栈 MapViewOfFile 函数的地址
然后跳转到 MapViewOfFile 函数中执行,该函数将一个文件映射对象映射到当前应用程序的地址空间,其中 hMapObject 参数为上面调用返回的 hMapObject 对象,调用函数后会返回该文件对象在内存中对应的地址
运行到返回后,eax 存放着映射的内存地址,此处为 0x471000
可以看到映射地址 0x471000 处的属性为读写执行权限,可以执行 shellcode
继续运行,把 0x4A8A0004 地址放到 ecx
接着把 eax 中由 MapViewOfFile 函数返回的内存地址保存到 0x4A8A0004 中
接下来交换 eax,edi
给 ebx 赋值 0x30
把 edi 的值保存在 esp + ebx*2 的位置,也就是 0x0C0C0D44 的位置 ,该处的作用是用于后续 ROP 链的返回地址,最后 retn 时会返回到 0x4710000
接下来给 eax 赋值 0x4A8A0004
把 0x4710000 这个新映射的地址保存到 0x4A8A0004 处
交换 eax, edi
赋值 ebx 为 0x20
保存 0x4710000 到 esp + ebx*2 处,该处为后续要调用 memcpy 函数的参数
赋值 ecx 为 0x4A801064,该处为一个 retn 指令的地址
以上是关于CVE-2010-2883 从漏洞分析到样本分析的主要内容,如果未能解决你的问题,请参考以下文章
Adobe Reader 缓冲区溢出漏洞 (CVE-2010-2883)漏洞分析报告
[漏洞复现] CVE-2010-2883 Adobe Reader 打开pdf即刻中招