
Reprodução e análise de causa raiz do CVE-2023-32233, um use-after-free no nf_tables do kernel Linux que permite escalonamento local de privilégios, com PoC e notas de exploração.
O que é este repositório: minha reprodução prática e estudo da CVE-2023-32233, um use-after-free no subsistema nf_tables do Netfilter do kernel Linux que permite escalonamento local de privilégios, divulgado publicamente em maio de 2023 por Patryk Sondej e Piotr Krysiuk.
Créditos: o PoC (exploit.c) e o write-up original são de
@Liuk3r. Meu trabalho neste repositório
é reproduzir o exploit no meu próprio laboratório (Ubuntu 23.04, kernel 6.2.0-20)
e documentar a causa raiz e a cadeia de exploração abaixo. Todos os testes
foram feitos em máquinas de laboratório dedicadas.
O nf_tables processa atualizações de configuração como um lote atômico. A validação de cada operação em relação às mudanças de estado das operações anteriores no mesmo lote é insuficiente. Concretamente:
nft_rule contendo uma expressão lookup sobre um
anônimo que contém alguns elementos.nft_setNFT_MSG_DELRULE — exclui a regra, o que implicitamente exclui a
expressão lookup e o nft_set anônimo;NFT_MSG_DELSETELEM — exclui um elemento do conjunto anônimo
já excluído.nf_tables_commit_release() enfileira recursos
em nf_tables_destroy_list, processados depois por
nf_tables_trans_destroy_work():
primeiro nft_commit_release() → nf_tables_rule_destroy() →
nft_lookup_destroy() → nft_set_destroy() → kvfree() libera o
nft_set;
depois, para NFT_MSG_DELSETELEM, nf_tables_set_elem_destroy() chama
nft_set_elem_ext() que desreferencia o nft_set liberado:
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 estiver corrompido, um local de memória escolhido pelo
atacante é interpretado como um nft_set_ext — a primitiva sobre a qual todo o
resto é construído.
nf_tables_trans_destroy_work() executando em uma
thread de trabalho em segundo plano: insira uma operação grande de destruição
de conjunto como atraso controlado, mantenha outras CPUs ocupadas e realoque o
chunk do nft_set liberado a partir da mesma CPU com um nft_set de um tipo
diferente (elemsize diferente) → confusão de tipos.nft_set_ext corrompidos com offsets fora do
intervalo para que nf_tables_set_elem_destroy() percorra chunks adjacentes
como uma lista de nft_expr a destruir.nft_log com NFTA_LOG_PREFIX controlado;
nft_log_destroy() libera priv->prefix, fornecendo uma primitiva de
alocação sobreposta em kmalloc-{8..192} (limitada por byte NULL no início).nft_object->udata para remover a restrição de byte NULL
na leitura pendente.nft_dynset para dois tipos de expressão com estado:
nft_counter — vaza nft_counter_ops → base de nf_tables.ko
(contorna o KASLR para o módulo);nft_quota — o ponteiro consumed fornece leitura arbitrária
(NFT_MSG_GETSETELEM → nft_quota_do_dump() → NFTA_QUOTA_CONSUMED)
e escrita arbitrária (nft_overquota() adiciona skb->len a
*priv->consumed no tráfego de loopback).modprobe_path ("/sbin/modprobe" → "//tmp/modprobe") →
execução de processo como root com conteúdo controlado pelo atacante.Notavelmente, as primitivas escolhidas evitam qualquer coisa que o CFI bloquearia — nenhum sequestro de chamada indireta é necessário em nenhuma etapa.
SLAB_FREELIST_HARDENED), INIT_ON_FREE e restrições de reutilização de slab
por CPU atacam a etapa 1; CFI (onde presente) restringe a etapa 3+.nf_tables contendo DELRULE+DELSETELEM em conjuntos anônimos; triagem de
crash para nft_set_elem_ext / nf_tables_trans_destroy_work na pilha.nftables requer CAP_NET_ADMIN, mas
namespaces de usuário sem privilégios o concedem — é por isso que
kernel.unprivileged_userns_clone=0 é um ajuste de endurecimento significativo.Testado no 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
O perfil embutido tem como alvo os kernels binários do Ubuntu 23.04
(linux-image-6.2.0-20-generic 6.2.0-20.20). Para testar outros kernels,
extraia os símbolos para um arquivo profile:
modprobe nf_tables
egrep ' (nft_counter_ops|nft_counter_destroy|free_percpu|modprobe_path)(\s|$)' /proc/kallsyms > profile
O layout de código de máquina de nft_counter_destroy() varia com o compilador e
as opções; veja ORIGIN.md para a referência completa de parâmetros
(nft_counter_destroy_call_offset/mask/check) e ajustes de sintonia da corrida
(race_lead_sleep etc.). A probabilidade de sucesso relatada é ≥80% em sistemas
Intel bare-metal ociosos; algumas microarquiteturas (por exemplo, Alder Lake)
precisam de ajuste extra.
O PoC deixa o kernel em um estado instável com memória corrompida após uma execução bem-sucedida. Teste apenas em um sistema dedicado e descartável ou snapshot de VM — nunca em algo com dados que você se importa.
exploit.c — código-fonte do PoC (por @Liuk3r)ORIGIN.md — write-up original da vulnerabilidade e exploração (por Liuk3r)README.md — este arquivo: reprodução + minhas notas de análisePesquisa conduzida para fins defensivos/educacionais em um ambiente de laboratório isolado.