Guía de uso: American Fuzzy Lop para principiantes

⚠️ Nota importante

Este artículo tiene más de un año. La tecnología evoluciona rápido, por lo que algunos contenidos o instrucciones pueden estar desactualizados. Recuerda buscar información reciente y actualizada.

Fuzzing es una de las más poderosas y probadas estrategias para identificar problemas de seguridad en todo tipo de software. Gran cantidad de los bugs de ejecución remota de código y escalada de privilegios encontrados hasta la fecha han sido gracias a esta técnica. No es perfecta ya que es relativamente superficial. La mutaciones aleatorias hacen poco probable alcanzar algunas rutas del código bajo prueba. American Fuzzy Lop es un fuzzer de fuerza bruta acoplado con un simple pero sólido algoritmo genético con un guía visual detallada. Básicamente, el funcionamiento de esta herramienta se resume así:

  1. Carga los casos de prueba iniciales provistos por el usuario
  2. Toma el archivo de entrada de la lista
  3. Intenta recortar el caso de prueba al menor tamaño posible sin alterar el comportamiento del programa
  4. Muta repetidamente el archivo usando una variedad de estrategias de fuzzing
  5. Si alguna de las mutaciones generadas resultan en una transición en el estado registrada por la instrumentación agrega la mutación a la lista de entradas y vuelve al segundo paso. 

En este artículo explicaré como usar este fuzzer de forma sencilla y rápida por medio de un caso de ejemplo. Además incorporaré algunas estrategias para aumentar el rendimiento en sistemas de múltiples núcleos y aumentar la eficiencia del proceso en general. Es especialmente usado para encontrar algunos problemas en programas de código abierto ya que es más eficiente si se cuenta con el código fuente. Es importante aclarar que solo está disponible para Linux. 

Instalando American Fuzzy Lop

Descargar el código fuente de  American Fuzzy Lop en este enlace. Una vez descargado lo extraemos en la carpeta que queramos y ejecutamos abrimos una terminal en dicha carpeta y ejecutamos el comando:

sudo make install

Una vez instalado debemos preparar el programa que vamos a someter a las pruebas. 

Preparando programas para American Fuzzy Lop

Cuando el código fuente está disponible se puede inyectar la instrumentación por medio de una herramienta incluida que simplemente funciona en sustitución gcc. La forma correcta de recompilar un programa puede variar dependiendo del proceso original. En este caso voy a utilizar dos ejemplos para demostrar. 

En el primer ejemplo voy a utilizar un programa llamado Fuzzgoat que puede ser descargado en este enlace. Fuzzgoat se diseñó de forma deliberada con una serie de bugs (backdoors y corrupción de memoria) para probar la eficacia de los fuzzers y otras herramientas de análisis. Para prepararlo para AFL debemos extraerlo y recompilarlo usando el siguiente archivo Makefile:

CC=afl-gcc
DEPS=main.c fuzzgoat.c
ASAN=-fsanitize=address
CFLAGS=-I.
LIBS=-lm

all: $(DEPS)
	$(CC) -o fuzzgoat $(CFLAGS) $^ $(LIBS)
	$(CC) $(ASAN) -o fuzzgoat_ASAN $(CFLAGS) $^ $(LIBS)

afl: fuzzgoat
	afl-fuzz -i in -o out ./fuzzgoat @@

.PHONY: clean

clean:
	rm ./fuzzgoat ./fuzzgoat_ASAN

Lo importante del ejemplo anterior es como va a utilizar afl-gcc en lugar del gcc regular. No debería tener problema ubicando el archivo si la instalación se completó correctamente en el paso anterior. En el caso de que no ubique correctamente el binario lo mejor es copiarlo de la carpeta de AFL a la carpeta de Fuzzgoat. Una vez compilado no queda más que ejecutar el fuzzer utilizando los archivos preparados para desencadenar cada vulnerabilidad. 

En el segundo ejemplo voy a utilizar un sencillo programa de Github que pueden descargar en este enlace. Se extrae igualmente y se revisa el archivo Makefile que originalmente contiene lo siguiente: 

all: plsa

plsa: Database.o Plsm.o plsa.o
	$(CXX) -o plsa plsa.o Database.o Plsm.o

Database.o: Database.cpp Database.h
	$(CXX) -c Database.cpp

Plsm.o: Plsm.cpp Plsm.h
	$(CXX) -c Plsm.cpp

plsa.o: plsa.cpp
	$(CXX) -c plsa.cpp

clean:
	rm *.o plsa

Dado que estamos trabajando en Linux y al intentar compilar con de esa forma nos va a indicar que requiere soporte para las librerías ISO C++ 2011 debemos agregar dicha opción (-std=c++11) experimental al Makefile y además agregar la ruta correcta para compilar como en el ejemplo anterior. El archivo entonces queda de la siguiente forma:

all: plsa

CXX=/home/eera5607/afl-2.52b/afl-g++

plsa: Database.o Plsm.o plsa.o
	$(CXX) -o plsa plsa.o Database.o Plsm.o

Database.o: Database.cpp Database.h
	$(CXX) -c -std=c++11 Database.cpp

Plsm.o: Plsm.cpp Plsm.h
	$(CXX) -c -std=c++11 Plsm.cpp

plsa.o: plsa.cpp
	$(CXX) -c -std=c++11 plsa.cpp

clean:
	rm *.o plsa

De esa forma, al ejecutar el comando make, queda compilado e instrumentado. En el caso de programas en C, como Fuzzgoat se utiliza  CC=/path/to/afl/afl-gcc ./configure

Ejecución de American Fuzzy Lop

