
Una vulnerabilidad relacionada con Linux
Lo que es este repositorio: mi reproducción práctica y estudio de CVE-2023-32233, un use-after-free en el subsistema nf_tables de Netfilter del kernel de Linux que permite la escalada local de privilegios, divulgado públicamente en mayo de 2023 por Patryk Sondej y Piotr Krysiuk.
Crédito: el PoC (exploit.c) y el análisis original son de
@Liuk3r. Mi trabajo en este repositorio
consiste en reproducir el exploit en mi propio laboratorio (Ubuntu 23.04, kernel
6.2.0-20) y documentar la causa raíz y la cadena de explotación a continuación. Todas
las pruebas se realizaron en máquinas de laboratorio dedicadas.
nf_tables procesa las actualizaciones de configuración como un lote atómico. La validación de cada operación frente a los cambios de estado de las operaciones anteriores del mismo lote es insuficiente. Concretamente:
nft_rule que contiene una expresión lookup sobre un
nft_set anónimo que contiene algunos elementos.NFT_MSG_DELRULE — elimina la regla, lo que a su vez elimina la expresión
lookup y el nft_set anónimo;NFT_MSG_DELSETELEM — elimina un elemento del conjunto anónimo ya eliminado.nf_tables_commit_release() pone en cola los recursos en
nf_tables_destroy_list, procesados más tarde por
nf_tables_trans_destroy_work():
primero nft_commit_release() → nf_tables_rule_destroy() →
nft_lookup_destroy() → nft_set_destroy() → kvfree() libera el nft_set;
luego, para NFT_MSG_DELSETELEM, nf_tables_set_elem_destroy() llama
a nft_set_elem_ext(), que desreferencia el nft_set :
Si set->ops->elemsize está corrompido, una ubicación de memoria elegida por el
atacante se interpreta como un nft_set_ext — la primitiva sobre la que se
construye todo lo demás.
nf_tables_trans_destroy_work() que se ejecuta en
un hilo de trabajo en segundo plano: insertar una operación grande de destrucción
de conjunto como retardo controlado, mantener ocupadas otras CPUs y reasignar el
fragmento liberado del nft_set desde la misma CPU con un nft_set de un tipo
diferente (elemsize distinto) → confusión de tipos.nft_set_ext corruptas con desplazamientos fuera de rango
para que nf_tables_set_elem_destroy() recorra fragmentos adyacentes como una
lista de nft_expr que destruir.nft_log con NFTA_LOG_PREFIX controlado;
nft_log_destroy() libera priv->prefix, dando una primitiva de asignación
superpuesta en kmalloc-{8..192} (limitada por bytes NULL al principio).Cabe destacar que las primitivas elegidas evitan cualquier cosa que CFI bloquearía — no se necesita secuestro de llamadas indirectas en ningún paso.
SLAB_FREELIST_HARDENED), INIT_ON_FREE y las restricciones de reutilización
de slabs por CPU atacan el paso 1; CFI (donde esté presente) limita el paso 3 y
siguientes.nf_tables que contengan DELRULE+DELSETELEM en conjuntos anónimos; triaje de
caídas para nft_set_elem_ext / nf_tables_trans_destroy_work en la pila.nftables requiere CAP_NET_ADMIN,
pero los espacios de nombres de usuario sin privilegios lo otorgan — por eso
kernel.unprivileged_userns_clone=0 es un parámetro de endurecimiento relevante.Probado en 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
El perfil integrado apunta a los kernels binarios de Ubuntu 23.04
(linux-image-6.2.0-20-generic 6.2.0-20.20). Para probar otros kernels,
extrae los símbolos en un archivo profile:
modprobe nf_tables
egrep ' (nft_counter_ops|nft_counter_destroy|free_percpu|modprobe_path)(\s|$)' /proc/kallsyms > profile
El diseño del código máquina de nft_counter_destroy() varía según el compilador
y las opciones; consulta ORIGIN.md para la referencia completa de
parámetros (nft_counter_destroy_call_offset/mask/check) y las perillas de ajuste
de la carrera (race_lead_sleep, etc.). La probabilidad de éxito reportada es ≥80%
en sistemas Intel de metal desnudo en reposo; algunas microarquitecturas (p. ej.,
Alder Lake) necesitan ajustes adicionales.
El PoC deja el kernel en un estado inestable con memoria corrupta después de una ejecución exitosa. Solo pruébalo en un sistema dedicado y desechable o en una instantánea de máquina virtual — nunca en algo con datos que te importen.
exploit.c — código fuente del PoC (por @Liuk3r)ORIGIN.md — análisis original de la vulnerabilidad y la explotación (por Liuk3r)README.md — este archivo: reproducción + mis notas de análisisInvestigación realizada con fines defensivos/educativos en un entorno de laboratorio aislado.
static inline struct nft_set_ext *nft_set_elem_ext(const struct nft_set *set,
void *elem)
{
return elem + set->ops->elemsize;
}
nft_object->udatanft_dynset para dos tipos de expresiones con estado:
nft_counter — filtra nft_counter_ops → base de nf_tables.ko
(derrota el KASLR del módulo);nft_quota — el puntero consumed permite lectura arbitraria
(NFT_MSG_GETSETELEM → nft_quota_do_dump() → NFTA_QUOTA_CONSUMED)
y escritura arbitraria (nft_overquota() añade skb->len a
*priv->consumed en tráfico de loopback).modprobe_path ("/sbin/modprobe" → "//tmp/modprobe") →
ejecución de un proceso root con contenido controlado por el atacante.