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
POC-CVE-2023-32233 — Uso após liberação no Netfilter nf_tables ao processar solicitações em lote CVE-2023-32233 | Kitploit
Ferramentas/GitHubGitHub/oferchen/poc-cve-2023-32233
Escalada de PrivilégiosForensia de MemóriaAnálise de VulnerabilidadesExploraçãoTestes de PenetraçãoDesenvolvimento de PayloadsExploração de Binários
GitHuboferchen/poc-cve-2023-32233

POC-CVE-2023-32233

Uso após liberação no Netfilter nf_tables ao processar solicitações em lote CVE-2023-32233

Ver Repositório
53610há 3 anosRevisado pelo Kitploit

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

Use-After-Free no Netfilter nf_tables ao processar solicitações em lote

Demonstração

Demo_CVE-2023-32233

Detalhes da Vulnerabilidade

O código afetado é originário do kernel Linux oficial de https://kernel.org/ e faz parte do componente Netfilter nf_tables (net/netfilter/nf_tables_api.c).

Netfilter nf_tables permite atualizar sua configuração como uma operação atômica. Ao usar este recurso, os clientes em modo de usuário enviam solicitações em lote contendo uma lista de operações básicas. O Netfilter nf_tables processa então todas as operações do lote como uma única transação. Ao processar o lote, o Netfilter nf_tables verifica as atualizações de estado da configuração para garantir que cada operação básica sucessiva seja válida, e isso também considera as atualizações de estado de todas as operações anteriores no lote. No entanto, a verificação atualmente implementada é insuficiente.

Em nosso cenário específico, começamos com uma configuração do Netfilter nf_tables que possui um nft_rule com expressão lookup em nft_set anônimo, e onde o nft_set anônimo contém alguns elementos. Em seguida, enviamos uma solicitação em lote contendo as seguintes duas operações básicas:

  1. Operação NFT_MSG_DELRULE para excluir o nft_rule.
    Observe que isso também exclui implicitamente a expressão lookup e o nft_set anônimo.
  2. Operação NFT_MSG_DELSETELEM para excluir qualquer um dos elementos do nft_set anônimo excluído.

A versão atual do Netfilter nf_tables aceita a solicitação em lote acima. Em seguida, ela chama nf_tables_commit_release(), que anexa os recursos liberados a nf_tables_destroy_list. O nf_tables_destroy_list é então processado por nf_tables_trans_destroy_work(), que primeiro desaloca recursos relacionados à operação NFT_MSG_DELRULE chamando:

nft_commit_release()
    nf_tables_rule_destroy()
        nf_tables_expr_destroy()
            expr->ops->destroy() that points to nft_lookup_destroy()
                nf_tables_destroy_set()
                    nft_set_destroy()
                        kvfree() that deallocates memory used by `nft_set`

antes de processar a operação NFT_MSG_DELSETELEM, onde a referência ao nft_set desalocado é acessada via nft_trans_elem_set() durante as seguintes chamadas:

nft_commit_release()
    nf_tables_set_elem_destroy()
        nft_set_elem_ext()

Dentro de nft_set_elem_ext() acima, a localização de memória do nft_set desalocado é acessada para determinar a localização de nft_set_ext:

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

para as operações que se seguem. Portanto, sempre que o valor de set->ops->elemsize é corrompido, uma localização de memória inesperada pode ser interpretada como lista de nft_expr a ser destruída:

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));

Técnicas de Exploração

Explorar a vulnerabilidade acima requer vencer uma corrida com nf_tables_trans_destroy_work(), que é executada a partir da thread de trabalho em segundo plano do kernel Linux. Isso parece complicar a exploração prática antes mesmo de considerarmos as mitigações existentes, como o endurecimento do alocador de slabs do kernel, a Randomização do Layout do Espaço de Endereço do Kernel (KASLR) e especialmente a Integridade do Fluxo de Controle. No entanto, o PoC anexado prova que ainda é possível obter uma exploração razoavelmente confiável na prática.

Para explorar a vulnerabilidade, precisamos modificar o conteúdo da memória do nft_set depois que ele é desalocado em nf_tables_rule_destroy(), mas antes que seja usado em nf_tables_set_elem_destroy(). Ambas as funções nf_tables_rule_destroy() e nf_tables_set_elem_destroy() são chamadas em uma única invocação de nf_tables_trans_destroy_work(), que é executada a partir da thread de trabalho em segundo plano do kernel Linux. Além disso, a região de memória desalocada geralmente está disponível para reutilização apenas no mesmo núcleo da CPU.

Ao competir com nf_tables_trans_destroy_work(), aumentamos nossas chances adicionando um atraso controlado para a thread de trabalho em segundo plano entre suas chamadas a nf_tables_rule_destroy() e nf_tables_set_elem_destroy(). Para isso, inserimos uma operação adicional para destruir outro nft_set contendo um grande número de elementos. Além disso, mantemos todos os outros núcleos da CPU ocupados, de modo que a thread de trabalho em segundo plano provavelmente seja escalonada em um núcleo de CPU específico, permitindo-nos tentar alocar uma nova estrutura do mesmo núcleo de CPU logo após ela desalocar o nft_set em nf_tables_rule_destroy(). Nosso objetivo é alocar um novo nft_set de tipo diferente para reutilizar a localização de memória do nft_set desalocado em nf_tables_rule_destroy().

O novo tipo de nft_set é selecionado para usar um valor diferente para set->ops->elemsize. Assim, quando a thread de trabalho em segundo plano finalmente chama nf_tables_set_elem_destroy() para processar a operação NFT_MSG_DELSETELEM, ela interpreta seu argumento elem incorretamente, de modo que o nft_set_ext *ext corrompido fica alguns bytes após a localização correta. Isso significa que certos campos de dados controlados pelo usuário do nft_set_ext original são agora interpretados como cabeçalhos, resultando em confusão de tipos.

Uma maneira de abusar dessa confusão de tipos é elaborar os cabeçalhos corrompidos do nft_set_ext com valores de offsets tais que nf_tables_set_elem_destroy() interprete o conteúdo de quaisquer blocos de memória adjacentes como a lista de nft_expr a destruir por meio das seguintes chamadas:

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

Neste ponto da exploração, ainda não temos detalhes do layout da memória do kernel. Portanto, não é possível elaborar endereços absolutos de ponteiros. No entanto, ao elaborar os cabeçalhos corrompidos do nft_set_ext, ainda podemos usar offsets fora do intervalo, de modo que expr->ops->destroy() seja chamado em certos nft_expr válidos nos blocos de memória adjacentes.

Para isso, pulverizamos expressões nft_log, com NFTA_LOG_PREFIX controlado. Esse nft_log->prefix é então desalocado por nft_log_destroy() quando expr->ops->destroy() é chamado:

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);

Observe que ainda podemos acessar e até mesmo desalocar novamente essa memória por meio da outra referência da expressão nft_log pulverizada.

Além disso, também podemos controlar o tamanho de nft_log->prefix, de modo que ele possa ser alocado de qualquer um dos slabs kmalloc-{8, ..., 192}. Por fim, a memória referenciada é interpretada pelo kernel como uma string de caracteres, então não precisamos nos preocupar com corrupções ao sobrepor objetos diferentes sobre ela. Isso é essencialmente o fim de jogo.

Baixar ferramenta