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.

··Feeds·Kontakt·Datenschutz·© 2026 Kitploit

Tool-Verzeichnis

Kategorien

Alle Kategorien anzeigen
Loading categories
TEST-CVE-2023-32233 — CVE-2023-32233 | Kitploit
Tools/GitHubGitHub/rogeliopumajulca/test-cve-2023-32233
SpeicherforensikSchwachstellenanalyseExploitationLernen & BildungBinary-Exploitation
GitHubrogeliopumajulca/test-cve-2023-32233

TEST-CVE-2023-32233

CVE-2023-32233

Repository anzeigen
14vor 2 JahrenNoch nicht geprüft

Beliebteste

Alle anzeigen →

Entdecken Sie die meistgenutzten Tools unserer Community.

Alle Tools erkunden

Durchsuchen Sie unsere Tool-Sammlung

Alle Tools anzeigen →
Teilen

Use-After-Free in Netfilter nf_tables bei der Verarbeitung von Batch-Anfragen

Details zur Sicherheitslücke

Der betroffene Code stammt vom offiziellen Linux-Kernel von https://kernel.org/ und ist Teil der Netfilter nf_tables-Komponente (net/netfilter/nf_tables_api.c).

Netfilter nf_tables erlaubt es, seine Konfiguration als atomare Operation zu aktualisieren. Bei Verwendung dieser Funktion senden die Benutzermodus-Clients Batch-Anfragen, die eine Liste von Basisoperationen enthalten. Netfilter nf_tables verarbeitet dann alle Operationen innerhalb des Batches als einzelne Transaktion. Bei der Verarbeitung des Batches prüft Netfilter nf_tables die Konfigurationszustandsänderungen, um sicherzustellen, dass jede aufeinanderfolgende Basisoperation gültig ist, und dies berücksichtigt auch die Zustandsänderungen aller vorherigen Operationen innerhalb des Batches. Allerdings ist die derzeit implementierte Prüfung unzureichend.

In unserem spezifischen Szenario starten wir mit einer Netfilter nf_tables-Konfiguration, die eine nft_rule mit lookup-Ausdruck auf einem anonymen nft_set hat, und wobei das anonyme nft_set einige Elemente enthält. Als nächstes senden wir eine Batch-Anfrage, die die folgenden zwei Basisoperationen enthält:

  1. NFT_MSG_DELRULE-Operation zum Löschen der nft_rule.
    Beachten Sie, dass dies auch implizit den lookup-Ausdruck und das anonyme nft_set löscht.
  2. NFT_MSG_DELSETELEM-Operation zum Löschen eines der Elemente des gelöschten anonymen nft_set.

Die aktuelle Version von Netfilter nf_tables akzeptiert die obige Batch-Anfrage. Sie ruft dann nf_tables_commit_release() auf, das freigegebene Ressourcen an nf_tables_destroy_list anhängt. Die nf_tables_destroy_list wird dann von nf_tables_trans_destroy_work() verarbeitet, das zunächst Ressourcen freigibt, die mit der NFT_MSG_DELRULE-Operation zusammenhängen, indem es aufruft:

nft_commit_release()
    nf_tables_rule_destroy()
        nf_tables_expr_destroy()
            expr->ops->destroy() zeigt auf nft_lookup_destroy()
                nf_tables_destroy_set()
                    nft_set_destroy()
                        kvfree() gibt den von `nft_set` verwendeten Speicher frei

bevor die NFT_MSG_DELSETELEM-Operation verarbeitet wird, bei der eine Referenz auf das freigegebene nft_set über nft_trans_elem_set() während der folgenden Aufrufe zugegriffen wird:

nft_commit_release()
    nf_tables_set_elem_destroy()
        nft_set_elem_ext()

Innerhalb von nft_set_elem_ext() oben wird auf die Speicherstelle des freigegebenen nft_set zugegriffen, um die Position von nft_set_ext zu bestimmen:

static inline struct nft_set_ext *nft_set_elem_ext(const struct nft_set *set,
                                                   void *elem)
{
        return elem + set->ops->elemsize;
}

für die folgenden Operationen. Sobald also der Wert von set->ops->elemsize korrumpiert wird, könnte eine bestimmte unerwartete Speicherstelle als Liste von zu zerstörenden nft_expr interpretiert werden:

static void nf_tables_set_elem_destroy(const struct nft_ctx *ctx,
                                       const struct nft_set *set, void *elem)
{
        struct nft_set_ext *ext = nft_set_elem_ext(set, elem);

        if (nft_set_ext_exists(ext, NFT_SET_EXT_EXPRESSIONS))
                nft_set_elem_expr_destroy(ctx, nft_set_ext_expr(ext));

Ausbeutungstechniken

Die Ausnutzung der obigen Schwachstelle erfordert, ein Rennen mit nf_tables_trans_destroy_work() zu gewinnen, das im Hintergrund-Worker-Thread des Linux-Kernels ausgeführt wird. Dies scheint die praktische Ausnutzung selbst dann zu erschweren, wenn wir bestehende Schutzmaßnahmen berücksichtigen, wie die Härtung des Kernel-Slab-Allokators, Kernel Address Space Layout Randomization (KASLR) und insbesondere Control-Flow Integrity. Der beigefügte PoC beweist jedoch, dass es dennoch möglich ist, eine einigermaßen zuverlässige Ausnutzung in der Praxis zu erreichen.

Um die Schwachstelle auszunutzen, müssen wir den Inhalt des Speichers von nft_set ändern, nachdem es unter nf_tables_rule_destroy() freigegeben wurde, aber bevor es unter nf_tables_set_elem_destroy() verwendet wird. Beide nf_tables_rule_destroy() und nf_tables_set_elem_destroy() werden innerhalb eines einzelnen Aufrufs von nf_tables_trans_destroy_work() aufgerufen, das im Hintergrund-Worker-Thread des Linux-Kernels ausgeführt wird. Darüber hinaus ist der freigegebene Speicherblock normalerweise nur vom selben CPU-Kern aus zur Wiederverwendung verfügbar.

Wenn wir mit nf_tables_trans_destroy_work() um die Wette laufen, verbessern wir unsere Chancen, indem wir eine kontrollierte Verzögerung für den Hintergrund-Worker-Thread zwischen seinen Aufrufen nf_tables_rule_destroy() und nf_tables_set_elem_destroy() hinzufügen. Dazu fügen wir eine zusätzliche Operation ein, um ein weiteres nft_set mit einer großen Anzahl von Elementen zu zerstören. Zusätzlich halten wir alle anderen CPU-Kerne beschäftigt, sodass der Hintergrund-Worker-Thread wahrscheinlich auf einem bestimmten CPU-Kern geplant wird, sodass wir versuchen können, eine neue Struktur vom selben CPU-Kern zu allozieren, direkt nachdem er nft_set unter nf_tables_rule_destroy() freigegeben hat. Unser Ziel ist es, ein neues nft_set eines anderen Typs zu allozieren, um die Speicherstelle des unter nf_tables_rule_destroy() freigegebenen nft_set wiederzuverwenden.

Der neue nft_set-Typ wird so gewählt, dass er einen anderen Wert für set->ops->elemsize verwendet. Wenn der Hintergrund-Worker-Thread schließlich nf_tables_set_elem_destroy() aufruft, um die NFT_MSG_DELSETELEM-Operation zu verarbeiten, interpretiert er sein elem-Argument falsch, sodass das korrumpierte nft_set_ext *ext einige Bytes nach der korrekten Position liegt. Dies bedeutet, dass bestimmte benutzergesteuerte Datenfelder des ursprünglichen nft_set_ext nun als Header interpretiert werden, was zu einer Typverwirrung führt.

Eine Möglichkeit, diese Typverwirrung auszunutzen, besteht darin, die korrumpierten nft_set_ext-Header mit Offsetwerten so zu präparieren, dass nf_tables_set_elem_destroy() den Inhalt beliebiger benachbarter Speicherblöcke als die Liste der zu zerstörenden nft_expr interpretiert, und zwar über die folgenden Aufrufe:

nft_set_elem_expr_destroy()
    __nft_set_elem_expr_destroy()
        nf_tables_expr_destroy()
            expr->ops->destroy()

An diesem Punkt der Ausnutzung haben wir noch keine Details zum Kernel-Speicherlayout. Daher ist es nicht möglich, absolute Zeigeradressen zu präparieren. Bei der Präparierung der korrumpierten nft_set_ext-Header können wir jedoch immer noch außerhalb des gültigen Bereichs liegende Offsets verwenden, sodass expr->ops->destroy() auf bestimmten gültigen nft_expr in den benachbarten Speicherblöcken aufgerufen wird.

Dazu spammen wir nft_log-Ausdrücke mit kontrolliertem NFTA_LOG_PREFIX. Dieses nft_log->prefix wird dann durch nft_log_destroy() freigegeben, sobald expr->ops->destroy() aufgerufen wird:

static void nft_log_destroy(const struct nft_ctx *ctx,
                            const struct nft_expr *expr)
{
        struct nft_log *priv = nft_expr_priv(expr);
        struct nf_loginfo *li = &priv->loginfo;

        if (priv->prefix != nft_log_null_prefix)
                kfree(priv->prefix);

Beachten Sie, dass wir auf diesen Speicher über die andere Referenz des gespammten nft_log-Ausdrucks immer noch zugreifen und ihn sogar erneut freigeben können.

Tool herunterladen