研究人员:
· Cody Brocious (Daeken) 科迪 · 布罗斯(戴肯)
· 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 文件上传。 (更多内容见下文)
这是一个有用的标识符,原因如下。 =INFO("osversion")函数对于 OpenOffice/LibreOffice 具有硬编码值。 OpenOffice 和旧版本的 Libre 返回了一个 INFO 函数的错误,2015年后它不支持 LibreOffice ,并将显示“#N/A”。 这些细微差别为创建一个 XLSX 文件提供了机会,该文件可用于更好地了解服务器上处理电子表格的内容。
下面是我们最终使用的指纹:
其中 c4单元格为 =INFO("DIRECTORY")
对 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
结果如下:
一个常见的文件扩展名陷阱
在我们最初的测试中,我们观察到一个网站只会渲染扩展名为.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/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/如若转载,请注明原文地址: