内容简介:在这篇文章中,我将展示如何利用我们先回顾一下这个漏洞,首先,PostScript对象的类型为结构体
一、前言
在这篇文章中,我将展示如何利用 CVE-2018-19134 漏洞远程执行任意代码。该漏洞是由类型混淆引起的。2018年11月,该漏洞被发现。如果你想了解更多关于QL技术相关文章,可以翻看我以前的 博客 。
二、漏洞
我们先回顾一下这个漏洞,首先,PostScript对象的类型为结构体 ref_s (或者为ref,ref是ref_s的别名),如下图所示:
该结构大小为16字节,其中tas_s类型占据前8个字节,包含的字段为类型信息以及数组,字符串,字典的大小。如下图所示:
我发现该漏洞触发的原因是 zsetcolor 函数中缺少类型检查:在将其解释为gs_pattern_instance_t之前未进行pPatInst类型检查。如下图所示:
如下图所示,r_ptr是一个宏,被定义在 iref.h 文件中:
pstruct的值源自PostScript,因此由用户控制。例如,setpattern的输入将造成pPatInst.value.pstruct的值为0x41。如下所示:
将代码放入 pattern_instance_uses_base_space 后,我看到我控制了一个指针对象,代码将其解释为gs_pattern_instance_t指针,如下所示:
所以我可以控制许多函数指针:get_pattern,uses_base_space和pinst。
创建一个伪造的对象
PostScript类型数组非常重要,因为它的值指向ref数组开头的ref指针。并允许我创建一个缓冲区进行存储,我可以控制缓冲区内容,如下所示:
如上图,灰色部分表示我可以控制部分数据(我无法完全控制type_attrs和pad),绿色部分是我可以完全控制的数据。其中关键点是,refs中的值和gs_pattern_instance_t中的type都是8个字节,意味着pinst-> type-> procs中的procs将是部分被我控制的底层PostScript数组。事实证明,我确实可以通过使用嵌套数组来控制函数指针get_pattern和uses_base_space:
[16#41 [16#51 16#52]]的结果如下所示:
这表明我确实可以控制uses_base_space和get_pattern,下一步,如何使用任意函数指针来实现代码执行。
我决定先获取一些有效的函数指针,在Ghostscript中,内置的PostScript运算符由 t_operator 类型表示,ref的值是一个op_proc_t,它是一个 函数指针 。可以通过下面的命令获得:
让我们尝试在我们伪造的数组中加入一些内置函数,如下所示:
我将使用以下指令:systemdict
实际上,我现在可以直接调用zget函数和zput函数来替代uses_base_space和get_pattern,如下所示:
我现在可以调用PostScript中的函数并控制函数的参数,当从PostScript调用底层C函数时,执行上下文作为参数传递给C函数,该上下文类型为 i_ctx_t (gs_context_state_s的别名),包含许多无法通过PostScript控制的信息,其中包括重要的安全设置,如LockFilePermissions,如下所示:
当从PostScript调用操作符时,传递的参数存储在op_stack中,通过直接调用这些函数并控制参数i_ctx_p。
我们尝试创建一个PostScript数组来伪造i_ctx_t对象,PostScript函数参数存储在i_ctx_p-> op_stack.stack.p中,这是一个指向参数的ref指针。为了使用伪造的上下文调用PostScript函数,我需要控制p。从p到i_ctx_p的偏移量实际上与op_stack的偏移量相同,即0x270。由于每个ref的大小为0x10,所以对应伪造数组的第39个元素。
从上图可以看出,这种对齐并不理想,op_stack.stack.p对应数组的tas部分,我无法完全控制,如果只有op_stack对应的ref值,我便能成功控制。另外,tas存储了ref的元数据,即使我完全控制,也无法在不知道其地址的情况下将其设置为任意对象地址。因此,任何漏洞利用很可能只会在此时崩溃在Ghostscript中。
获取任意的读写原语
我想找到一个符合下列条件的PostScript函数:
1.引用osp(op_stack.stack.p)指针
2.使用osp指针做一些事情
3.可在SAFER模式下使用
我想到了pop运算,如下所示:
它使用check_op检查堆栈指针的值,并将osp与指针osbot进行比较,如果大于osbot,则减小osp的值,这是一个简单的函数,并且不会取消引用osp。我们先仔细研究一下ref和op_stack的结构,如下图所示:
回顾我们之前提到的东西,在我们伪造的对象中,op_stack是ref数组的第39个元素,如上图,字段tas对应p,而value对应osbot。type_attrs,_padd和rsize三个字段组合在一起形成op_stack中的指针p。如之前提到的,type_attrs指定ref对象的类型及其可访问性。通过pop函数,我可以修改选择对象的类型和可访问性。但问题在于,pop只有在p大于osbot时才有效,osbot是ref对象的地址。所以我篡改的对象需要是一个足够大的字符串,数组或字典。以便于rsize字段大于大多数ref对象的指针地址。我无法仅修改systemdict等内置只读对象的可访问性以获得写权限。但是,我可以做以下事情:
1.我可以使用将数组转换为字符串的方法,将内部引用数组视为字节数组,因为PostScript中的字符串不是由空字符终止,而是由rsize指定的长度。因此任何字节都可以从缓冲区读/写。值得注意的是,这样做并不会产生任何越界读/写,因为结果字符串具有与原始数组相同的长度,生成的字节缓冲区仅覆盖ref数组分配缓冲区的1/16。
2.我也可以反过来做,将一个字符串转换成一个相同长度的数组。如上所述,生成的ref数组将比原始字符串数组大16倍,这样我可以进行OOB读写,但我没有这么做。
我还需要克服另一个技术难题,伪造对象,pinst实际上调用了两个函数,如下所示,一个函数输出到另一个:
如上所示,use_base_space的返回值是pinst-> type-> procs.get_pattern(pinst)。现在,我们把zpop(pinst)作为输入。当我使用任何内置的PostScript运算符替代uses_base_space时,可能导致产生空指针。使zpop返回0。我需要找到一个不使用上下文指针i_ctx_p的操作。
下面是我进行的查找代码:
我的QL查询使用了一些启发式方法来识别PostScript运算符,它们的名称通常以z开头,并在psi目录中定义。它们也采用i_ctx_t 类型的参数,然后,我查找不会取消引用参数的函数,该函数不会调用自身且不包含i_ctx_t 类型的变量。
您可以在LGTM.com上的130,000+的GitHub,Bitbucket和GitLab项目上运行自己的QL查询,您可以使用在 线查询控制台 ,也可以安装 QL for Eclipse 插件并在本地快照上运行查询语句。Ghostscript不是在GitHub,Bitbucket或GitLab上开发的,因此LGTM.com尚未对其进行分析。 但是您可以在此处下载 Ghostscript代码快照 。
查询后返回了6个结果:
如上图所示,ucache函数是我们所需要的。首先我们伪造pinst对象,如下所示:
现在我们需要创建一个大型数组对象并将其存储在pinst的第39个元素中。它的元数据tas将被解释为堆栈指针地址osp。我将使用PostScript中的put运算作为第一个元素,然后使用pop将类型更改为字符串并读取zput函数的地址。
不幸的是,数组的type_attrs值是0x4,而string的值是0x12。我必须使ushort下溢以从数组转换为字符串。所以我进行impl setpattern操作1291次。
从上面的截图可以看出,伪造的数组被转换为字符串,我得到了zput的地址。我可以使用该方法将字节写入arr中的任何位置。
现在我可以从任意PostScript对象读取和写入任意字节。我最初的计划是覆盖LockFilePermissions参数,然后调用file,允许任意命令执行,如同 CVE-2018-19475 中的操作。然而,事实证明,我还需要伪造许多对象。这使工作变得复杂。相反,我仅仅想要调用一个简单但功能强大的函数,forceput操作能够满足我的需求。
总结一下,我需要做的事情:
1.使用forceput提供的参数创建一个伪造的操作数堆栈。
2.覆盖pinst中的地址,并将操作数堆栈指针的地址存储到我上面创建的堆栈中。
3.获取forceput的地址,并替换pinst-> type.procs.getpattern的值。
为了实现1,我只需要用我的参数创建一个数组。如下所示:
然后我可以将它存储在arr中以检索此数组的地址。重用pinst并将其放在第31个元素中:
使用上一节的技巧,我现在可以读取这个伪造堆栈指针的地址并将其写入pinst中的适当位置。我可以简单获取zput地址,并将其偏移量添加到zforceput以获取zforceput的地址(因为此偏移量不是随机的)。在使用commit 81f3d1e编译的调试二进制文件中,此偏移量为0x437,在9.25版本中,偏移量为0x4B0。执行此操作后,我可以将LockFilePermissions参数写入当前设备,然后运行任意 shell 命令。如下所示,是从Ghostscript中启动计算器的示意图。
通过覆盖userparams中的其他字段,如PermitFileReading和PermitFileWriting,还可以获得任意文件访问。至此,漏洞利用结束。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 如何使用类型混淆(CVE-2018-12794)在Adobe Reader执行代码
- Flash Player类型混淆严重漏洞,成功利用可能导致任意代码执行(CVE-2018-15981)
- Powershell编码与混淆
- Android修炼之混淆
- 类型混淆漏洞实例浅析
- PHP 代码混淆处理思路
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Persuasive Technology
B.J. Fogg / Morgan Kaufmann / 2002-12 / USD 39.95
Can computers change what you think and do? Can they motivate you to stop smoking, persuade you to buy insurance, or convince you to join the Army? "Yes, they can," says Dr. B.J. Fogg, directo......一起来看看 《Persuasive Technology》 这本书的介绍吧!
XML、JSON 在线转换
在线XML、JSON转换工具
UNIX 时间戳转换
UNIX 时间戳转换