Proyecto
Para ejecutar: ./script.sh
Repositorio en GitHub - https://github.com/LaCinquette/practice-22-23
Desarrollo
-
Para buscar la vulnerabilidad elegí el proyecto FFmpeg. Encontré en él un commit que cumplía los requisitos, a saber:
- Correspondía al tipo CWE-476 - desreferencia de puntero nulo
-
Creé un Dockerfile, en el que:
- Elegí como imagen base Ubuntu 22.04
- Configuré
DEBIAN_FRONTEND=nointeractive para evitar la interacción con la línea de comandos durante la instalación de paquetes y otros comandos
- Instalé las dependencias necesarias indicadas en la wiki oficial
- Preparo el lugar de trabajo (carpeta workdir)
- Descargo, descomprimo y muevo el commit con la vulnerabilidad aún sin corregir al lugar de trabajo
- Ejecuto el build del programa con la utilidad make
- Creo el script copy_out.sh, que se encarga de buscar el archivo objeto necesario con el error y copiarlo al directorio workspace/out
- Dejo una instrucción para ejecutar el script copy_out.sh, que debe ejecutarse al iniciar el contenedor
-
Para automatizar creo el script script.sh, que compila la imagen y ejecuta el contenedor, del cual luego toma el archivo y lo mueve al directorio actual:
- Elimino la carpeta actual out (si existe)
- Compilo la imagen con el nombre ffmpeg_image
- Ejecuto el contenedor basado en la imagen compilada, en el que paso los siguientes parámetros:
--rm para la eliminación automática del contenedor al finalizar
-v $PWD/out:/workspace/out para montar el directorio temporal, a través del cual el archivo objeto se transfiere al host
- Copio el archivo necesario de la carpeta out
- Elimino la carpeta out
Análisis de la vulnerabilidad
Fuentes:
- Commit con el error corregido
- Página en GitHub sobre la vulnerabilidad
- Correo del investigador de seguridad sobre la vulnerabilidad
Análisis:
Problema:
- Con el comando
ffmpeg -c:v dnxhd -i poc.mov -y output.ts se envía a la entrada del programa un archivo .mov creado especialmente
- Para el parseo del formato DNxHD se llama a la función dnxhd_parse en el archivo dnxhd_parser
- Esta a su vez llama a la función dnxhd_find_frame_end (en el mismo archivo), que bajo ciertas condiciones no encuentra el final y devuelve un número negativo, que no es un código de error
- Este número, junto con otros parámetros, se pasa a la función ff_combine_frame (ubicada en el archivo parser) para la unión de los frames
- Como este número no es un código de error, ff_combine_frame lo interpreta como un desplazamiento e intenta volver a leer esos bytes del buffer, y como el buffer en ese momento está vacío, se produce la desreferencia de un puntero nulo, lo que provoca un Segmentation fault
En ensamblador:
0x08000d4e - inicio de la sección
-
movsxd rcx, dword [rbx + 0xc]
En el registro rcx obtenemos la referencia a pc->buffer
-
add rcx, rdi
Añadimos next a pc->buffer
-
add rcx, qword [rbx]
Añadimos pc->last_index a next y a pc->buffer
-
movzx edi, byte [rcx]
Obtenemos el byte en la dirección rcx, pero como pc->buffer es inicialmente null - obtenemos un Segmentation fault
Solución:
Evitar el acceso a una región de memoria no asignada, mediante el manejo correcto del caso excepcional. Al detectar un número negativo de bytes restantes, continuar el procesamiento del archivo omitiendo el bucle.