AFL (American Fuzzy Lop) es una herramienta de prueba difusa basada en Cobertura guiada desarrollada por el investigador de seguridad Michał Zalewski. Al registrar la cobertura del código de las muestras de entrada, la entrada se muta continuamente para lograr una mayor cobertura del código. AFL utiliza un nuevo tipo de instrumentación en tiempo de compilación y algoritmo genético para descubrir automáticamente nuevos casos de prueba que desencadenarán nuevos estados internos en el binario objetivo. Esto mejora en gran medida la cobertura del código de las pruebas fuzz. 1
- Inserte el instrumento al compilar el programa del código fuente para registrar la cobertura del código (Cobertura del código);
- Seleccione algunos archivos de entrada para unirse a la cola de entrada como el conjunto de prueba inicial;
- Mutar los archivos en la cola de acuerdo con una determinada estrategia ";
- Si la cobertura se actualiza a través del archivo de mutación, se mantendrá y se agregará a la cola;
- El proceso anterior continuará circulando y se grabará el archivo que provocó el bloqueo.
0x10 instalar afl
Elija una de las siguientes tres versiones (se recomienda la segunda. He probado las tres. En modo afl normal, no hay problema con las tres. Pero cuando se trata de un uso más profundo, hay algunos errores; segunda Esta es una versión relativamente buena)
AFLplusplus introduce un algoritmo de compilación más fuerte.Si se inserta el código fuente, AFLplusplus es más adecuado. Ingrese al proyecto descargado, instale afl, el comando es el siguiente
make # 编译 afl
sudo make install
Esta es una captura de pantalla de una compilación exitosa
0x20 compilar el programa bajo prueba (prueba de caja blanca)
El propósito de usar AFL para compilar el código fuente de destino es insertar instrumentación para que el programa compilado pueda ser cubierto por la ruta de retroalimentación. AFL viene con versiones personalizadas de compiladores gcc y clang, se recomienda elegir el compilador clang de LLVM, que puede acelerar la velocidad de fuzz .
0x21 Use afl-gcc para la inserción del código fuente
Para un solo archivo, solo use afl-gcc en lugar de gcc
afl-gcc test.c -o test
Para un proyecto completo, debe especificar el compilador como afl-gcc y luego compilar
./configure CC="afl-gcc" CXX="afl-g++" # 或者直接修改 Makefie 文件,将编译器改位 afl-gcc
make
Si necesita biblioteca compartida pelusa , puede configurar LD_LIBRARY_PATH
el programa para cargar archivos .so instrumentados a través de la AFL, pero la forma más fácil es construir una estática, logrado por
./configure --disable-shared CC="afl-gcc" CXX="afl-g++"
0x22 Utilice el modo LLVM para instrumentación de código fuente
AFL también admite el uso del modo LLVM, que puede obtener una velocidad de fuzz más rápida y tiene más opciones. La representación frontal de LLVM es el compilador clang, por lo que debe instalar clang usted mismo y luego puede compilar
afl-clang test.c -o test
Error 0x23 al cargar bibliotecas compartidas error 2
Una vez completada la compilación, puede producirse el siguiente error. Esto se debe a que el compilador solo usará los archivos de la biblioteca en los dos directorios / lib y / usr / lib de forma predeterminada . Instale el programa mediante la compilación del código fuente. Si no se especifica --prefix
, la biblioteca se instalará en el /usr/local/lib
directorio; cuando ejecute el programa, debe vincular Cuando se muestra la biblioteca dinámica, indica que no se puede encontrar la biblioteca .so relevante y se informará un error. En otras palabras, el directorio / usr / local / lib no está en el directorio de búsqueda de biblioteca predeterminado del sistema, y el directorio debe agregarse.
Solución
- Abrir
/etc/ld.so.conf
archivo - Agregue el directorio donde se encuentra el archivo de biblioteca dinámica: ejecutar
vi /etc/ld.so.conf
,include ld.so.conf.d/*.conf"
agregue en ""/usr/local/lib"
- Después de guardar, ejecutar el terminal de línea de comandos:
/sbin/ldconfig -v
; su papel es el de archivo de/etc/ld.so.conf
almacenamiento en caché de archivo de biblioteca en la ruta que se muestra a/etc/ld.so.cache
para su uso, por lo que al instalar algunas de las bibliotecas, o modificaretc/ld.so.conf
añadido una nueva ruta de búsqueda de biblioteca, consiguió correr ldconfig, de modo que todos los archivos de la biblioteca se almacenan en caché en el archivo/etc/ld.so.cache
, si no se hace, que no podía encontrar las librerías recién instaladas.
0x30 seleccione corpus
De hecho, es para alimentar el programa de prueba con casos de prueba apropiados. Afl generará una gran cantidad de casos de uso basados en estas semillas y mutaciones originales. En condiciones ideales, el corpus proporcionado (es decir, el caso de prueba original) puede permitir que el programa ejecute diferentes rutas , para maximizar la cobertura del código.
0x31 Seleccionar caso de uso
Aquí, tomando prestados los materiales proporcionados por Freebuf, proporcione algunos corpus de código abierto
- conjuntos de prueba de imagen generados por AFL
- conjunto de prueba de fuzzer
- muestras de libav
- muestras de ffmpeg
- fuzzdata
- luz de la luna
De hecho, muchos programas también traerán algunos casos, que también pueden usarse como casos de prueba.
Cuerpo condensado 0x32
Después de encontrar el corpus, es mejor poder recortar, fusionar casos de uso repetidos y recortar el volumen. afl El volumen de casos de uso recomendado es inferior a 1 KB , de lo contrario, afectará la eficiencia de fuzz.
Deduplicación
afl-cmin
Es una herramienta muy útil proporcionada por afl, que puede racionalizar el corpus y eliminar posibles casos de prueba duplicados. Es muy útil para algunos cuerpos complejos y puede reducir en gran medida los casos de uso de fuzz inútiles.
afl-cmin -i input_dir -o output_dir -- /path/to/tested/program [params]
Más a menudo, recibimos información del archivo, por lo que a menudo usamos @@ en lugar de parámetros (parámetros), es decir
afl-cmin -i input_dir -o output_dir -- /path/to/tested/program @@
Reducir el volumen
afl-tmin
El tamaño del archivo se puede acortar, porque afl requiere que el tamaño de los casos de prueba sea preferiblemente inferior a 1 KB, por lo que es mejor reducir aún más el tamaño de los casos de uso simplificados. afl-tmin tiene dos modos de trabajo instrumented mode
y crash mode
. El modo de trabajo predeterminado es el modo instrumentado.
afl-tmin -i input_file -o output_file -- /path/to/tested/program [params] @@
Debido a que afl-cmin solo puede simplificar un solo archivo a la vez, si hay muchos casos de uso, lleva mucho tiempo manualmente, de hecho, se puede completar un script de shell simple
for i in *; do afl-tmin -i $i -o tmin-$i -- ~/path/to/tested/program [params] @@; done;
0x40 fuzzing
Antes de programa formalmente de la pelusa, se puede utilizar afl-map
para rastrear una sola ruta de ejecución con la forma de realización, se imprima y procedimientos tuplas de salida
afl-showmap -m none -o /dev/null
El comando para ejecutar formalmente la prueba fuzz es el siguiente
afl-fuzz -m none -i in -o out target_binary @@
Fuzz de caja negra 0x50
El proceso fuzz anterior depende del código fuente del programa que tenemos, y la instrumentación se lleva a cabo durante el proceso de compilación, pero muchas veces no tenemos el código fuente, en este momento confiamos en el modo qemu_mode provisto por afl. La versión original del modo afl qemu es demasiado antigua para ejecutarse normalmente. Se recomienda usar AFLplusplus o afl-unicorn en github . AFLplusplus
Más fácil de instalar y afl-unicorn
más fácil de usar para el modo de qemu.
No importa qué versión de afl se descargue, habrá una carpeta qemu_mode en el directorio raíz, ingrese este directorio, ejecute el siguiente script, si no hay error, significa que qemu_mode se realizó correctamente
cd qemu_mode
sudo ./build_qemu_support.sh
Si hay un error, visite: Análisis en profundidad de los problemas de compilación e instalación de afl / qemu-mode (qemu mode) / afl-unicorn y las soluciones correspondientes
Si desea hacer un recuadro negro de archivos binarios fuzz de diferentes arquitecturas, debe especificar la arquitectura correspondiente antes de compilar el script qemu . Por ejemplo, para ejecutar el programa de arquitectura fuzz arm bajo la arquitectura x86, debe ejecutar el siguiente comando
CPU_TARGET=arm ./build_qemu_support.sh
Después de que la compilación sea exitosa, puede realizar fuzz box negro
afl-fuzz -Q -m none -i in -o out target_binary @@
Análisis de combate real 0x60
Análisis de código fuente 0x61
Escribe una demostración, por ejemplo. Aquí, para reflejar la función de instrumentación del af, varias si las ramas se escriben intencionalmente. En la profundidad de la rama, se producirá un desbordamiento de la pila.
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/fcntl.h>
int main(int argc, char const *argv[])
{
if(argc != 2)
{
printf("null args!\n");
return -1;
}
/* Get file state */
struct stat fstat;
if(stat(argv[1], &fstat))
{
printf("Failed ^_^\n");
return -1;
}
/* Open file */
FILE * fd = NULL;
fd = open(argv[1], O_RDONLY);
if(fd == -1)
{
printf("open file failed!\n");
return -1;
}
/* Select */
char buf[15];
if(read(fd, buf, 2) == -1)
{
printf("read failed!");
return -1;
}
if(buf[0] == 'a' && buf[1] == 'b')
{
if(read(fd, buf, 4) != -1)
{
if(buf[2] == 's')
{
read(fd, buf, fstat.st_size - 6);
printf("%s\n", buf);
}
}
}
return 0;
}
Inserción de código fuente 0x62
Compile con el modo LLVM de afl, es decir, instrumente el código fuente
afl-clang afl_demo.c -o afl_demo
Cada instrucción if representa cada rama condicional, y lo que aparece en la ventana de desmontaje de IDA es un bloque básico. Una declaración if es una nueva rama. Como se muestra a continuación, usamos afl-clang para compilar el código desensamblado. Como puede ver, en cada declaración if, se ha instrumentado automáticamente. Es _afl_maybe_log
una función de instrumentación que se utiliza para retroalimentar la ruta.
0x63 Generar corpus
Cree un nuevo directorio en, cree un nuevo archivo en el directorio, escriba una semilla, y el algoritmo de mutación generará varios casos de prueba basados en esta mutación semilla y lo alimentará al programa, como escribir la siguiente información (de acuerdo con el código, cuando el primer carácter es un, el segundo Los caracteres son b, el quinto carácter es s, puede producirse un desbordamiento)
abttdcccccccccccccccccccccccccaaaaaaaaaaaaaaaaaaaaaaadddddddddddddddddddddddddddd
0x64 comenzar a difuminar
root@lys-virtual-machine:~/Documents/test# afl-fuzz -m none -i in -o out ./afl_demo @@
afl-fuzz++2.60d based on afl by Michal Zalewski and a big online community
[+] afl++ is maintained by Marc "van Hauser" Heuse, Heiko "hexcoder" Eißfeldt and Andrea Fioraldi
[+] afl++ is open source, get it at https://github.com/vanhauser-thc/AFLplusplus
[+] Power schedules from github.com/mboehme/aflfast
[+] Python Mutator and llvm_mode whitelisting from github.com/choller/afl
[+] afl-tmin fork server patch from github.com/nccgroup/TriforceAFL
[+] MOpt Mutator from github.com/puppet-meteor/MOpt-AFL
[*] Getting to work...
[+] Using exploration-based constant power schedule (EXPLORE)
[+] You have 8 CPU cores and 2 runnable tasks (utilization: 25%).
[+] Try parallel jobs - see /usr/local/share/doc/afl/parallel_fuzzing.md.
[*] Checking CPU core loadout...
[+] Found a free CPU core, try binding to #0.
[*] Checking core_pattern...
[!] WARNING: Could not check CPU scaling governor
[*] Setting up output directories...
[+] Output directory exists but deemed OK to reuse.
[*] Deleting old session data...
[+] Output dir cleanup successful.
[*] Scanning 'in'...
[+] No auto-generated dictionary tokens to reuse.
[*] Creating hard links for all input files...
[*] Validating target binary...
[*] Attempting dry run with 'id:000000,time:0,orig:testcases.txt'...
[*] Spinning up the fork server...
[+] All right - fork server is up.
len = 81, map size = 9, exec speed = 199 us
[+] All test cases processed.
[+] Here are some useful stats:
Test case count : 1 favored, 0 variable, 1 total
Bitmap range : 9 to 9 bits (average: 9.00 bits)
Exec timing : 199 to 199 us (average: 199 us)
[*] No -t option specified, so I'll use exec timeout of 20 ms.
[+] All set and ready to roll!
En la ventana de fuzz,
puede ver que se ha producido un bloqueo. Cuando los ciclos realizados son de color verde, significa que se puede detener el fuzz.
Análisis de resultados 0x65
Analicemos los resultados, de acuerdo con los comandos ingresados durante fuzz, nuestros resultados se muestran en el directorio de salida
root@lys-virtual-machine:~/Documents/test/out# tree
.
├── cmdline
├── crashes
│ ├── id:000000,sig:11,src:000001,time:600493+000003,op:splice,rep:64
│ ├── id:000001,sig:11,src:000003,time:600898,op:havoc,rep:64
│ └── README.txt
├── fuzz_bitmap
├── fuzzer_stats
├── hangs
├── plot_data
└── queue
├── id:000000,time:0,orig:testcases.txt
├── id:000001,src:000000,time:3,op:flip1,pos:0,+cov
├── id:000002,src:000000,time:6,op:flip1,pos:1,+cov
└── id:000003,src:000000,time:3406,op:havoc,rep:2,+cov
3 directories, 11 files
- accidentes : casos de prueba únicos que hacen que el objetivo se bloquee con una señal fatal
- fuzzer_stats: estado de ejecución de afl-fuzz
- se bloquea: casos de prueba únicos que hacen que el objetivo agote el tiempo de espera
- plot_data: se usa para el trazado afl-plot
- cola: almacena todos los casos de prueba con rutas de ejecución únicas
afl-plot puede dibujar resultados más intuitivos, utilizando el archivo plot_data generado por el fuzzer. Por supuesto, para usar afl-plot, necesita instalarapt-get install gnuplot
root@lys-virtual-machine:~/Documents/test# afl-plot out result/
progress plotting utility for afl-fuzz by Michal Zalewski
[*] Generating plots...
[*] Generating index.html...
[+] All done - enjoy your charts!
De esta manera, puede generar archivos html y de imágenes en el directorio de resultados, como se muestra a continuación
- La primera imagen: cuando la cobertura de ruta cambia, el número de favoritos pendientes se convierte en cero, y el número de rutas totales básicamente no ha aumentado, significa que es menos probable que el fuzzer encuentre nuevas.
- Crash y cambios de tiempo de espera
- Cambios en la velocidad de ejecución.
Para encontrar el error nuevamente, simplemente ingrese el caso de prueba en el directorio de bloqueo.
Resumen 0x70
Como una excelente herramienta de fuzz, AFL calcula la cobertura del código a través de la inserción del código fuente, y luego utiliza esto como base para mutar continuamente el corpus (archivo semilla) para lograr el efecto de aumentar la cobertura del código. Este artículo explica principalmente su uso general, y su más eficiente es también la inserción del código fuente en modo LLVM, combinado con ejemplos específicos, para realizar pruebas fuzz. Para archivos binarios compilados a partir de código C / C ++, aunque AFL también proporciona fuzzbox de fuente negra sin fuente basada en qemu, la eficiencia es baja y la posibilidad de encontrar vulnerabilidades es pequeña. Por lo tanto, es mejor usar el modelo general de AFL, es decir, la prueba fuzz basada en la instrumentación del código fuente.
En el caso de que no haya código fuente, si desea utilizar la instrumentación binaria directamente, debe instalar qemu-mode o unicornio. Puede haber muchos problemas con la instalación. Bienvenido a otro blog: análisis en profundidad de afl / qemu-mode (qemu mode) / Problemas de compilación e instalación de afl-unicornio y soluciones correspondientes .