// HackTheBox

Analytics

Metabase Pre-Auth-RCE (CVE-2023-38646) über H2-JDBC-Injection → aus Umgebungsvariablen geleakte SSH-Zugangsdaten → GameOver(lay) Kernel-Rechteausweitung

HackTheBoxLeichtLinux 20. Juli 2026 4 Min. Lesezeit

Aufklärung

Zwei Ports, und die ganze Box hängt daran, was der Webserver wirklich ausliefert:

Port Service Version
22 SSH OpenSSH 8.9p1 Ubuntu 3ubuntu0.4
80 HTTP nginx 1.18.0; redirects → analytical.htb (static landing)

Port 80 liefert für die reine IP keinen Inhalt aus — er leitet auf den vhost analytical.htb um, also wandert dieser Name in /etc/hosts. analytical.htb selbst ist nur eine statische Marketing-Landingpage, aber das Durchsuchen ihrer Links fördert einen zweiten vhost zutage, data.analytical.htb, der neben dem ersten in /etc/hosts eingetragen wird. Diese Subdomain antwortet mit Metabase, einem quelloffenen Business-Intelligence-Dashboard. Eine selbst gehostete Analytics-App auf einer eigenen Subdomain ist genau die Art von fettem, versioniertem Ziel, das man zuerst fingerprinten sollte — das ist also der Faden, an dem man zieht.

Erstzugang — CVE-2023-38646

1. Metabase fingerprinten und das Setup-Token leaken

Metabase stellt einen nicht authentifizierten Settings-Endpoint bereit, /api/session/properties, der seine öffentliche Konfiguration als JSON ausgibt — einschließlich der laufenden Version und, auf einer nie vollständig initialisierten Box, des einmaligen Setup-Tokens, das den Erstkonfigurations-Assistenten absichert:

$ curl -s http://data.analytical.htb/api/session/properties

Zwei Fakten fallen aus dieser Antwort:

  • Version v0.46.6 (veröffentlicht 2023-06-29).
  • setup-token 249fa03d-fd94-4d5b-b94f-b4ebf3df681f — das Token ist nicht null, was bedeutet, dass der Erstkonfigurations-Flow nie abgeschlossen wurde und noch offen ist.

Beides ist entscheidend für CVE-2023-38646, eine Pre-Authentication-RCE in Metabase. Sie wurde in 0.46.6.1 behoben; 0.46.6 liegt genau im verwundbaren Bereich, und ein aktives Setup-Token ist exakt die Voraussetzung, die der Exploit benötigt.

2. Pre-Auth-RCE über H2-JDBC-Injection

Metabase bringt für die eigenen Beispieldaten eine eingebettete H2-Datenbank mit (eine reine Java-SQL-Engine). Der Setup-Assistent erlaubt es, Metabase über einen JDBC-Verbindungsstring auf eine Datenbank zeigen zu lassen, und POST /api/setup/validate „testet” diese Verbindung, bevor ein Konto existiert — wobei das geleakte Setup-Token die einzige Berechtigung ist. Der JDBC-Treiber von H2 erlaubt es einem Verbindungsstring, einen SQL-Trigger in JavaScript zu definieren, und dieser Trigger-Code läuft serverseitig, sobald die Verbindung geöffnet wird. Ein präparierter Verbindungsstring verwandelt somit „validiere meine Datenbankeinstellungen” in „führe meinen Code aus”: CREATE TRIGGER ... AS '//javascript ...' → Kommandoausführung als der Metabase-Prozess.

Der öffentliche Exploit metabase_rce.py automatisiert dies gegen POST /api/setup/validate. Über zwei Implementierungsdetails stolpert man leicht:

  • Das vollständige details-Objekt ist erforderlich. Das äußere details-Feld des Requests muss jeden vom Endpoint erwarteten Geschwister-Schlüssel tragen — is_on_demand, is_full_sync, is_sample, cache_ttl, refingerprint, auto_run_queries, schedules. Lässt man einen weg, weist der Server den gesamten Request mit 400 {"message":"Vector arg to map conj must be a pair"} ab, bevor er überhaupt den verwundbaren Code erreicht.
  • Der Payload ist Base64, mit Leerzeichen aufgefüllt. Das Reverse-Shell-Kommando wird Base64-kodiert und mit Leerzeichen aufgefüllt, damit es nie auf ein =-Zeichen endet — ein = würde den H2-Verbindungsstring vorzeitig beenden und die Injection brechen.

Der Trigger ist so verdrahtet, dass er feuert, wenn Metabase während der Validierung sein eigenes SELECT gegen INFORMATION_SCHEMA.TABLES ausführt. Der HTTP-Request kommt als 400-SQL-Syntaxfehler zurück, aber das ist kosmetisch — das JavaScript des Triggers wurde zu diesem Zeitpunkt bereits ausgeführt. Das Ergebnis ist eine Reverse-Shell als uid=2000(metabase) innerhalb des Containers 71c5ea8a011e.

Lateral — aus Umgebungsvariablen geleakte SSH-Zugangsdaten

Die Shell landet in einem Container, nicht auf dem Host, also lautet die nächste Frage, was der Container weiß, das der Host wiederverwendet. Metabase wird über Umgebungsvariablen konfiguriert, und seine eigene Prozessumgebung gibt einen Satz Zugangsdaten preis:

META_USER=metalytics
META_PASS=An4lytics_ds20223#

Die Variablennamen sehen Metabase-spezifisch aus, aber die Werte werden als Host-SSH-Zugangsdaten wiederverwendet — der klassische Password-Reuse-Pivot aus einem Container heraus auf die Box, auf der er läuft. Sie funktionieren direkt über SSH und liefern eine echte Session als uid=1000(metalytics) samt user.txt:

$ ssh metalytics@10.129.229.224

Rechteausweitung — GameOver(lay)

Auf dem Host meldet uname -a Ubuntu 22.04.3 auf Kernel 6.2.0-25-generic. Dieser Kernel ist anfällig für GameOver(lay) (CVE-2023-2640 / CVE-2023-3262), einen Fehler in Ubuntus OverlayFS, bei dem Datei-Capabilities, die auf einer Datei in einem unprivilegierten User-Namespace gesetzt werden, auf das echte Dateisystem übernommen werden — wodurch ein unprivilegierter Benutzer privilegierte Capabilities auf eine ausführbare Datei stempeln kann.

Der Standard-Einzeiler unshare -rm nutzt dies aus: einen neuen User- und Mount-Namespace erzeugen, einen OverlayFS-Mount aufbauen und die Capability cap_setuid auf eine Kopie des ruby-Binaries setzen. Da die Capability den Copy-up auf das Host-Dateisystem übersteht, kann dieses ruby anschließend Process::Sys.setuid(0) aufrufen, um root zu werden:

$ ruby -e 'Process::Sys.setuid(0); exec "/bin/bash"'

Das liefert eine root-Shell zurück — /root/root.txt lesen, um die Box abzuschließen.

← Alle Writeups