¿Cómo debo compilar el programa para las pruebas fuzz?

7

Estoy haciendo algunas pruebas fuzz de un programa para el que tengo código fuente. ¿Debo compilar el programa con alguna opción de compilador en particular, para que la prueba fuzz sea más efectiva? Si es así, ¿cuál es la lista correcta de indicadores de línea de comando para pasar al compilador, para que la prueba fuzz sea lo más efectiva posible?

¿Debo intentar habilitar explícitamente las cookies de pila (gcc -fstack-protector)? ¿Comprobación de la longitud de los buffers asignados a la pila (gcc -D_FORTIFY_SOURCE = 2)? Malloc / comprobación gratuita (env MALLOC_CHECK_ = 2)? El asignador de depuración de Glib (G_SLICE = debug-blocks)?

¿Recomendaría que usara Mudflap (por ejemplo, gcc -fmudflap -fmudflapir + MUDFLAP_OPTIONS = '- mode -check -viol-abort -check-initializations -ignore-reads ')?

Me interesan especialmente las respuestas para gcc en Linux, pero siéntase libre de responder también para otras plataformas.

    
pregunta D.W. 08.09.2011 - 23:50
fuente

3 respuestas

4

Si una aplicación se bloquea de una prueba, una opción del compilador no la guardará. Si compila la aplicación con gcc -D_FORTIFY_SOURCE=2 -O2 , el proceso se eliminará con más frecuencia debido a infracciones menores de la memoria que normalmente no bloquearían el proceso. Un buen ejemplo de esto es que tendrá una mayor capacidad para detectar desbordamientos de pilas adyacentes.

GCC Mudflap es una herramienta de depuración más avanzada para buscar punteros colgantes, liberas dobles, desbordamientos de búfer y posiblemente otra memoria Vulnerabilidades de corrupción. Esta opción del compilador GCC hace que la aplicación sea muy lenta, por lo que no está destinada a la producción. Sin embargo, registra todas las violaciones de memoria, incluso las violaciones que no hacen que la aplicación se bloquee. Le brinda información detallada para ayudar a reducir el tipo de violación de memoria con la que está trabajando.

sin embargo es una gallina o el huevo. Después de encontrar una de estas fallas, tendrás que vencer este sistema de seguridad que no es una tarea fácil (o alguien que no esté usando esta medida de seguridad). No podrás encontrar los ataques de estilo "Aplastar la pila por diversión y ganancias". Las técnicas modernas incluyen encadenamiento de vulnerabilidades de corrupción de memoria y el uso de Cadenas ROP para derrotar a ASLR.

    
respondido por el rook 10.09.2011 - 18:44
fuente
5

Nadie sugirió una respuesta definitiva, así que hice un pequeño experimento. Basado en este experimento, aquí está mi recomendación hasta ahora:

Recomendación. Al fuzzing, puedes considerar configurar las variables de entorno LIBC_FATAL_STDERR_=1 MALLOC_CHECK_=3 . Esta configuración no tuvo un impacto medible en el rendimiento en mi experimento y, según mis resultados, esta configuración podría aumentar ligeramente la cantidad de errores que detectas.

Ninguna de las otras configuraciones hizo una diferencia detectable en mi experimento.

Opcional. Si lo deseas, puedes compilar con -fstack-protector o -fstack-protector-all , con -O2 -D_FORTIFY_SOURCE=2 , y / o con mudflap; y puede ejecutar con la variable de entorno G_SLICE=debug-blocks . Ninguno de ellos tuvo un impacto medible en el rendimiento en mi experimento. Sin embargo, ninguno de ellos tuvo ningún impacto en el conjunto de errores encontrados. Entonces, si bien no hubo costo en mi experimento, tampoco hubo beneficio.

Metodología experimental y detalles. En cada ejecución, confundí ffmpeg con zzuf , utilizando un archivo semilla, para 5000 iteraciones. Hubo una ejecución por configuración de indicadores de compilador / variables de entorno. Me aseguré de que fuzzing generara exactamente el mismo conjunto de archivos de variante en cada ejecución, por lo que la única diferencia era el compilador de indicadores / variables de entorno. Para medir el impacto en el rendimiento, medí el tiempo de CPU + del sistema para completar el difuminado. Para medir el impacto en la capacidad de detectar errores, registré qué archivos de variantes provocaron un bloqueo detectable.

