记一次电子表格文件转换中的漏洞挖掘和利用 - 嘶吼 RoarTalk – 网络安全行业综合服务平台,4hou.com

记一次电子表格文件转换中的漏洞挖掘和利用

atp7bkil 资讯 2020-03-23 09:15:00
562003
收藏

导语:我们在尝试将 LibreOffice 识别为 PDF 渲染服务时,发现了多个代码实现上的漏洞。

image.png

研究人员:

· Brett Buerhaus 布雷特 · 布尔豪斯

· Cody Brocious (Daeken) 科迪 · 布罗斯(戴肯)

· Sam Erb (erbbysam)

· Olivier Beg (Smiegles) 奥利维尔 · 贝格(Smiegles)

介绍

我们在尝试将 LibreOffice 识别为 PDF 渲染服务时,发现了多个代码实现上的漏洞。

本文介绍了我们在 LibreOffice 指纹识别、 LibreOffice 文件检测(以及滥用)和 LibreOffice Python-UNO 桥接方面的工作。

比较流行的 unconv 库无意中滥用了 Python-UNO 桥接器,导致了 CVE-2019-17400漏洞。

我们相信我们的研究并不是终点,我们鼓励其他人也研究这个领域。

LibreOffice

Libreoffice 是 OpenOffice 的一个开源分支,通过在 google 搜索,你可以看到仅在过去几周就有几个关键的 CVE 产生。 LibreOffice 的 Github 项目有超过50万的提交代码,其中包括多年未更新的代码。 由于允许无头文件转换,许多公司依赖于使用 LibreOffice 将通用文档格式导出到 HTML/PDF。

电子表格转换器指纹识别

我们采用以下两种方法对多个网站的文档渲染服务进行了指纹识别。

INFO 功能

大多数电子表格规范,例如 XLSX 或 ODS,都为你提供 INFO 功能,以便为你提供有关打开电子表格的软件或系统的信息。

这里需要注意的一个重要观察结果是,尽管客户端限制了文件扩展名,但我们遇到的许多网站都允许渲染任何支持 LibreOffice 的文件类型。 利用这一点,我们可以测试 XLSX 文件上传。 (更多内容见下文)

 image.png

这是一个有用的标识符,原因如下。 =INFO("osversion")函数对于 OpenOffice/LibreOffice 具有硬编码值。 OpenOffice 和旧版本的 Libre 返回了一个 INFO 函数的错误,2015年后它不支持 LibreOffice ,并将显示“#N/A”。 这些细微差别为创建一个 XLSX 文件提供了机会,该文件可用于更好地了解服务器上处理电子表格的内容。

下面是我们最终使用的指纹:

其中 c4单元格为 =INFO("DIRECTORY") 

image.png

对 OpenOffice 的检查是由于 Libre 是 OpenOffice 的分支,如果你调用一个 OO/Libre 不支持的 Excel INFO 函数,最终会添加结果 #N/A。 这是在这个提交中添加的: https://github.com/LibreOffice/core/commit/db6a928a420868b2a80ba11c8d46151d16c13624。 所以不能完全保证,但是她可以帮助你决定是否要尝试一些老版本的 Libre CVE。

同样值得注意的是,最近 Libre 开始将 git 散列作为他们的版本号,因此 INFO("release") 将帮助你找到正在使用的软件的确切版本。

除了指纹识别应用程序进行转换之外,它还会告诉你一些其他的事情。 一个有用的例子是 OSVERSION,因为它将告诉你服务器的操作系统(WIN、 LINUX、 SOLARIS) ,这些操作系统可能是有用的侦察数据,可以根据服务器的情况调整攻击。另一个对Excel有用的是DIRECTORY,它告诉你当前的工作目录,根据文件位置给你一个路径提示或Windows用户名。

PDF 元数据

由于大多数应用程序使用 OpenOffice/LibreOffice 将 XLSX/DOCX 导出为 PDF,如果应用程序将转换后的原始PDF返回给你,那么它很可能包含诸如正在使用的LibreOffice版本之类的元数据。下面是 Slack 中的情况。

https://files.slack.com/files-pri/[filehash]/download/asdf.odt_converted.pdf

结果如下:

image.png

一个常见的文件扩展名陷阱

在我们最初的测试中,我们观察到一个网站只会渲染扩展名为.xlsx 的文档。 然后,该网站将使用 LibreOffice 渲染该文件。 然后,我们创建了一个 ODS 文档,并将其重命名为使用 XLSX 扩展。 噗! 它现在返回 ODS 文件的预览。 这是利用  Open/LibreOffice 转换的入口点。

