Office EPS文件解析漏洞分析

admin 2022年10月2日05:45:33评论12 views字数 6897阅读22分59秒阅读模式

前言

第一次分析 EPS 类漏洞,对于 PostScript 格式十分陌生,通过查阅PostScript LANGUAGE REFERENCE了解 PostScript 格式。调试 EXP 来自 kcufld 师傅的eps-CVE-2017-0261,EXP 在 Office 2007 可以正常运行,但在 Office 2010 以上版本需要配合提权漏洞逃逸沙箱后完成利用。

调试环境

调试是直接使用 kcufld 师傅的 eps 加载器进行调试,EPSIMP32.FLT 版本信息如下:

OS:               Win7 x64 SP1
Office:           Ofiice 2007 x86
Image name:       EPSIMP32.FLT
ImageSize:        0x0006E000
File version:     2006.1200.4518.1014
Product version:  2006.1200.4518.0

PostScript 格式简介

先介绍下 PostScript 基本的数据结构:

SIMPLE OBJECTS COMPOSITE OBJECTS
boolean array
fontID dictionary
integer file
mark gstate
name packedarray
null save
operator string
real

左侧为简单对象,右侧为复合对象。简单对象都是原子实体,类型、属性和值不可逆转地结合在一起,不能改变。但复合对象的值与对象本身是分开的,对象本身存储于 dict 对象中,具体的结构如下:

// PostScript Object
struct PostScript object
{
    dword    type;  //对象类型
    dword    attr;
    dword    value1; //指向对象所属变量名称
    dword    value2; //若为简单对象,直接指向值;若为复合对象,指向存储的值的结构
}ps_obj;

//字典‘key-value’对象的定义
struct Dictionary_key_value {
    dword *pNext; //指向存放PostScript Object的地址
    dword dwIndex;
    ps_obj key;
    ps_obj value;
} dict_kv;

其中部分 type 的值与类型的映射如下:

type 值 数据类型
0x0 nulltype
0x3 integertype
0x5 realtype
0x8 booleantype
0x10 operatortype
0x20 marktype
0x40 savetype
0x300 nametype
0x500 stringtype
0x900 filetype
0x30000 arraytype
0x70000 packedarraytype
0x0B0000 packedarraytype
0x110000 dicttype
0x210000 gstatetype

接着介绍下漏洞中使用到的比较关键的操作符的意义:

操作符 示例 解析
forall array proc forall 枚举第一个操作数的元素,为每个元素执行过程 proc。如果第一个操作数是数组、压缩数组或字符串对象,则 forall 将一个元素压入操作数堆栈,并对对象中的每个元素执行 proc,从索引为 0 的元素开始并依次执行。
dup any dup ---> any any 复制操作数堆栈上的顶部元素。dup 只复制对象;复合对象的值不是复制而是共享的。
putinterval array1 index array2 putinterval 用第三个操作数的全部内容替换第一个操作数的元素的子序列。被替换的子序列从第一个操作数的 index 开始;它的长度与第三个操作数的长度相同。
put/get array index any put/get 替换/获取第一个操作数的一个元素的值。如果第一个操作数是一个数组或一个字符串,put/get 将第二个操作数视为一个索引,并将第三个操作数存储在索引所确定的位置,从 0 开始计算。
save /save save 保存当前 VM 状态快照,一个快照只能使用一次。
restore save restore 丢弃本地 VM 中自相应保存以来创建的所有对象,并回收它们占用的内存;将本地 VM 中所有复合对象的值(字符串除外)重置为保存时的状态;关闭自相应保存以来打开的文件,只要这些文件在 local VM 分配模式有效时打开。

了解了上述背景后,开始分析漏洞。

漏洞成因

通过使用 forall 操作符获取创建的字符串对象,并在第一次循环时使用 restore 操作符释放字符串对象,随后创建新的字符串对象使得原本存储旧字符串对象的结构被新复合对象代替。若故意构造大小为 0x27 的字符串对象,则字符串被释放后会多出 0x28 的内存空间,此时立即创建新的字符串对象,则该内存会用来存储指向新字符串的 string 结构。随后通过改变 forall 的函数,获取指向新字符串的结构。

漏洞文件中一共触发了三次漏洞,第一次是获取了被释放的 string 的字符用于判断系统是 32 位还是 64 位。第二次触发故意构造大小为 0x27 的 string 对象,用于获取指向恶意 string 的结构。第三次则利用第二次构造的特殊 string 结构创造了一个起始地址为 0x00000000,大小为 0x7fffffff 的字符串,构造了能够读写任意地址内存的读写原语。接着利用读写原语搜索内存中函数地址构造 ROP 链。最终创建了一个文件对象,在调用 closefile 操作符时跳转执行 ROP 完成漏洞利用。

查看 poc.eps 文件,第一次调用 forall 如图所示:

Office EPS文件解析漏洞分析

在 ida 中定位到 forall 操作符的代码:

