
Riproduzione e analisi della causa radice di CVE-2023-32233, una use-after-free nel nf_tables del kernel Linux che consente l'escalation locale dei privilegi, con PoC e note di sfruttamento.
Cos'è questo repo: la mia riproduzione pratica e lo studio di CVE-2023-32233, una use-after-free nel sottosistema nf_tables di Netfilter del kernel Linux che consente l'escalation locale dei privilegi, divulgata pubblicamente a maggio 2023 da Patryk Sondej e Piotr Krysiuk.
Crediti: il PoC (exploit.c) e il write-up originale sono di
@Liuk3r. Il mio lavoro in questo repo
consiste nel riprodurre l'exploit nel mio laboratorio (Ubuntu 23.04, kernel 6.2.0-20)
e nel documentare di seguito la causa radice e la catena di sfruttamento. Tutti i test
sono stati eseguiti su macchine di laboratorio dedicate.
nf_tables elabora gli aggiornamenti di configurazione come un batch atomico. La validazione di ciascuna operazione rispetto ai cambiamenti di stato delle operazioni precedenti nello stesso batch è insufficiente. Concretamente:
nft_rule contenente un'espressione lookup su un
anonimo che contiene alcuni elementi.nft_setNFT_MSG_DELRULE — elimina la regola, che elimina implicitamente
l'espressione lookup e l'nft_set anonimo;NFT_MSG_DELSETELEM — elimina un elemento del set anonimo già eliminato.nf_tables_commit_release() accoda le risorse
su nf_tables_destroy_list, elaborate successivamente da
nf_tables_trans_destroy_work():
prima nft_commit_release() → nf_tables_rule_destroy() →
nft_lookup_destroy() → nft_set_destroy() → kvfree() libera
l'nft_set;
poi, per NFT_MSG_DELSETELEM, nf_tables_set_elem_destroy() chiama
nft_set_elem_ext() che dereferenzia l'nft_set liberato:
static inline struct nft_set_ext *nft_set_elem_ext(const struct nft_set *set,
void *elem)
{
return elem + set->ops->elemsize;
}
Se set->ops->elemsize è corrotto, una locazione di memoria scelta dall'attaccante
viene interpretata come un nft_set_ext — la primitiva su cui si basa tutto il resto.
nf_tables_trans_destroy_work() in esecuzione su un
thread worker in background: inserire una grande operazione di distruzione di set come
ritardo controllato, tenere occupate le altre CPU, e riallocare il chunk
nft_set liberato dalla stessa CPU con un nft_set di un tipo diverso
(elemsize diverso) → type confusion.nft_set_ext corrotti con offset fuori range in modo che
nf_tables_set_elem_destroy() percorra i chunk adiacenti come una lista di
nft_expr da distruggere.nft_log con NFTA_LOG_PREFIX controllato;
nft_log_destroy() libera priv->prefix, fornendo una primitiva di
allocazione sovrapposta in kmalloc-{8..192} (inizialmente limitata dal byte NULL).nft_object->udata per rimuovere la restrizione del byte NULL
sulla lettura dangling.nft_dynset per due tipi di espressioni stateful:
nft_counter — fa trapelare nft_counter_ops → base di nf_tables.ko
(aggira il KASLR per il modulo);nft_quota — il puntatore consumed fornisce lettura arbitraria
(NFT_MSG_GETSETELEM → nft_quota_do_dump() → NFTA_QUOTA_CONSUMED)
e scrittura arbitraria (nft_overquota() aggiunge skb->len a
*priv->consumed sul traffico loopback).modprobe_path ("/sbin/modprobe" → "//tmp/modprobe") →
esecuzione di un processo root con contenuto controllato dall'attaccante.In particolare, le primitive scelte evitano tutto ciò che il CFI bloccherebbe — non è necessario dirottare chiamate indirette in nessun passaggio.
SLAB_FREELIST_HARDENED), INIT_ON_FREE, e restrizioni sul riuso degli slab
per-CPU attaccano tutti il passaggio 1; il CFI (dove presente) vincola il passaggio 3+.nf_tables
contenenti DELRULE+DELSETELEM su set anonimi; triage dei crash per
nft_set_elem_ext / nf_tables_trans_destroy_work nello stack.nftables richiede CAP_NET_ADMIN, ma
gli user namespace non privilegiati lo concedono — questo è il motivo per cui
kernel.unprivileged_userns_clone=0 è una manopola di hardening significativa.Testato su Ubuntu 23.04 (Lunar Lobster), kernel 6.2.0-20-generic.
sudo apt install gcc libmnl-dev libnftnl-dev
gcc -Wall -o exploit exploit.c -lmnl -lnftnl
Il profilo integrato è pensato per i kernel binari di Ubuntu 23.04
(linux-image-6.2.0-20-generic 6.2.0-20.20). Per testare altri kernel,
estrarre i simboli in un file profile:
modprobe nf_tables
egrep ' (nft_counter_ops|nft_counter_destroy|free_percpu|modprobe_path)(\s|$)' /proc/kallsyms > profile
Il layout del codice macchina di nft_counter_destroy() varia con il compilatore e
le opzioni; vedere ORIGIN.md per il riferimento completo dei parametri
(nft_counter_destroy_call_offset/mask/check) e le manopole di tuning della race
(race_lead_sleep ecc.). La probabilità di successo riportata è ≥80% su sistemi
Intel bare-metal inattivi; alcune microarchitetture (es. Alder Lake) necessitano
di tuning aggiuntivo.
Il PoC lascia il kernel in uno stato instabile con memoria corrotta dopo un'esecuzione riuscita. Testare solo su un sistema dedicato e usa e getta o su uno snapshot di VM — mai su qualcosa con dati a cui tenete.
exploit.c — sorgente del PoC (di @Liuk3r)ORIGIN.md — write-up originale sulla vulnerabilità e sullo sfruttamento (di Liuk3r)README.md — questo file: riproduzione + le mie note di analisiRicerca condotta per scopi difensivi/educativi in un ambiente di laboratorio isolato.