Skip to content
KitploitKITPLOIT
ToolsExploitsBlog
Log in
Einreichen
ToolsExploitsBlog
Einreichen

Hacking-, PenTest- und Cybersicherheits-Tools für Ihr Sicherheitsarsenal!

Kitploit ist ein Verzeichnis von Hacking-, Cybersicherheits- und Pentesting-Tools. Entdecken Sie die neuesten Projekt-Updates, um Schwachstellen zu finden, Systeme zu analysieren, Tests zu automatisieren und Ihre Sicherheit zu stärken.

FeedsKontaktDatenschutz© 2026 Kitploit

Tool-Verzeichnis

Kategorien

Alle Kategorien anzeigen
Loading categories
CVE-2026-31413-BPF-Container-Escape — CVE-2026-31413: BPF-Verifier-Soundness-Bug - Container-Escape | Kitploit
Tools/GitHubGitHub/rat5ak/cve-2026-31413-bpf-container-escape
Privilege EscalationSchwachstellenanalyseExploitationPost-ExploitationPapers & ForschungLernen & BildungContainer-AusbruchBinary-Exploitation

Beliebteste

Alle anzeigen →

Entdecken Sie die meistgenutzten Tools unserer Community.

Alle Tools erkunden

Durchsuchen Sie unsere Tool-Sammlung

Alle Tools anzeigen →
Teilen
GitHub
rat5ak/cve-2026-31413-bpf-container-escape

CVE-2026-31413-BPF-Container-Escape

CVE-2026-31413: BPF-Verifier-Soundness-Bug - Container-Escape

Repository anzeigen
1128vor 6 MonatenNoch nicht geprüft

CVE-2026-31413: Ein Byte im BPF Verifier zum Container-Ausbruch

Ich habe einen Soundness-Bug im Linux BPF-Verifier gefunden – ein + 1 in einem push_stack()-Aufruf, der dazu führt, dass der Verifier eine ALU-Instruktion auf einem verzweigten Pfad überspringt. Für BPF_OR bedeutet dies, dass der Verifier dst = 0 verfolgt, während die CPU 0 | K = K berechnet. Ich schrieb einen vollständigen Container-Ausbruch: OOB-Lesen/Schreiben aus einer BPF-Map, Vtable-Hijacking, Überschreiben von modprobe_path, Root auf dem Host. Dann erstellte ich eine Patch-Serie mit zwei Patches – eine Ein-Zeichen-Fix im Verifier und 90 Zeilen Selftests – und ließ sie in den Mainline-Merge einfließen.

📹 Demo-Video zum Container-Ausbruch

CVECVE-2026-31413
Bug-KlasseVerifier-Soundness – Abweichung des Registerwerts
Ursachepush_stack(env, env->insn_idx + 1, ...) überspringt ALU-Instruktion auf verzweigtem Pfad
Eingeführtbffacdb80b93 - Linux 7.0-rc1 (14. Jan. 2026)
Behobenc845894ebd6f - Linux 7.0-rc5 (22. März 2026)
Betroffen6.12.75+ (stabiler Backport dea9989a3f) bis 7.0-rc4
AuswirkungBeliebiger Kernel-Lese-/Schreibzugriff → Container-Ausbruch → Host-Root
ErforderlichCAP_BPF + CAP_PERFMON + CAP_NET_ADMIN
FixEin Zeichen: insn_idx + 1 → insn_idx

TL;DR

maybe_fork_scalars() verzweigt den Verifier-Zustand, wenn es ARSH + AND/OR mit einer Konstante sieht. Der gepushte Pfad erhält dst = 0 und überspringt die ALU-Instruktion. Für AND ist das in Ordnung: 0 & K = 0. Für OR ist es falsch: 0 | K = K, nicht 0.

Der Verifier denkt, das Register sei Null. Die CPU hat K. Ich nutzte dies, um beliebiges OOB-Lesen/Schreiben aus einem BPF-Map-Wert aufzubauen, leckte die Kernel-Adresse der Map, erstellte eine gefälschte bpf_map_ops-Vtable, leitete map_push_elem über array_map_get_next_key für beliebiges Schreiben um und überschrieb modprobe_path. Ein unbekanntes Binärformat auslösen, der Kernel führt mein Skript als Root aus. In einem Container vollständiger Host-Ausbruch.

Zwei-Patch-Serie: ein Ein-Zeichen-Fix im Verifier plus 90 Zeilen BPF-Selftests, die OR vs. AND-Verzweigung abdecken. Gemerged von Alexei Starovoitov am 22. März. CVE-2026-31413 zugewiesen von Greg Kroah-Hartman am 12. April.


Hintergrund: Der BPF-Verifier

eBPF ermöglicht es Ihnen, kleine Programme in den Kernel zu laden – Paketfilter, Tracing-Hooks, Sicherheitsrichtlinien – ohne ein Kernel-Modul zu kompilieren. Der Haken ist, dass Sie Code in Ring 0 injizieren. Wenn dieser Code einen Fehler hat, ist es ein Kernel-Fehler.

