
Schritt-für-Schritt-Exploit-Writeup für CVE-2017-11610 (Supervisord XML-RPC RCE) mit Angriffsflächenanalyse, Entdeckung von Namespace-Traversal und Post-Exploitation-Techniken in einer Docker-Lab-Umgebung.
Beginnend mit dem, was in der Umgebung läuft. Ich liste alle aktiven Container auf:``` docker ps-a

**Das Opfer setzt einen einzelnen Port frei: `9001`**.
Port 9001 ist keine Standard-Webanwendung. Ein Blick in die **Port-Datenbank** zeigt, dass dieser Port mit **Supervisord** (laut IANA ETL Service Manager), Tor-Proxy oder einem anderen internen Dienst verbunden sein könnte. Allerdings können wir nicht allein anhand der Portnummer eine Schlussfolgerung ziehen.
⇒ Ich verwende curl direkt, um die Antwort zu lesen, und greife auch auf die Web-GUI zu, um weitere Informationen zu sammeln.```
curl -i http://192.168.3.137:9001/


Analyse der Antwort:
Server: Medusa/1.12 und den Titel Supervisor Status→ Damit ist bestätigt, dass es sich um Supervisord handelt, nicht um Tor oder einen anderen Dienst.
REFRESH, RESTART ALL, STOP ALLSupervisord ist ein Prozessmanager unter Linux. Wenn port 9001 ohne Passwort im Netzwerk exponiert ist, handelt es sich um eine gefährliche Konfiguration. Ein Angreifer könnte Dienste einsehen, Prozesse neu starten/stoppen und unter bestimmten Konfigurationen ausnutzen, um Befehle auszuführen, sofern er Privilegien besitzt, die verwalteten Programme zu ändern oder zu steuern.
Analyseergebnis: Wir können bestätigen, dass das Ziel die Supervisord-Verwaltungsoberfläche auf Port 9001 im Netzwerk exponiert. Dies ist kein Standard-Webdienst, sondern eine Verwaltungsschnittstelle, die dazu dient, Prozesse zu überwachen und zu steuern. Die Möglichkeit, auf diese Schnittstelle zuzugreifen, ohne Authentifizierung stellt ein Risiko dar, dass ein Angreifer den Status der verwalteten Dienste einsehen oder mit ihnen interagieren kann.
Wir müssen jedoch zwischen der sichtbaren Benutzeroberfläche und dem zugrunde liegenden Steuerungsmechanismus unterscheiden. Schaltflächen wie REFRESH, RESTART ALL und STOP ALL verarbeiten Anfragen nicht unabhängig im Frontend; stattdessen müssen sie eine Schnittstelle/ein Backend von Supervisord aufrufen, um Status abzurufen oder Prozesssteuerungsbefehle zu senden. Nachdem die offengelegte Weboberfläche bestätigt wurde, besteht der nächste Analyseschritt daher darin, festzustellen, ob die zugrunde liegende Steuerungsschnittstelle hinter der Weboberfläche existiert und ob sie eine Authentifizierung erfordert.
⇒ Denkweise: Es muss geprüft werden, ob die Steuerungsschnittstelle hinter der Weboberfläche existiert und ob sie eine Authentifizierung erfordert.