Medí el rendimiento, pero ninguna de las opciones tuvo un efecto detectable en el rendimiento (las diferencias fueron de < 1% en todos los casos, y probablemente debido al ruido aleatorio).

Para el poder de detección de errores, I MALLOC_CHECK_=3 dio una ligera ventaja, pero ninguna de las otras marcas o configuraciones hizo alguna diferencia en el poder de detección de errores:

  • MALLOC_CHECK_=3 tuvo una influencia en qué archivos de variantes provocaron un bloqueo. Sin banderas, 22 de las 5000 iteraciones causaron un choque. Otras 2 iteraciones causaron un mensaje de advertencia ( *** glibc detected *** ...) que, si supiera buscarlo, se podría usar para detectar un error, por lo que si era lo suficientemente inteligente como para grep sus registros de confusión para ese mensaje, 24 de las 5000 iteraciones darían señales de un error, mientras que si no conoce los registros para ese mensaje de advertencia en particular, solo 22 de las 5000 iteraciones proporcionaron indicaciones de un error. En contraste, cuando habilité MALLOC_CHECK_=3 , 25 de las 5000 iteraciones causaron un bloqueo y no hubo necesidad de grep en los registros. Por lo tanto, MALLOC_CHECK_=3 ambos es ligeramente más efectivo para descubrir signos de un error, y también reduce la necesidad de postprocesar sus registros de confusión especialmente.

    Interesantemente, hubo un archivo de variantes que bloqueó el programa sin configuraciones pero no lo hizo con MALLOC_CHECK_=3 , lo que confirma la hipótesis de @ this.josh de que la comprobación adicional en algunos casos podría hacer que nos perdamos algunos errores. pero al mismo tiempo, hubo 2 archivos de variantes que no bloquearon el programa sin configuraciones, pero que lo hicieron con MALLOC_CHECK_=3 . Por lo tanto, los beneficios de MALLOC_CHECK_=3 superaron sus costos.

  • Aparte de MALLOC_CHECK_ , ninguna de las otras configuraciones tuvo influencia alguna en los archivos de variantes que provocaron un bloqueo detectable. El conjunto de archivos de variantes que causaron que el programa de línea de base (sin indicadores especiales) se bloquee fue exactamente igual que el conjunto de archivos de variantes que causaron que el programa fallara cuando se compila con indicadores especiales. Por lo tanto, al menos en este experimento, esas otras configuraciones no nos costaron nada (en el rendimiento), pero tampoco nos ganaron nada (en el poder de detección de errores).

Mi experimento está lejos de ser autoritario. Para hacer esto bien, uno debería probarlo con muchos programas diferentes (no solo uno) y múltiples archivos semilla diferentes (no solo uno). Así que le advierto que no saque demasiadas conclusiones de este pequeño experimento. Pero pensé que los resultados eran interesantes, no obstante.

    
respondido por el D.W. 13.09.2011 - 09:42
fuente
4

Qué pregunta interesante. Supongo que solo es UNIX, pero si no lo es, lo primero que recomendaría es probarlo en ambos entornos. Windows tiene un conjunto de herramientas realmente bueno para realizar la depuración del montón, la administración peligrosa de la API y demás: el verificador de aplicaciones de Google si está interesado.

Pero en general, yo diría que debería al menos intentar una versión de lanzamiento, con la misma configuración de optimizador que planea usar en producción. Desea tener una configuración en la prueba en la que no se guarde mediante las comprobaciones de depuración mejoradas, como el verificador de la aplicación o el material malloc_check. Después de todo, el atacante apuntará a su código optimizado de lanzamiento-construcción.

Incluso puedes probar con otros compiladores de linux, y fuzz contra esos resultados.

Más allá de eso, estoy tan interesado en escuchar las respuestas como usted. :-)

    
respondido por el Steve Dispensa 09.09.2011 - 03:59
fuente

Lea otras preguntas en las etiquetas