Bevor also ein BPF-Programm ausgeführt wird, simuliert der Verifier des Kernels jeden möglichen Ausführungspfad. Er verfolgt, was jedes Register enthält (ein Zeiger? ein Skalar? welcher Bereich?), überprüft jeden Speicherzugriff auf Map-Grenzen und lehnt alles ab, was außerhalb der Grenzen lesen oder schreiben könnte. Wenn der Verifier ein Programm für sicher erklärt, kompiliert der JIT es in nativen Maschinencode und führt es mit voller Kernel-Berechtigung aus. Es gibt danach keine Laufzeit-Grenzprüfungen mehr. Der Verifier ist die Sicherheitsgrenze.

Aus diesem Grund unterscheiden sich Verifier-Soundness-Fehler von normalen Speicherfehlern. Bei einem Heap-Overflow oder UAF erhalten Sie eine Korruptionsprimitive und müssen von dort aus arbeiten – Heap sprayen, Objekte groomen, ein Zeitfenster ausnutzen. Bei einem Verifier-Fehler bringen Sie den Kernel dazu, eine Lüge über den Wert eines Registers zu glauben. Jede Grenzprüfung, die von diesem Register abhängt, wird bestanden. Der Kernel hat Ihren OOB-Zugriff genehmigt. Er führt ihn ohne Frage aus. Wenn Sie den Registerzustand korrekt abstimmen können, erhalten Sie eine saubere und zuverlässige Primitive daraus.

Wie ich es gefunden habe

Ich auditierte maybe_fork_scalars() – neuer Code, hinzugefügt Januar 2026 in bffacdb80b93. State-Forking ist immer interessant, weil der Verifier dort in parallele Erkundungspfade aufteilt, und wenn ein Pfad einen falschen Wert verfolgt, ist alles stromabwärts dieses Pfades unsound.

Die Funktion verzweigt, wenn sie ARSH + AND/OR mit einer konstanten Quelle sieht. Der gepushte Pfad erhält dst = 0, überspringt die ALU-Instruktion. Ich las die Zeile push_stack(env, env->insn_idx + 1, ...) und es klickte sofort – das + 1 bedeutet, dass der gepushte Pfad die ALU-Operation nie ausführt. Für AND, 0 & K = 0, daher ist das Überspringen in Ordnung. Für OR, 0 | K = K. Der gepushte Pfad denkt, das Ergebnis sei 0, obwohl es tatsächlich K ist.

Ich schrieb noch am selben Abend ein BPF-Programm. ARSH 63, um {0, -1} zu erhalten, OR mit einer Konstante, bedingter Sprung, um die Verifier-Pfade zu trennen, dann Addieren des "Null"-Registers zu einem Map-Zeiger. Der Verifier genehmigte map_value + 0. Die CPU griff auf map_value + K zu. KASAN bestätigte den Out-of-Bounds-Zugriff in Tests.

OOB-Lesen/Schreiben am nächsten Morgen. Container-Ausbruch am nächsten Abend. Ich nutzte durchgehend Claude (Opus 4.5) – zum Durcharbeiten der State-Forking-Logik des Verifiers, zum Brainstorming von Exploitation-Primitives und zum Umwandeln des OOB in eine vollständige Escape-Chain. Der Vtable-Hijack-Ansatz entstand aus einem Hin und Her, bei dem Claude die Funktionszeiger von bpf_map_ops durchging und nach aufrufbaren Gadgets suchte.

Der einführende Commit

Commit bffacdb80b93 ("bpf: Recognize special arithmetic shift in the verifier") wurde am 14. Januar 2026 in 7.0-rc1 aufgenommen. Alexei Starovoitov, gemeinsam entwickelt von Puranjay Mohan. Er fügte maybe_fork_scalars() hinzu, um ein LLVM-DAGCombiner-Muster zu behandeln:``` w2 s>>= 31 // arithmetic shift right: w2 becomes 0 or -1 w2 &= -134 // AND with constant K

LLVM senkt `select_cc setlt X, 0, A, 0` zu `sra + and` ab. Nach der arithmetischen Rechtsverschiebung ist das Register entweder `0` (nicht-negative Eingabe) oder `-1` (alle Einsen). AND mit einer Konstanten ergibt `0` oder `K`.

Der Verifier kann `{0, K}` in einem einzelnen `bpf_reg_state` nicht tracken – sein vorzeichenbehafteter Bereich `[0, K]` überapproximiert, und das führte dazu, dass er gültige Cilium-Programme ablehnte. Die Lösung: Forken des Verifier-Zustands. Ein Pfad untersucht `dst = 0`, der andere `dst = -1`, wobei jeder den genauen Wert verfolgt.

Die Implementierung:```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;
}

Zwei Dinge geschehen auf dem geschobenen Pfad:

  1. Das Zielregister wird auf 0 gesetzt.
  2. Die Ausführung wird bei insn_idx + 1 fortgesetzt – der Anweisung nach der ALU-Operation.

Für BPF_AND: dst = 0, überspringe die AND-Operation. Laufzeit: 0 & K = 0. Übereinstimmung. Korrekt.

Für BPF_OR: dst = 0, überspringe die OR-Operation. Laufzeit: 0 | K = K. Nichtübereinstimmung. Der Verifier sieht 0. Die CPU hat K. Nicht korrekt.

Die Funktion prüft den Opcode nicht. Sie wurde für AND geschrieben – wo das Überspringen der Anweisung das Gleiche ist wie ihre Ausführung mit dst = 0 – und wurde auch auf OR angewendet. Für OR gilt diese Gleichheit nicht.

Auslösen der Divergenz

Tool herunterladen