用于处理 Python 图像处理的 PIL(Pillow)模块,由于内部调用 GhostScript,受到 GhostButt 漏洞(CVE-2017-8291)的影响,导致远程命令执行漏洞。
PIL 内部根据图片头部(Magic Bytes)判断图片类型,如果发现是 EPS 文件(文件头为 %!PS),则分发到 PIL/EpsImagePlugin.py 进行处理。
在该模块中,PIL 调用系统的 gs 命令,也就是 GhostScript,来处理图片文件:
command = ["gs",
"-q", # quiet mode
"-g%dx%d" % size, # set output geometry (pixels)
"-r%fx%f" % res, # set input DPI (dots per inch)
"-dBATCH", # exit after processing
"-dNOPAUSE", # don't pause between pages,
"-dSAFER", # safe mode
"-sDEVICE=ppmraw", # ppm driver
"-sOutputFile=%s" % outfile, # output file
"-c", "%d %d translate" % (-bbox[0], -bbox[1]),
# adjust for image origin
"-f", infile, # input file
]
# 省略判断 GhostScript 是否安装的代码
try:
with open(os.devnull, 'w+b') as devnull:
subprocess.check_call(command, stdin=devnull, stdout=devnull)
im = Image.open(outfile)
虽然设置了 -dSAFER,也就是安全模式,但由于 GhostScript 中的沙箱绕过漏洞(GhostButt CVE-2017-8291),该安全模式被绕过,可以执行任意命令。
此外,截至目前,GhostScript 最新的官方版本 9.21 仍然受到此漏洞的影响,因此可以说,只要操作系统上安装了 GhostScript,我们的 PIL 就存在命令执行漏洞。
运行环境:
docker-compose up -d
运行后,访问 http://your-ip:8000/ 即可看到一个上传页面。正常功能是上传一个 PNG 文件,后端调用 PIL 加载图片,并输出长和宽。但我们可以将可执行命令的 EPS 文件后缀改为 PNG 后进行上传,因为后端是根据文件头部来判断图片类型的,所以后缀检查被忽略。
例如,上传 poc.png,即可执行 touch /tmp/youhavebeenpwned。将 POC 中的命令改为反弹命令即可获得 shell: