这个漏洞其实影响也挺广的,虽然是需要授权,但其实在公网上暴露的很多gitlab都是开放注册的,其实也基本等于给了授权。除此之外,获取CSRF_TOKEN后也可以触发。这个漏洞本质不是gitlab
的代码问题,而是gitlab
在文件处理时的逻辑,引用了第三方exiftool
组件导致在解析时出现问题,从而引起的任意文件执行。
总结一下: gitab
中的gitlab-horse
会根据上传文件的标识符来判断文件类型,不同类型有着不同的处理逻辑,对于图片类的文件,会去调用exiftool
组件来清除图片文件的元数据,而exiftool
组件在处理Djvu
格式文件的时候,存在缺陷,可以透过构造恶意的元数据造成双引号逃逸,从而执行任意指令。
gitlab 数据传递逻辑
首先我们去下载个受影响版本的gitlab,https://github.com/gitlabhq/gitlabhq/tree/v13.10.2。官网对于gitlab-workhorse的描述可以见下图所示。可以看到,最前端nginx会将请求代理给gitlab-workhorse,按官方的说法,gitlab-workhorse用于处理负载量较大的HTTP请求,例如文件的上传下载、git操作等。
在gitlab-workhorse的文档中描述了,其安装时依赖ExifTool
,用于擦除元数据。
我们来看一下程序里面实现的逻辑。首先会去判断上传的文件类型,如果是exif
文件的话,会去调用handleExifUpload
函数进行元数据清理。handleExifUpload
中会去调用NewCleaner-->cleaner
,最终执行exiftool
指令进行数据清除。
在清理之前,会去判断元数据的tag是否存在,清除掉敏感元数据保留允许的tags。可以看到最终通过exif_tags
方法触发了exiftool
对于文件元数据tag的解析,从而造成漏洞利用。
exiftool漏洞详情
上面我们介绍了gitlab-workhorse的处理逻辑,接下来我们来看exiftool部分的逻辑。ExifTool
是由Phil Harvey
开发的一个跨平台元数据处理软件,由perl语言编写而成,支持大量的不同格式的数据,包括图像、音频、视频、pdf等等,详见exiftool官网。这个漏洞是利用的exiftool低版本的一个RCE漏洞,而在gitlab-workhorse中的操作指南提到,推荐使用apt install libimage-exiftool-perl
进行安装,而默认源中的版本较低,存在漏洞。
exiftool简介
exiftool的整体逻辑还是比较清晰的。如下图,为其代码的整体结构图,因为是perl语言编写的,看起来还是比较容易的。入口文件为exiftool
,lib文件夹中存放了处理不同文件格式对应的逻辑代码,以文件类型名+.pm
为结尾。t文件夹中是各种文件类型的样例,方便将其作为基础进行使用。
|
|
exiftool DjVu RCE利用
这个漏洞在DjVu格式文件的处理逻辑中。我们首先来了解下DjVu是什么。djvu在过去主要用于存储扫描的文档,如电子书等,其相对于PDF并不普及,其对二进制图像有损压缩,从而以较小的控件存放高质量的可读图像。可以找一个例子看下,使用exiftool xxxx.djvu
来查看解析djvu元数据。好像并看不出来什么,都是格式化后的kv形式。我们来看DjVu.pm
文件。可以看到函数ProcessAnt
用于检查判断是否存在注释性语句,/\(\s*(metadata|xmp)[\s("]/
其格式应该是匹配这样的正则表达式。ParseAnt
是一个递归调用的函数,用于从(xxx)
的注释性数据中,解析出kv的内容。
为了验证我们的猜想,我们将$dataPt
输出出来,如下图,可以看到metdata如我们分析的一样,是以(kv kv)
的形式存储的。其中value的值用"
双引号包裹。
知道格式了,我们来说下这个漏洞。很明显,罪恶之源eval
又出现了。在上面的代码中,会通过$
来匹配文件末尾,但如果字符串是多行字符串时,只会匹配到第一行末尾,而重新构造一个新行和新引号时,会将第二个引号进行毕业从而逃逸出来,第二个引号后的内容便可以直接被执行。qq
的意思是将其作为双引号字符串来输出。
因此,当我们可以构造一个带有恶意元数据的DjVu文件时,将其用exiftool解析即可触发漏洞。为了构造DjVu格式,我们可以根据官方提供的DjVu文档来进行修改构造,文档见djvu_document。大致简单介绍下,DjVu
主要是用于存储电子书,所以其存储的内容基于和我们现在看到的pdf类似。其由单页或多页组成,并可以保存注释信息、隐藏文字信息以及缩略图。不同的层/块(chink)用于保存不同的信息,例如DIRM
块存储目录信息,ANTz
块存储注释信息。FORM
块表示是一个合成块,包含有多个其他的块。
不同类型的文档有着不同的块,比如单页文档在一个FORM:DJVU
块中,而多页文档用FORM:DJVM
标识,且其内部的第一个块是文档块DIRM
。注释信息在ANTa
或者ANTz
块中,原文信息在TXTa
或者TXTz
块当中,其余的不做过多介绍,可以参考文档查询。
可以看到,前4字节是magic标识,用于标识是djvu文件。之后就是chunk_data
,每个chunk_data
由3部分组成,chunk_id
,length
以及具体的data
。
那么现在我们根据已知的信息来构造恶意文件,我们知道构造的payload在metadata中,也就是注释块中,我们使用明文ANTa
块更便于我们生成payload,但要注意ANTz
也是可以的,其结果是使用BZZ encoder
进行压缩后的内容。我们首先根据t/image/DjVu.djvu
来进行修改,修改一个正常的内容。
|
|
看来我们理解的没错,接下来我们试着去插入恶意payload,可以看到已经执行了指令。
其他模块解析
#AIFF
之前提到的漏洞点在DjVu
模块的处理逻辑中,一些复杂的文件格式一般都会支持内置各种其他的文件格式,那么是否有其他模块调用了该模块的解析函数?我们对整个目录进行搜索,可以看到了AIFF
模块中调用了DjVu
模块。而AIFF
解析数据时会去判断数据格式是否为DjVu
,如果是解析对应的数据。因此在AIFF
中插入DjVu
数据再去解析也可以触发漏洞。
#Extractinfo
除了直接在代码中写了去调用DjVu
模块,在exiftool.pm
中有Extractinfo
函数,其会根据不同的magicNumber头去判断文件所属类型,从而调用不同的$module.pm
来进行解析。因此,如果我们上传的文件能够触发Extractinfo
函数并通过构造AT&T
头让其解析为DjVu
格式进而调用DjVu.pm
的处理函数,造成漏洞利用。
因此我们的目标就是搜索其他什么类型的文件处理逻辑中调用了Extractinfo
来解析内容,且解析的方式应该是递归式的根据文件每个块的类型进行解析。根据搜索结果,应该有9个类型解析时会触发调用Extractinfo
字段,包括Cannon/CaptureOne/Exif/MPF/PDF/PGF/Rawzor/Samsung/ZIP
我们点进去看,每个处理逻辑其实是需要一定的触发条件的,利用exif
类型需要使用特定的TAG,PDF
需要使用特定的filter等等。
#Exif
这里我们看下Exif.pm
的处理逻辑,其是用于Read EXIF/TIFF meta information
。EXIF
格式我不太熟悉,而TIFF
我们知道是一个位图格式,应该跟我们以前的文章image文件格式解析分析jpg、png时差不多。这里TIFF
格式解析参考这篇文章TIFF 文件格式以及样例t/image/exiftool.tif
基本可以弄的差不多。因此,如果我们构造一个0xc51b
的块,然后将其数据填充为带恶意payload的Djvu
内容就可以触发利用。
比较方便的是,exiftool
有一个自定义配置并按照配置生成文件的功能,非常有用。我们随便从网上下载一个tiff
文件作为base,然后将我们构造的恶意数据插入进去。
|
|
其他文件格式的触发方式也类似,在此不再赘述,基本方法就是分析一下文件格式,然后按特定的方式插入payload构造恶意文件,最终触发漏洞。
Gitlab POC
分析完了原理,我们来实际进行验证一下在gitlab中的利用。如我们之前分析的,gitlab只会将jpg/jpeg/tiff
后缀的文件传入exiftool
进行tag清理,那么按我们的理解,我们只要任意找到一个上传点,上传的文件后缀改成jpg/jpeg/tiff
3者之一就可以触发。值得注意的是,尽管这个漏洞需要后台权限,但是很多对公网开放的gitlab网站都支持注册机制,因此鉴权的逻辑基本等于没有。
我们来试一下,我们随便开一个new issue然后进行上传,可以看到已经利用成功。
当我们对原有图片进行修改时,会调用PUT
方法,可以看到也可以成功。
当然,tiff
类型的文件上传,依旧可以触发成功。