Office EPS文件解析漏洞分析

使用 windbg 找到对应偏移后下断:sxe ld EPSIMP32;g;bp EPSIMP32+2b928;g;

Office EPS文件解析漏洞分析

运行到图中所示位置时查看 edi 的值,指向了 forall 的 dict 对象,接着查看*pnext,发现存储了两个对象,第一个为 string l63,第二个为 array l61

Office EPS文件解析漏洞分析

继续分析,会获取 l63 和 l61 对象到栈中,并确认 l63 的类型为 string 后,跳转到获取 string 类型元素部分

Office EPS文件解析漏洞分析

获取值的过程会因为 type 的不同而有所变化,具体如图所示:

Office EPS文件解析漏洞分析

通过调试可以更加直观的看到通过 value2 获取 string 的方式:

Office EPS文件解析漏洞分析

接着循环获取 string 中的每一个元素并执行函数:

Office EPS文件解析漏洞分析

此时传入 deferred_exec 的参数为 eax,查看传入参数:

0:000> bp EPSIMP32+2ba06          //call    deferred_exec
0:000> g
Breakpoint 1 hit
eax=0018fd78 ebx=00000000 ecx=00291280 edx=00000001 esi=00425770 edi=00000000
eip=718fba06 esp=0018fd54 ebp=0018fdbc iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202
EPSIMP32!RegisterPercentCallback+0x4604:
718fba06 e8d8abffff      call    deferred_exec (718f65e3)
0:000> dd eax L4        //查看传入的参数为数组
0018fd78  00030000 00000000 0049ea98 0048f40c
0:000> dd poi(poi(poi(poi(poi( 0018fd78 +c))+24))+28)   //查看数组中存储的内容
0049e2c0  00000500 00000100 00495408 0048ee98   //数组中存放着字符串对象
0049e2d0  12d85688 8000f194 00000020 00000100
0049e2e0  0049dc40 0048f198 12d8568f 80000000
0049e2f0  00490023 000007c8 00000300 00000100
0049e300  12d856b2 8000f19c 00000026 00000100
0049e310  0049dc60 0048f1a0 12d856b1 80000100
0049e320  00420029 0048f1a4 00000003 00000000
0049e330  12d856b4 80000080 0000002c 00000100
0:000> db poi(poi(poi(poi(poi( 0049e2c0 +c))+24))+20) L10   //查看字符串的内容为l56 cvx exec
00495940  20 6c 35 36 20 63 76 78-20 65 78 65 63 20 00 00   l56 cvx exec ..
0:000> g        //第二次执行deferred_exec
(5c8.144): C++ EH exception - code e06d7363 (first chance)
(5c8.144): C++ EH exception - code e06d7363 (first chance)
Breakpoint 1 hit
eax=0018fd78 ebx=00000000 ecx=00291280 edx=00000003 esi=00425770 edi=00000001
eip=718fba06 esp=0018fd54 ebp=0018fdbc iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206
EPSIMP32!RegisterPercentCallback+0x4604:
718fba06 e8d8abffff      call    EPSIMP32+0x265e3 (718f65e3)
0:000> dd poi(poi(poi(poi(poi( 0018fd78 +c))+24))+28)   //查看数组的内容
0049e2c0  00000500 00000100 00495438 0048eeac   //数组中存放着字符串对象
0049e2d0  12d85688 8000f194 00000020 00000100
0049e2e0  0049dc40 0048f198 12d8568f 80000000
0049e2f0  00490023 000007c8 00000300 00000100
0049e300  12d856b2 8000f19c 00000026 00000100
0049e310  0049dc60 0048f1a0 12d856b1 80000100
0049e320  00420029 0048f1a4 00000003 00000000
0049e330  12d856b4 80000080 0000002c 00000100
0:000> db poi(poi(poi(poi(poi( 0049e2c0 +c))+24))+20) L10   //查看字符串的内容为l53 cvx exec
00495958  20 6c 35 33 20 63 76 78-20 65 78 65 63 20 00 00   l53 cvx exec ..

从调试的结果可以得知,该函数执行的正是 forall。在第一次执行时,l61 中待执行的命令是l56 cvx exec,在第二次执行时,l61 中的内容已经被换成了l53 cvx exec与调试结果相符。

接着深入函数分析,发现函数内部嵌套了 deferred_exec:

Office EPS文件解析漏洞分析

于是重新调试,下断在此,分析参数:

Office EPS文件解析漏洞分析

虽然 type 为 0x10 的操作符对象存储在 Systemdict 中无法查看,但是通过其他字符和数字还是能够确定该语句就是 l50。当执行该语句后,原本 l63 指向的 string 结构将被替换成存放 l52 内容的 string 结构:

Office EPS文件解析漏洞分析

可以看到此时原本存放 l63 的 string 结构已经变成了 l52。

在 get 函数下断,跳转到 forall 下的/l64 l57 56 get def语句查看 l57 的值:

Office EPS文件解析漏洞分析

可以证实 l57 中存放的就是从 l63 中获取到的字符,该 forall 的作用就是泄露被释放的 string 结构指向的字符串。

接着获取 l57 中的值,并进行一些处理,通过 ifelse 判断系统位数,若 l77 等于 l52 的长度+1,那么 l99 的值为 1 代表系统为 64 位,否则 l99 为 0,代表系统为 32 位:

Office EPS文件解析漏洞分析

可以看到在 32 位的调试环境下,l77 的值为 0,因此会将 5 个 0 压入操作栈中,并赋值给 l95 到 l99:

Office EPS文件解析漏洞分析

至此,漏洞原理部分分析完毕,接下来分析漏洞利用部分。

漏洞利用

第二次执行 forall 代码如下:

Office EPS文件解析漏洞分析

和第一次执行十分类似,因此就不深入分析。查看执行完 forall 后 stringl63 的变化:

Office EPS文件解析漏洞分析

查看 l63 中的值,发现是一个 string 结构,于是查看字符串,内容正是 l102 中存储的 l36 的字符串

Office EPS文件解析漏洞分析

接着通过l90 0 l92 putinterval将 l63 中指向的第一个 4 字节的内容改为 0x02b14ad4,该值指向 l36 中四字节之后的内容

Office EPS文件解析漏洞分析

经过多次修改,字符串修改为如下状态,修改的值会在第三次漏洞触发时使用到:

Office EPS文件解析漏洞分析

接着查看 l137 获取的是 l63 中 0x4 处的值,l138 获取的是 l63 中 0x20 处的值,l103 的值为 1

Office EPS文件解析漏洞分析

第二次漏洞触发部分分析完毕,接下分析第三次漏洞触发构造读写原语的部分。

构造读写原语

l142 中存储的是将 l138 放入到 l193 的 0x24 位置的后的字符串:

Office EPS文件解析漏洞分析

接着使用 forall 操作符遍历 l63 数组,当遍历到第 54 个元素时,恢复快照。此时 array l63 被释放,接着复制 l142 字符串,使得 array l63 对象被 l142 字符串对象覆盖:

Office EPS文件解析漏洞分析

此时查看被覆盖后的 l63 中最后一次会被获取的值:

Office EPS文件解析漏洞分析

说明最后一次会获取一个 array 对象,继续深入查看该对象发现存储了一个字符串,该字符串起始地址为 0x00000000,大小为 0x7fffffff:

Office EPS文件解析漏洞分析

通过该字符串,可读写内存中 0x00000000-0x7fffffff 的任意地址,实现了读写原语的构造,最终将字符串对象存储在 l201 中。

构建 ROP 链

通过字符串 l201 获取 EPSIMP32 的基地址为:0x74750000,并存入 l314 中:

Office EPS文件解析漏洞分析

接着通过 EPSIMP32 的导入表获取 kernel32.dll 的基地址并存放于 l315 中:

Office EPS文件解析漏洞分析

随后开始利用读写原语搜索内存中的 gadget 用于构造 ROP 链:

Office EPS文件解析漏洞分析

将构造好的 ROP 链放入伪造的文件对象中,并将对象放置在 l159 的 2 号元素中,将恶意 pe 文件和 shellcode 组成的字符串放置在 l159 的 3 号元素中:

Office EPS文件解析漏洞分析

最终调用 closefile 操作符关闭伪造的文件对象,在关闭过程中会执行call [eax+8]使得跳转到构造好的 ROP 链中:

Office EPS文件解析漏洞分析

至此,整个漏洞的原理和利用分析完毕,剩下的行为部分不再分析。

总结

该样本漏洞利用的十分巧妙,通过 UAF 将原本正常的数组对象替换为指向构造好的能够读写任意内存的字符串对象。通过字符串对象实现了读写任意内存并构造 ROP 链的目的,并最终将构造好的 ROP 字符串对象修改为文件对象,利用 cloasefile 操作符跳转到 ROP 链中。

尽管微软已经关闭了 Office 对于 EPS 文件的支持,但该格式文件仍然能被 Adobe Illustrator 打开,如果深入研究该类型文件可能仍有出现漏洞的可能。

参考链接

[1] PostScript LANGUAGE REFERENCE: https://www.adobe.com/content/dam/acom/en/devnet/actionscript/articles/PLRM.pdf

[2] eps-CVE-2017-0261: 

https://github.com/kcufId/eps-CVE-2017-0261

[3] CVE-2017-0261及利用样本分析: 

https://bbs.pediy.com/thread-261442.htm

[4] EPS Processing Zero-Days Exploited by Multiple Threat Actors: https://www.fireeye.com/blog/threat-research/2017/05/eps-processing-zero-days.html


原文始发于微信公众号(天玄安全实验室):Office EPS文件解析漏洞分析

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年10月2日05:45:33
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Office EPS文件解析漏洞分析https://cn-sec.com/archives/901184.html

发表评论

匿名网友 填写信息