Laut Supervisor-Dokumentation ist [inet_http_server] ein HTTP-Server, der auf einem TCP-Socket lauscht. Diese Schnittstelle ist standardmäßig nicht aktiviert, sollte nur in vertrauenswürdigen Umgebungen verwendet werden, unterstützt keine Verschlüsselung und besitzt keine Standard-Authentifizierung, sofern kein username/password konfiguriert ist.
Die Dokumentation weist außerdem darauf hin, dass der Port von [inet_http_server] verwendet wird, um HTTP/XML-RPC-Anfragen zu empfangen; supervisorctl verwendet XML-RPC, um über diesen Port mit supervisord zu kommunizieren. Dies deckt sich mit unserer Beobachtung im Labor: Der Container exponiert 0.0.0.0:9001->9001/tcp, die Weboberfläche ist ohne Authentifizierung erreichbar, und die angezeigte Version ist Supervisor 3.3.2.
Nach der Bestätigung der Weboberfläche auf Port 9001 besteht der nächste Schritt also darin, den XML-RPC-Endpunkt /RPC2 zu untersuchen. Basierend auf dem offiziellen Mechanismus von Supervisord müssen wir folgende Ziele verifizieren:
/RPC2 existiert.supervisor.getState oder system.listMethods aufrufen können.Prüfen, ob der Endpunkt erreichbar ist:```
curl -i -s -X POST -H "Content-Type: text/xml"
-d 'supervisor.getState'
http://192.168.3.137:9001/RPC2

Das Ergebnis liefert `HTTP/1.1 200 OK`, nicht `401 Unauthorized` oder `403 Forbidden`, was zeigt, dass die Anfrage vom Server ohne Anmeldedaten akzeptiert wurde. Die Antwort liegt im XML-RPC-Format `<methodResponse>` vor und enthält `statename=RUNNING` und `statecode=1`, was beweist, dass der `/RPC2`-Endpunkt aktiv ist und die Methode `supervisor.getState` erfolgreich ausgeführt wurde.
**⇒ Denkweise:** Die Angriffsfläche ist nicht mehr auf die Web-UI beschränkt, sondern hat sich auf die XML-RPC-API ausgeweitet, über die Befehle zur Daemon-/Prozesssteuerung abgewickelt werden. Von hier aus ist die nächste Analyse-Richtung, zu **prüfen, wie Supervisor** `methodName` in **XML-RPC** verarbeitet, um festzustellen, ob das aktuelle Ziel **das Verhalten von CVE-2017-11610** aufweist, das im Dispatch-/Lookup-Mechanismus dieser Methode liegt. Wir müssen dies verifizieren, um zu dem Schluss zu kommen, ob es sich um **CVE-2017-11610** handelt.
### **Analyse der Verarbeitung von Methodennamen in XML-RPC**
Im vorherigen Schritt haben wir die Methode `supervisor.getState` erfolgreich über den `/RPC2`-Endpunkt aufgerufen. Dies wirft die nächste Frage auf: Wie bildet Supervisord beim Empfang eines stringbasierten `methodName` diese Zeichenkette auf die interne Python-Funktion ab?
In XML-RPC verwenden Methoden typischerweise Namespaces, zum Beispiel:
- `supervisor.getState`
- `supervisor.stopProcess`
- `supervisor.getAllProcessInfo`
Logischerweise empfängt der Server die `methodName`-Zeichenkette, teilt sie am Punkt `.` auf und sucht das entsprechende Objekt/die entsprechende Funktion innerhalb des registrierten Handlers.
Der Pseudocode kann wie folgt verstanden werden:```python
# Pseudo-code simulating the dispatch method concept in XML-RPC
def dispatch(method_name, params):
parts = method_name.split(".") # ["supervisor", "getState"]
obj = registered_handlers[parts[0]] # get namespace "supervisor"
for attr in parts[1:]:
obj = getattr(obj, attr) # lookup the next attribute
return obj(*params) # call the final function
Für Standardmethoden wie supervisor.getState funktioniert dieser Mechanismus normal: Der Server ruft den supervisor-Handler ab und ruft dann die Funktion getState auf. Das Kernproblem von CVE-2017-11610 ist jedoch, dass dieser Nachschlagemechanismus die Attribute, auf die zugegriffen werden darf, nicht ausreichend einschränkt. Wenn ein Angreifer den methodName kontrolliert, kann er nicht nur öffentliche Methoden wie getState aufrufen, sondern auch tiefer in die internen Objekte/Module eindringen, die vom supervisor-Handler aus erreichbar sind.