名称: vulfocus/ghostscript-cve_2018_16509:latest ​ 描述: ​ GhostScript 被许多图片处理库所使用如 ImageMagick、Python PIL 等默认情况下这些库会根据图片的内容将其分发给不同的处理方法其中就包括 GhostScript。 ​ 在 9.24 之前的 Artifex Ghostscript 中发现了一个问题。能够提供精心制作的 PostScript 以使用“管道”指令执行代码的攻击者可能会在处理 /invalidaccess 异常期间使用不正确的“特权恢复”检查 ​ ​0x00 漏洞基本信息CVE 编号CVE-2018-16509漏洞类型沙盒绕过 / 远程代码执行 (RCE)受影响组件Ghostscript 9.24 之前的所有版本成因利用restores操作中的内存不一致性通过制造一个伪造的异常状态使内核在自同步过程中将LockSafetyParams从1误写为0。Ghostscript 的安全模式-dSAFER依赖于内存中的一个布尔值LockSafetyParams。当其为1时系统禁止修改敏感设备属性如输出路径OutputFile。当其为0时系统允许执行包括%pipe%管道重定向在内的高权限指令。0x01 必备知识点一、 PostScript 语法特性逆波兰表示法 (RPN)PostScript 是基于堆栈Stack的语言。它的核心逻辑是操作对象在前操作符在后。堆栈操作 (Stack-based)当你看到save或legal时解释器会把它们压入堆栈。当你看到undef或restore时解释器会从堆栈顶部取出数据并执行。可执行数组 (Procedure)语法{ ... }特性大括号内的内容不会立即执行而是作为一个整体过程压入堆栈。控制流 (Control Flow)语法stopped特性它执行前面的过程。如果过程报错它会在堆栈压入true否则压入false。语法if特性从堆栈取出一个布尔值如果是true则执行前面的代码块。名称与字典 (Name Dictionary)语法/name特性带斜杠的是“名称”相当于变量名不带斜杠的是执行该名称对应的命令二、沙盒看了维基有一段话挺有意思的“在沙盒页编辑的内容就像在沙滩上所写的文字涨潮时就会消失。同样沙盒中所写的内容不久也会消去。”意思就是修改沙盒只停留在一个虚拟层没有写入硬件一旦程序关闭一切修改都没了结合本此漏洞在Ghostscript中沙河开启只能处理数学运算和绘图指令。不能执行系统命令%pipe%ls”0x02 前期准备准备代码1.怎么绕过沙箱—— 在处理异常的时候趁机拿到高权限并”保存“最后执行代码%!PS userdict /setpagedevice undef save legal { null restore } stopped { pop } if { legal } stopped { pop } if restore mark /OutputFile (%pipe%ls / /tmp/success cat /tmp/success) currentdevice putdeviceprops一开始我们的沙盒状态LockSafetyParams truesave是保存当前所有状态。legal是调用预定义的页面尺寸设置legal会调用到setpagedevice调用的顺序是 字典栈中从上到下 最上面的是userdict最下面才是systemdict。但是后面 { legal } stopped { pop } if ,此时legal需要用的是系统字典中的setpagedevice并不是userdict里面的。[因为原生的、拥有底层操作权限的setpagedevice在执行时才会用底层的 C 函数gs_setpagedevice而此函数在legal处理设备重置时如果发现当前的null restore异常它会尝试自动同步设备状态那么我们就在硬件中储存了处理异常需要用到的高权限了]所以一开始我们可以undef删除掉用户字典中的setpagedevice他就只能拿到systemdic里面的setpagedevice了。由于null不能被restore所以stopped往堆栈里面扔了一个trueif拿到堆栈中的true执行pop清除掉推展顶部报错信息让程序继续进行此时权限上升了此时再legal一下强制调用设备页面重置由于刚刚pop后仍处于异常状态模式还没有处理完错误刚刚pop只是掩盖了报错信息也就是还是高权限状态而legal触发的setpagedevice会去修改页面参数legal只修改页面大小其他都照搬以前的配置由于刚刚处理异常时沙盒状态就是关着的legal后拿到的状态还是关着的沙盒状态。{ ... } stopped { pop } if掩盖其他报错再次保证程序继续运行restore看似是恢复原样实际上只能恢复 PostScript 层面的变量和堆栈之前沙盒关闭的配置没有被恢复却被”保存“起来了。然后进行命令输出mark /OutputFile (%pipe%命令) currentdevice putdevicepropsmark: 在堆栈中放置一个标记点。/OutputFile: 定义一个键Key(%pipe%...):pipe文件前缀会把后面的内容当成命令交给系统输出currentdevice: 将当前设备对象压入堆栈。putdeviceprops: 消费掉堆栈中从mark开始的所有数据将其作为属性应用到设备上。payloadPostScript (PS)%!PS userdict /setpagedevice undef save legal { null restore } stopped { pop } if { legal } stopped { pop } if restore mark /OutputFile (%pipe%ls / /tmp/success cat /tmp/success) currentdevice putdeviceprops​0x03 复现过程构造带有代码的图片 上传即可查看flag