有些应用程序获取你用 XLSX 或 DOCX 扩展上传的文件,并将它们传递到 OpenOffice,而不执行强文件格式验证或安全地配置过滤器。 当转换这些文件时,所使用的转换流是由文件内容而不是扩展名决定的。

LibreOffice/OpenOffice 文件检测

请注意,我们对代码分析没有很高的信心。

当使用 --convert-to 和 --headless 参数通过 soffice 传递文件时,它将通过代码流来确定要传递给它的文件类型。 在我们的研究中,绝大多数都输出到 PDF 中,可以用下面的流程来概括:

· 如果没有指定硬过滤器,会进行文件格式的猜测

· 检查传递文件的文件扩展名

· 它根据文件内容(例如魔术头)检查过滤器

· 它有一个文档格式列表分析系统,并根据复杂程度对它们进行排序。 例如,它将在回到 XML 或 HTML 之前检测它是否是复杂的 XML 格式(如 docbook)

· 如果扩展和过滤器不匹配,它就会回到仅仅依赖过滤器猜测的状态

https://github.com/LibreOffice/core/blob/master/desktop/source/app/dispatchwatcher.cxx#L595

OUString aParam = aDispatchRequest.aPrinterName;
sal_Int32 nFilterIndex = aParam.indexOf( ':' );
bool bGuess = false;
if( nFilterIndex >= 0 ) {
    ...
} else {
    // Guess
    bGuess = true;
    aFilterExt = aParam.copy( 0, nPathIndex );
}

如果在 URI 中未指定筛选器,则启用猜测文件格式流。

