Skip to content
KitploitKITPLOIT
FerramentasBlog
Enviar
FerramentasBlog
Enviar

Ferramentas de Hacking, PenTest e Cibersegurança para o seu Arsenal de Segurança!

Kitploit é um diretório de ferramentas de hacking, cibersegurança e pentesting. Descubra as últimas atualizações de projetos para encontrar vulnerabilidades, analisar sistemas, automatizar testes e fortalecer sua segurança.

··Feeds·Contato·Privacidade·© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
CVE-2026-18963 — Laboratório baseado em Docker e exploit em Python para CVE-2026-18963, um bypass do fluxo de redefinição de credenciais do Keycloak que permite a tomada de conta por meio do bypass de verificação de e-mail. | Kitploit
Ferramentas/GitHubGitHub/ivanesk315/cve-2026-18963
Análise de VulnerabilidadesExploraçãoExploração de Aplicações WebSegurança WebTestes de PenetraçãoGerenciamento de Identidade e Acesso (IAM)AutenticaçãoAprendizado e EducaçãoLabs e Prática
GitHubivanesk315/cve-2026-18963

CVE-2026-18963

Laboratório baseado em Docker e exploit em Python para CVE-2026-18963, um bypass do fluxo de redefinição de credenciais do Keycloak que permite a tomada de conta por meio do bypass de verificação de e-mail.

há 0 diasAinda não revisado
Ver Repositório

Mais Populares

Ver todos →

Descubra as ferramentas mais usadas pela nossa comunidade.

Explore todas as ferramentas

Navegue pela nossa coleção de ferramentas

Ver todas as ferramentas →
Compartilhar

CVE-2026-18963 — Laboratório de Bypass do Fluxo Reset-Credentials do Keycloak

Visão geral

Laboratório que simula a vulnerabilidade CVE-2026-18963 (CVSS 9.1) no Keycloak, permitindo que um atacante assuma o controle de qualquer conta por meio de bypass de verificação de email no fluxo de redefinição de senha.

Apenas para fins de pesquisa de segurança e educação.

Requisitos

  • Docker & Docker Compose
  • Python 3.8+
  • pip

Instruções de uso

1. Iniciar o Keycloak vulnerável

root@kitploit:~
docker-compose up -d

Aguarde o Keycloak iniciar (~30-60 segundos).

2. Configurar o laboratório

root@kitploit:~
pip install -r requirements.txt
python setup-lab.py

O script irá criar:

  • Realm vuln-lab com reset-password habilitado
  • Configuração SMTP (MailHog) para envio de emails
  • Usuário victim ([email protected] / VictimPass123!)

3. Executar o exploit

root@kitploit:~
python exploit.py -u http://127.0.0.1:8080 -r vuln-lab -t victim -p Pwned123!

Opções:

  • -u / --url: URL do Keycloak (padrão: http://127.0.0.1:8080)
  • -r / --realm: Nome do realm (padrão: vuln-lab)
  • -t / --target: Nome de usuário alvo (padrão: victim)
  • -p / --password: Nova senha (padrão: Pwned123!)
  • -v / --verbose: Ativar saída de debug

4. Visualizar emails (opcional)

MailHog UI: http://127.0.0.1:8025 — visualize os emails de reset-password enviados durante o exploit.

5. Limpeza

root@kitploit:~
docker-compose down -v

Detalhes técnicos

Causa raiz

Dois bugs combinados no Keycloak formam a cadeia de ataque:

Bug 1 — Corrupção de estado do seletor (DefaultAuthenticationFlow.java): Quando o usuário clica em "Try Another Way", a auth note AUTHENTICATION_SELECTOR_SCREEN_DISPLAYED é armazenada como "true" (string booleana) em vez do ID do modelo de execução. O valor "true" não está vinculado a nenhuma execução específica, então ele persiste ao longo das etapas do fluxo, fazendo com que o seletor seja exibido em contexto incorreto.

Bug 2 — Sucesso de ação incondicional (ResetCredentialEmail.java): O método action() de ResetCredentialEmail chama context.success() incondicionalmente sem verificar o action token. Normalmente, action() só é chamado quando o usuário clica no link do email (que contém o action token). Mas quando o seletor está corrompido, o atacante pode acionar action() diretamente por meio do processamento do fluxo.

Fluxo de ataque detalhado

root@kitploit:~
Attacker                              Keycloak
   │                                     │
   │─── GET /auth (OIDC + PKCE) ────────>│  1. Inicializa sessão de auth
   │<── Login page + cookies ────────────│
   │                                     │
   │─── GET /reset-credentials ─────────>│  2. Redireciona para o fluxo de reset
   │<── Username form ──────────────────│
   │                                     │
   │─── POST tryAnotherWay=on ─────────>│  3. Corrompe o estado do seletor
   │<── Authenticator selector ─────────│     SELECTOR_DISPLAYED = "true"
   │                                     │
   │─── POST username=victim ──────────>│  4. Envia username pelo seletor
   │<── "Check your email" page ────────│     Email enviado, CURRENT_EXEC = email_id
   │                                     │
   │─── GET /reset-credentials ────────>│  5. Reentra no fluxo de reset
   │<── Corrupted selector (!!!) ───────│     processFlow() vê SELECTOR="true"
   │                                     │     → exibe o seletor para a etapa de email
   │                                     │
   │─── POST {} (empty body) ──────────>│  6. BYPASS: aciona action()
   │<── 302 → UPDATE_PASSWORD ─────────│     processAction() não encontra
   │                                     │     authenticationExecution no form
   │─── GET /required-action ──────────>│     → cai no ramo action()
   │<── Password update form ──────────│     ResetCredentialEmail.action()
   │                                     │     → context.success() (incondicional!)
   │                                     │     → fluxo muda para ResetPassword
   │                                     │
   │─── POST password-new=Pwned! ──────>│  7. Define a nova senha
   │<── 302 → /account/ ──────────────│     Account takeover concluído
   │                                     │
   └── Login com a nova senha ──────────┘

Por que o passo 6 funciona?

Em DefaultAuthenticationFlow.processAction(), ao receber o POST:

  1. Verifica tryAnotherWay no form → NÃO (form vazio)
  2. Verifica authenticationExecution no form → NÃO (form vazio)
  3. Cai no ramo final: chama authenticator.action(result) no model da URL

Como a URL contém execution=<email_exec_id> (do action do form do seletor), então ResetCredentialEmail.action() é chamado → retorna context.success() → o fluxo muda para ResetPassword → exibe o form de definição de senha.

Versões afetadas

ProdutoAfetadoCorrigido
Keycloak (upstream)< 26.7.226.7.2+
RHBK 26.4.x< 26.4.1526.4.15+
RHBK 26.6.x< 26.6.626.6.6+

Correção (PR #51844)

DefaultAuthenticationFlow.java:

  • setAuthNote(SELECTOR_DISPLAYED, "true") → setAuthNote(SELECTOR_DISPLAYED, model.getId())
  • processFlow() verifica selector.equals(lastExecutionId) em vez de Boolean.parseBoolean()
  • Se não corresponder → removeAuthNote(SELECTOR_DISPLAYED)

ResetCredentialEmail.java:

  • action() verifica ACTION_TOKEN_USER_ID antes de chamar context.success()
  • Se não houver action token válido → context.failure(INVALID_USER)

Referências

  • NVD - CVE-2026-18963
  • Red Hat CVE Page
  • Keycloak Issue #51833
  • Fix PR #51844
  • Kudelski Security Research
  • The Hacker News
Baixar ferramenta