Skip to content
KitploitKITPLOIT
FerramentasBlog
Log in
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-31413-BPF-Container-Escape — CVE-2026-31413: bug de solidez do verificador BPF - escape de contêiner | Kitploit
Ferramentas/GitHubGitHub/rat5ak/cve-2026-31413-bpf-container-escape
Escalada de PrivilégiosAnálise de VulnerabilidadesExploraçãoPós-ExploraçãoPapers e PesquisaAprendizado e EducaçãoEscape de ContêinerExploração de Binários

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
GitHub
rat5ak/cve-2026-31413-bpf-container-escape

CVE-2026-31413-BPF-Container-Escape

CVE-2026-31413: bug de solidez do verificador BPF - escape de contêiner

Ver Repositório
1116há 5 mesesAinda não revisado

CVE-2026-31413: Um Byte no Verificador BPF para Escape de Contêiner

Encontrei um bug de solidez no verificador BPF do Linux - um + 1 em uma chamada push_stack() que faz o verificador pular uma instrução ALU em um caminho bifurcado. Para BPF_OR, isso significa que o verificador rastreia dst = 0 enquanto a CPU calcula 0 | K = K. Escrevi um escape de contêiner completo: leitura/escrita fora dos limites (OOB) a partir de um mapa BPF, sequestro de vtable, sobrescrita de modprobe_path, root no host. Em seguida, criei uma série de dois patches - uma correção de um caractere no verificador e 90 linhas de selftests - e consegui mesclá-la no mainline.

📹 Vídeo de demonstração do escape de contêiner

CVECVE-2026-31413
Classe do bugSolidez do verificador - divergência de valor de registrador
Causa raizpush_stack(env, env->insn_idx + 1, ...) pula instrução ALU no caminho bifurcado
Introduzidobffacdb80b93 - Linux 7.0-rc1 (Jan 14, 2026)
Corrigidoc845894ebd6f - Linux 7.0-rc5 (Mar 22, 2026)
Afetado6.12.75+ (backport estável dea9989a3f) até 7.0-rc4
ImpactoR/W arbitrário no kernel → escape de contêiner → root no host
RequeridoCAP_BPF + CAP_PERFMON + CAP_NET_ADMIN
CorreçãoUm caractere: insn_idx + 1 → insn_idx

Resumo

maybe_fork_scalars() bifurca o estado do verificador quando vê ARSH + AND/OR com uma constante. O caminho empurrado recebe dst = 0 e pula a instrução ALU. Para AND isso é válido: 0 & K = 0. Para OR está errado: 0 | K = K, não 0.

O verificador pensa que o registrador é zero. A CPU tem K. Usei isso para construir leitura/escrita OOB arbitrária a partir de um valor de mapa BPF, vazei o endereço de kernel do mapa, construí uma vtable bpf_map_ops falsa, redirecionei map_push_elem através de array_map_get_next_key para escrita arbitrária e sobrescrevi modprobe_path. Ao disparar um formato binário desconhecido, o kernel executa meu script como root. Em um contêiner, escape completo do host.

Série de dois patches: uma correção de um caractere no verificador mais 90 linhas de selftests BPF cobrindo OR vs bifurcação AND. Mesclada por Alexei Starovoitov em 22 de março. CVE-2026-31413 atribuída por Greg Kroah-Hartman em 12 de abril.


Contexto: O Verificador BPF

eBPF permite carregar pequenos programas no kernel - filtros de pacotes, hooks de rastreamento, políticas de segurança - sem compilar um módulo de kernel. O problema é que você está injetando código no ring 0. Se esse código tiver um bug, é um bug do kernel.

Então, antes de qualquer programa BPF executar, o verificador do kernel simula todos os possíveis caminhos de execução. Ele rastreia o que cada registrador contém (um ponteiro? um escalar? qual intervalo?), verifica cada acesso à memória em relação aos limites do mapa e rejeita qualquer coisa que possa ler ou escrever fora dos limites. Se o verificador diz que um programa é seguro, o JIT o compila para código de máquina nativo e o executa com privilégio total de kernel. Não há verificações de limites em tempo de execução depois desse ponto. O verificador é o limite de segurança.

É por isso que bugs de solidez do verificador são diferentes de corrupção de memória normal. Com um heap overflow ou UAF, você obtém uma primitiva de corrupção e precisa trabalhar a partir dela - fazer spray no heap, preparar objetos, disputar uma janela. Com um bug de verificador, você faz o kernel acreditar em uma mentira sobre o valor de um registrador. Toda verificação de limites que depende desse registrador passa. O kernel aprovou seu acesso OOB. Ele o executa sem questionar. Se você conseguir alinhar o estado do registrador corretamente, obtém uma primitiva limpa e confiável a partir disso.

Como Encontrei

Eu estava auditando maybe_fork_scalars() - código novo, adicionado em janeiro de 2026 em bffacdb80b93. A bifurcação de estado é sempre interessante porque é onde o verificador se divide em caminhos de exploração paralelos, e se qualquer caminho rastreia um valor incorreto, tudo a jusante desse caminho fica não sólido.

A função bifurca quando vê ARSH + AND/OR com uma fonte constante. O caminho empurrado recebe dst = 0 e pula a instrução ALU. Eu estava lendo a linha push_stack(env, env->insn_idx + 1, ...) e caiu a ficha na hora - o + 1 significa que o caminho empurrado nunca executa a operação ALU. Para AND, 0 & K = 0, então pular é válido. Para OR, 0 | K = K. O caminho empurrado pensa que o resultado é 0 quando na verdade é K.

Escrevi um programa BPF naquela noite. ARSH 63 para obter {0, -1}, OR com uma constante, desvio condicional para separar os caminhos do verificador, e então adicionei o registrador "zero" a um ponteiro de mapa. O verificador aprovou map_value + 0. A CPU acessou map_value + K. O KASAN confirmou o acesso fora dos limites nos testes.

Leitura/escrita OOB na manhã seguinte. Escape de contêiner na noite seguinte. Usei Claude (Opus 4.5) durante todo o processo - para analisar a lógica de bifurcação de estado do verificador, gerar ideias de primitivas de exploração e transformar o OOB em uma cadeia completa de escape. A abordagem de sequestro de vtable surgiu de uma troca em que Claude percorreu os ponteiros de função de bpf_map_ops procurando gadgets chamáveis.

O Commit que Introduziu o Bug

O commit bffacdb80b93 ("bpf: Recognize special arithmetic shift in the verifier") foi incorporado em 14 de janeiro de 2026 no 7.0-rc1. Alexei Starovoitov, co-desenvolvido por Puranjay Mohan. Ele adicionou maybe_fork_scalars() para lidar com um padrão do DAGCombiner do LLVM:``` w2 s>>= 31 // arithmetic shift right: w2 becomes 0 or -1 w2 &= -134 // AND with constant K

LLVM converte `select_cc setlt X, 0, A, 0` em `sra + and`. Após o deslocamento
aritmético para a direita, o registrador é ou `0` (entrada não negativa) ou `-1` (todos os bits em 1).
O AND com uma constante resulta em `0` ou `K`.

O verificador não consegue rastrear `{0, K}` em um único `bpf_reg_state` — seu intervalo com sinal
`[0, K]` é uma superaproximação, e isso estava fazendo com que ele rejeitasse programas Cilium
válidos. A correção: bifurcar o estado do verificador. Um caminho explora `dst = 0`, o
outro `dst = -1`, cada um rastreando o valor preciso.

A implementação:```c
static int maybe_fork_scalars(struct bpf_verifier_env *env,
                              struct bpf_insn *insn,
                              struct bpf_reg_state *dst_reg)
{
    // ... condition check: dst range is [-1, 0], src is constant ...

    branch = push_stack(env, env->insn_idx + 1, env->insn_idx, false);
    //                             ^^^^^^^^^^^^
    //                    pushed path resumes AFTER the ALU insn
    if (IS_ERR(branch))
        return PTR_ERR(branch);

    regs = branch->frame[branch->curframe]->regs;
    __mark_reg_known(&regs[insn->dst_reg], 0);   // pushed: dst = 0
    __mark_reg_known(dst_reg, -1ull);             // current: dst = -1
    return 0;
}

Duas coisas acontecem no caminho empurrado:

  1. O registrador de destino é definido para 0
  2. A execução é retomada em insn_idx + 1 - a instrução após a operação ALU

Para BPF_AND: dst = 0, pula a operação AND. Em tempo de execução: 0 & K = 0. Correspondência. Sólido.

Para BPF_OR: dst = 0, pula a operação OR. Em tempo de execução: 0 | K = K. Divergência. O verificador vê 0. A CPU tem K. Não sólido.

A função não verifica o opcode. Ela foi escrita para AND - onde pular a instrução é o mesmo que executá-la com dst = 0 - e foi aplicada também a OR. Para OR, essa equivalência não se sustenta.

Acionando a Divergência

Baixar ferramenta