if ( bGuess ) {
    ...
    aFilter = impl_GuessFilter( aOutFile, aDocService );
}
OUString impl_GuessFilter( const OUString& rUrlOut, const OUString& rDocService ) {
    std::shared_ptr pOutFilter = impl_getExportFilterFromUrl( rUrlOut, rDocService );
    ...
}
std::shared_ptr impl_getExportFilterFromUrl( const OUString& rUrl, const OUString& rFactory) {
    try {
        const Reference< XComponentContext > xContext( comphelper::getProcessComponentContext() );
        const Reference< document::XTypeDetection > xTypeDetector( xContext->getServiceManager()->createInstanceWithContext( "com.sun.star.document.TypeDetection", xContext ), UNO_QUERY_THROW );
        const OUString aTypeName( xTypeDetector->queryTypeByURL( rUrl ) );

现在,它依赖于一组基于com.sun.star.document.TypeDetection的可配置过滤器。 这些过滤器用于确定文件类型,可以大致概括为检查文件内容中的魔术头字节或硬编码字符串。 这意味着,如果你使用 word 文档或电子表格并导出到 PDF,它将完全否定 docx 或 xlsx 扩展名,并猜测如果它没有检测到xlsx或docx文件头,文件格式会是什么。

下面是一个 Encapsulated PostScript (EPFS) 的例子:

· 过滤器:https://github.com/LibreOffice/core/blob/master/filter/source/config/fragments/types/eps_Encapsulated_PostScript.xcu

· 检查:https://github.com/LibreOffice/core/blob/master/vcl/source/filter/GraphicFormatDetector.cxx#L322

bool GraphicFormatDetector::checkEPS()
{
    if ((mnFirstLong == 0xC5D0D3C6)
        || (ImplSearchEntry(maFirstBytes.data(), reinterpret_cast("%!PS-Adobe"),
                            10, 10)
            && ImplSearchEntry(&maFirstBytes[15], reinterpret_cast("EPS"), 3, 3)))
    {
        msDetectedFormat = "EPS";
        return true;
    }
    return false;
}

正如你所看到的,你不能只是将“PS-Adobe”放入一个文本文件并进行转换。 它还会检查“EPS”是否跟在PS-Adobe 头之后。 一旦确定了如何对特定文件格式进行文件检测,如果转换允许,就可以开始利用该文件格式。

LibreOffice 支持的文件格式

LibreOffice 支持的文件格式大约有100个。 这里有太多的内容需要介绍,所以我将在这里留下 Wiki 表的链接:

https://en.wikipedia.org/wiki/LibreOffice#Supported_file_formats

你需要单击“Show”链接来展开表。

Excel 中的 Ghost (script)

在支持的文件格式中,我们首先注意到 LibreOffice 支持 EPFS,这意味着 可以利用 PostScript/Ghostscript。 在过去的几年里,在 Ghostscript 已经有了一些有趣的利用,它也是唯一支持的(我们可以识别的) 文件格式,允许一些原始脚本与文件或执行命令交互。

使用 Ghostscript 有效载荷,我们能够实现文件读写。

这个有效载荷的代码可以在这里找到:

· https://gist.github.com/ziot/fb96e97baae59e3539ac3cdacbd09430

感谢 Cody Brocious (daeken) 让 Ghostscript 有效载荷正常工作。

关于 LibreOffice 我们了解到的一件事是,尽管 EPFS 文件是由 LibreOffice 处理的,但并不能保证它会导致 Ghostscript。 这是由于 EPFS 解析的层次系统导致的:

pstoedit、convert (ImageMagick的一部分)和GhostScript (gs或gswin32c)在所有平台上都按这个顺序进行了尝试。这是第一个可以用于渲染预览的组件。

更多信息请点击这里:

· https://github.com/LibreOffice/core/blob/master/filter/source/graphicfilter/ieps/ieps.cxx

但是,EPFS只是将postscript传递给其他应用程序,不能保证系统上有一个二进制文件可以处理传递给它的postscript。在这些情况下,你需要找到一个可以进行漏洞利用的替代路径。

Slack, OLE 对象和文本节

通过 LibreOffice 指纹电子表格文件,我们开始检查其他可能以类似方式使用 LibreOffice 的网站。 我们偶然发现 Slack 正在使用 LibreOffice (我共享文件使用的是Slack…)。 我们的 LFI Ghostscript 有效载荷不能正常工作,所以我们必须找到一个与Libre 不同的漏洞利用链。

下面我们将介绍 OLE 对象 xLinks 和文本节的具体细节,我们使用这些细节来读取本地文件内容和捕获 AWS 凭据。

LFD/SSRF——远程 OLE 对象 xLinking

这类似于 =WEBSERVICE LFD/SSRF 漏洞 (CVE-2018-6871)。 在 LibreOffice 文档中,可以在文档中嵌入 OLE 对象。 这也支持在打开文档时进行更新的远程对象。 尽管 LibreOffice 文档包含一些允许这样做的特性,比如浮动帧(iframe 的转换) ,但是在转换为 PDF 文档时,可能无法正常渲染。

Libreoffice 中的 OLE 对象通过获取远程 URL 的内容并显示帧内的内容来工作。 OLE 对象嵌入到 LibreOffice 文件的 content.xml 中。 默认情况下,这些 x-href 链接在转换时不会更新。 实际上,在 OpenOffice/LibreOffice 中,大多数情况下需要在打开文档后手动启用链接更新。 这就把我们带到了广受欢迎的 Universal Office Converter (unconv) 上,稍后将在博客中详细介绍。

只要启用了 x-href 更新,就可以获取任意内容。 这可以通过创建以下 PoC 来看到:

Poc 步骤

1. 在 LibreOffice 中创建一个新的电子表格;

2. 插入->对象 -> OLE 对象-从文件创建;

3. 勾选“链接到文件”复选框;

4. 输入一个实际文件的 url (如果是404,libre 就会失败);

5. 保存 odt 文件;

6. 用 zip 工具打开 odt 文件,如7zip;

7. 修改 content.xml, 使用 “file:///etc/passwd" 替换url。

· * 查找: `

· * 替换为: `

  · Oasis 文件规范

  · LibreOffice/OpenOffice 文件检测和解析

  · PyUNO 桥和 OpenOffice API 调用的实现

  · 无头版本的 LibreOffice 在转换过程使用的公共代码路径中的任何漏洞都可能影响在线 LibreOffice 的使用

  · https://wiki.openoffice.org/wiki/PyUNO_bridge

  · https://github.com/LibreOffice/core/blob/master/pyuno/

本文翻译自:https://buer.haus/2019/10/18/a-tale-of-exploitation-in-spreadsheet-file-conversions/如若转载,请注明原文地址:
  • 分享至
取消

感谢您的支持,我会继续努力的!

扫码支持

打开微信扫一扫后点击右上角即可分享哟

发表评论

 
本站4hou.com,所使用的字体和图片文字等素材部分来源于原作者或互联网共享平台。如使用任何字体和图片文字有侵犯其版权所有方的,嘶吼将配合联系原作者核实,并做出删除处理。
©2022 北京嘶吼文化传媒有限公司 京ICP备16063439号-1 本站由 提供云计算服务