Skip to content
KitploitKITPLOIT
HerramientasBlog
Enviar
HerramientasBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
freebsd-dirent-info-leak-bugs — CVE-2020-25578 y CVE-2020-25579: Algunos bugs de fuga de información de FreeBSD que encontré en 2020. | Kitploit
Herramientas/GitHubGitHub/farazsth98/freebsd-dirent-info-leak-bugs
Forensia de MemoriaAnálisis de VulnerabilidadesExplotaciónRecopilación de InformaciónAnálisis de Binarios
GitHubfarazsth98/freebsd-dirent-info-leak-bugs

freebsd-dirent-info-leak-bugs

CVE-2020-25578 y CVE-2020-25579: Algunos bugs de fuga de información de FreeBSD que encontré en 2020.

Ver Repositorio

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir
722hace 5 añosAún no revisado

¿Cómo encontré los bugs?

  1. Decido aleatoriamente auditar los sistemas de archivos en FreeBSD
  2. Investigo un poco y descubro que el sistema de archivos predeterminado es una combinación de FFS y UFS
  3. Dedico un tiempo a auditar ufs_create y encuentro 0 bugs
  4. Ve aquí y revisa el historial de commits de las funciones del sistema de archivos UFS
  5. Detecto este commit sobre información filtrada a través de bytes de relleno en objetos struct dirent asignados en la pila
  6. Analizo el parche y encuentro que el parche para msdosfs_readdir está incompleto. Parchearon una instancia del bug, pero no una segunda.
  7. Escribo un PoC para confirmar que puedo filtrar 3 bytes del relleno. Luego empiezo a buscar variantes.
  8. Encuentro las variantes en mqueuefs, autofs, smbfs y tmpfs que me permiten filtrar un puntero completo de 8 bytes. Escribo PoC para confirmar.

Bug original

Como se mencionó anteriormente, el bug original que encontré estaba en msdosfs_readdir mientras analizaba el parche del commit enlazado arriba.

El flujo básico para llamar a readdir en FreeBSD es el siguiente:

root@kitploit:~
#include <dirent.h>

int main(void) {
    struct dirent *dp;
    DIR *dirp;

    dirp = opendir("./somedir");
    dp = readdir(dirp);
}

Dependiendo del sistema de archivos en el que resida somedir, se puede llamar a cualquiera de las muchas funciones *_readdir en el kernel de FreeBSD.

El parche anterior agrega una función llamada dirent_terminate que está destinada a ser llamada antes de que un objeto struct dirent sea devuelto al espacio de usuario (a menudo usando la función uiomove). Esta función pondrá a cero los bytes de relleno así como los bytes restantes en el campo d_name de la estructura. La definición de struct dirent está aquí.

Mirando el parche, en la línea 1562, se puede ver que se llama a dirent_terminate con la variable dirbuf como argumento. A continuación, uiomove es llamado para copiar el contenido de dirbuf de vuelta al espacio de usuario. Sin embargo, nota que estas líneas de código están dentro del bloque de esta sentencia if. El comentario sobre esta sentencia if explica que esta rama solo se toma si readdir es llamado en la raíz del sistema de archivos MSDOS, por lo que podemos simplemente saltar esta sentencia if llamando a readdir en cualquier subdirectorio más allá de la raíz del sistema de archivos.

Más abajo, vemos otra llamada a uiomove en la línea 1691. Sin embargo, leyendo el código con atención, verás que dirent_terminate no es llamado en esta instancia, lo que significa que los bytes de relleno permanecerán sin inicializar. Desafortunadamente, el campo d_name fue puesto a cero al inicio de esta función (aquí), por lo que no podemos obtener una fuga más grande.

PoC

Primero, no tenía una unidad USB, así que tuve que encontrar una forma de montar un sistema de archivos MSDOS. Lo siguiente funciona:

root@kitploit:~
$ dd if=/dev/zero of=test.img bs=512 count=256000
$ sudo mdconfig -a -t vnode -f test.img
$ sudo newfs_msdos -s 131072000 /dev/md1 # Mi mdconfig devolvió md1
$ mkdir ./temp
$ sudo mount -t msdosfs /dev/md1 ./temp
$ mkdir ./temp/test_dir

El PoC se puede encontrar en original_poc.c. Simplemente compílalo con clang y ejecútalo desde el mismo directorio que los comandos anteriores, y verás los bytes filtrados impresos.

Variantes

Empecé a buscar variantes de esto. Creo que simplemente hice un grep de uiomove\(&.*, que devolvió alrededor de 15-20 resultados, y los revisé todos manualmente. Desafortunadamente, ninguna de las variantes existe en FreeBSD por defecto (los sistemas de archivos tienen que ser habilitados manualmente / compilados en el kernel). Las funciones con las variantes son las siguientes:

  1. mqfs_readdir
  2. tmpfs_dir_getdotdent
  3. tmpfs_dir_getdotdotdent
  4. smbfs_readvdir
  5. autofs_readdir_one

El bug es exactamente el mismo en todas estas funciones, así que solo cubriré mqfs_readdir.

  1. Primero, se asigna un struct dirent entry en la pila
  2. Luego, se llama a dirent_terminate para poner a cero los campos de relleno + d_name de la estructura
  3. Finalmente, se llama a vfs_read_dirent. Esta función llamará a uiomove para copiar la estructura al espacio de usuario

Todo se ve bien hasta ahora, ¿verdad? No necesariamente. Tenemos que asegurarnos de que todos los campos de la estructura estén inicializados. Si observas el código con atención, verás que el campo d_off queda sin inicializar. El tipo de este campo es off_t, que es esencialmente un int64_t. Cuando la estructura se copia al espacio de usuario, obtenemos datos no inicializados en este campo.

PoC

Este mismo PoC funcionará para todas las variantes, solo tienes que ejecutarlo en un sistema de archivos diferente. Para mqueuefs, haz lo siguiente (primero necesita mqueuefs habilitado / compilado en el kernel):

root@kitploit:~
$ mkdir ./temp
$ sudo mount -t mqueuefs null ./temp

El PoC en sí se puede encontrar en variants_poc.c. Simplemente compílalo con clang y ejecútalo desde el mismo directorio que los comandos anteriores. Verás punteros del kernel impresos (presumiblemente un puntero de pila y un puntero de sección de código / heap, no lo verifiqué).

Descargar herramienta