El proceso de ejecución depende del tipo de programa. Depende de si toma los datos de entrada de stdin o de un archivo externo. En cualquier caso se requiere de unos casos de prueba en una carpeta y una carpeta de resultados. Los casos de prueba corresponde a información de entrada que se esperaría sea ingresada al programa durante su uso normal.  En el caso de que tome los datos directamente desde stdin el proceso proceso sería el siguiente:

./afl-fuzz -i carpeta_casos_prueba -o carpeta_resultados /ruta/del/programa [...parámetros...]

Las carpetas pueden estar en cualquier ubicación y el comando, por supuesto, debe ejecutarse desde una ubicación donde esté el binario afl-fuzz. Puedes copiar el binario a la carpeta del programa que estás probando. En el caso de que la entrada sea por medio de archivos, todo es igual excepto que se debe usar @@ para marcar la localización donde deberías ser colocado el archivo en la línea de comandos. 

./afl-fuzz -i carpeta_casos_prueba -o carpeta_resultados /ruta/del/programa @@

En el caso de Fuzzgoat el comando para comenzar la ejecución del proceso debe ser similar al siguiente:

./afl-fuzz -i /home/eera5607/fuzzgoat-master/in -o  /home/eera5607/fuzzgoat-master/resultados/ /home/eera5607/fuzzgoat-master/fuzzgoat @@

Dentro de la carpeta in debe estar el o los casos de prueba. Dentro de la carpeta input-files hay diferentes archivos de ejemplo para encontrar las diferentes vulnerabilidades de Fuzzgoat. Debes pasarlo a la carpeta indicada correcta. La carpeta resultados es simplemente donde van a ir los registros del proceso. Finalmente hay que indicar la ruta completa del binario que vamos a probar (esto si se copió el binario afl-fuzz a la carpeta del programa; en dicho caso no sería necesario especificar la ruta completa. 

Antes de la ejecución es posible que presente una serie de errores por las siguientes dos razones. En primer lugar el sistema puede estar configurado para enviar volcados de memoria a una utilidad externa. Esto puede provocar que un bloqueo del software (crash) se confunda con un timeout.

 

Para evitar eso, ejecuta los siguientes comandos:

sudo su
echo core >/proc/sys/kernel/core_pattern

En segundo lugar, AFL puede indicar que el gobernador de la CPU no es el óptimo (por lo general los sistemas usan on-demand por defecto y este puede obviar algunos procesos de corta vida de afl-fuzz).

Para evitar algún problema debido a este debes ejecutar los siguientes comandos:

sudo su
cd /sys/devices/system/cpu
echo performance | tee cpu*/cpufreq/scaling_governor

Ahora, el proceso debería iniciar correctamente y veríamos algo similar a esto:

Aprovechamiento de recursos

Si ves un mensaje similar al siguiente es posible que estés usando archivos de prueba muy grandes o sean repetitivos. La idea de los casos de prueba es generar una base a partir de la cual AFL pueda trabajar con su proceso de mutación de la entrada. Lo mejor para aumentar la efectividad del proceso es utilizar archivos de prueba menores a 1 KB. Los casos de prueba de la herramienta Fuzzgoat son de 1 - 2 bytes. No ayuda en nada a AFL que hayan más datos, más bien reduce las posibilidades de encontrar problemas en menor tiempo. Si vas a realizar esta técnica, por ejemplo, a un programa para comprimir fotografías que recibe archivos JPEG como entrada, no vayas a usar os recuerdos de tus vacaciones como archivos de prueba. Mas bien usa una pequeña imagen de 16x16 y la idea es la misma para casi todo tipo de documentos. Hay muchos casos de ejemplos en la carpeta testcases. 

Finalmente si quieres aprovechar todos los recursos de tu ordenador es recomendable ejecutar múltiples instancias coordinadas. No tiene sentido que ejecutes varias veces el mismo comando de ejemplo porque una instancia no sabrá lo que hace la otra. Para esto debes crear una instancia principal (master) y luego crear múltiples instancias secundarias. De esta forma el proceso estará coordinado y se estarán aprovechando correctamente los recursos. Para el caso de ejemplo debes ejecutarlo de la siguiente forma. Primero el principal:

./afl-fuzz -i /home/eera5607/fuzzgoat-master/in -o  /home/eera5607/fuzzgoat-master/resultados/ -M fuzzer01 /home/eera5607/fuzzgoat-master/fuzzgoat @@

Y después los secundarios:

./afl-fuzz -i /home/eera5607/fuzzgoat-master/in -o  /home/eera5607/fuzzgoat-master/resultados/ -S fuzzer02 /home/eera5607/fuzzgoat-master/fuzzgoat @@

./afl-fuzz -i /home/eera5607/fuzzgoat-master/in -o  /home/eera5607/fuzzgoat-master/resultados/ -S fuzzer03 /home/eera5607/fuzzgoat-master/fuzzgoat @@

./afl-fuzz -i /home/eera5607/fuzzgoat-master/in -o  /home/eera5607/fuzzgoat-master/resultados/ -S fuzzer04 /home/eera5607/fuzzgoat-master/fuzzgoat @@

...fuzzer02, fuzzer03 etc... son nombres arbitrarios para ordenar los resultados dentro de la misma carpeta resultados. Es posible ver un claro aumento del uso de CPU con respecto al ejemplo con una instancia única. 

 Eso es todo en esta guía básica de uso de American Fuzzy Lop. En un próximo artículo abordaré el análisis de los resultados obtenidos durante las pruebas. Si tienes alguna duda o consulta sobre el proceso, no dudes en hacerlo llegar por medio de los comentarios.  

Fundador
Seguidor de Jesús. Escribo artículos en mi tiempo libre sobre temas de tecnología que me interesan.