
Marco de análisis estático que identifica objetivos de funciones fuzzeables en código fuente y binarios, genera plantillas de harness y se integra con AFL++ y libFuzzer para el descubrimiento automatizado de vulnerabilidades.
Marco para automatizar el descubrimiento de objetivos Fuzzable mediante análisis estático

Los investigadores de vulnerabilidades que realizan evaluaciones de seguridad a menudo aprovechan las capacidades del fuzzing guiado por cobertura mediante herramientas potentes como AFL++ y libFuzzer. Esto es importante ya que automatiza el proceso de búsqueda de errores y revela rápidamente condiciones explotables en los objetivos. Sin embargo, al encontrarse con bases de código grandes y complejas o binarios de código cerrado, los investigadores tienen que dedicar tiempo minuciosamente para auditar manualmente y aplicar ingeniería inversa para identificar funciones donde la exploración basada en fuzzing puede ser útil.
Fuzzable es un marco que se integra tanto con código fuente C/C++ como con binarios para ayudar a los investigadores de vulnerabilidades a identificar funciones objetivo que son viables para el fuzzing. Esto se logra aplicando varias heurísticas basadas en análisis estático para señalar comportamientos riesgosos en el software y las funciones que los ejecutan. Los investigadores pueden entonces utilizar el marco para generar plantillas básicas de harness, que luego pueden ser usadas para buscar vulnerabilidades, o integrarse como parte de un pipeline de fuzzing continuo, como el proyecto oss-fuzz de Google.
Además de ejecutarse como herramienta independiente, Fuzzable también está integrado como plugin para el desensamblador Binary Ninja, con soporte para otros backends de desensamblaje en desarrollo.
Consulte la publicación original del blog que detalla la herramienta aquí, que destaca las especificaciones técnicas de las heurísticas de análisis estático y cómo surgió esta herramienta. Esta herramienta también se presenta en Black Hat Arsenal USA 2022.
Algunos objetivos binarios pueden requerir cierta sanitización (por ejemplo, coincidencia de firmas o identificación de funciones a partir de inlining), por lo tanto, fuzzable utiliza principalmente Binary Ninja como backend de desensamblaje debido a su capacidad para resolver estos problemas de manera efectiva. Por lo tanto, puede utilizarse tanto como herramienta independiente como plugin.
Dado que Binary Ninja no es accesible para todos y puede haber demanda para su uso en evaluaciones de seguridad y posiblemente escalar en la nube, también se admite un backend alternativo angr. Anticipo incorporar otros desensambladores más adelante (prioridad: Ghidra).
Si tiene Binary Ninja Commercial, asegúrese de instalar la API para uso independiente sin interfaz gráfica:
$ python3 /Applications/Binary\ Ninja.app/Contents/Resources/scripts/install_api.py
Instale con pip:
$ pip install fuzzable
Usamos poetry para la gestión de dependencias y compilación. Para hacer una compilación manual, clone el repositorio con los módulos de terceros:
$ git clone --recursive https://github.com/ex0dus-0x/fuzzable
Para instalar manualmente:
$ cd fuzzable/
# sin poetry
$ pip install .
# con poetry
$ poetry install
# con poetry para un virtualenv de desarrollo
$ poetry shell
Ahora puede analizar binarios y/o código fuente con la herramienta:
# analizando un solo binario de biblioteca compartida
$ fuzzable analyze examples/binaries/libbasic.so
# analizando un solo archivo fuente C
$ fuzzable analyze examples/source/libbasic.c
# analizando un espacio de trabajo con múltiples archivos C/C++ y encabezados
$ fuzzable analyze examples/source/source_bundle/
fuzzable se puede instalar fácilmente a través del mercado de plugins de Binary Ninja yendo a Binary Ninja > Manage Plugins y buscándolo. Aquí hay un ejemplo del plugin fuzzable en ejecución, identificando con precisión objetivos para fuzzing y evaluación adicional de vulnerabilidades:

fuzzable viene con varias opciones para ayudar a ajustar mejor su análisis. Se admitirán más en planes futuros y en cualquier solicitud de funciones que se realicen.
Para determinar la fuzzabilidad, fuzzable utiliza varias heurísticas para determinar qué objetivos son los más viables para apuntar en el análisis dinámico. Estas heurísticas están ponderadas de manera diferente usando la biblioteca scikit-criteria, que utiliza el análisis de decisión multicriterio para determinar los mejores candidatos. Estas métricas y sus pesos se pueden ver aquí:
Como se mencionó, consulte la publicación técnica del blog para una visión más profunda de por qué y cómo se utilizan estas métricas.
Muchas métricas se inspiraron en gran medida en el trabajo original de Vincenzo Iozzo sobre fuzzing de 0 conocimiento.
Cada objetivo que desea analizar es diverso, y fuzzable no podrá tener en cuenta todos los comportamientos de casos extremos en el programa objetivo. Por lo tanto, puede ser importante durante el análisis ajustar estos pesos apropiadamente para ver si diferentes resultados tienen más sentido para su caso de uso. Para ajustar estos pesos en la CLI, simplemente especifique el argumento --score-weights:
$ fuzzable analyze <TARGET> --score-weights=0.2,0.2,0.2,0.2,0.2
Por defecto, fuzzable filtrará las funciones objetivo según los siguientes criterios:
static y no están expuestas a través de encabezados.Para ver las llamadas que fueron filtradas por fuzzable, establezca el flag --list_ignored:
$ fuzzable analyze --list-ignored <TARGET>
En Binary Ninja, puede activar esta opción en Settings > Fuzzable > List Ignored Calls.
En caso de que fuzzable filtre falsamente llamadas importantes que deberían analizarse, se recomienda usar los argumentos --include-* para incluirlas durante la ejecución:
# incluir TODAS las llamadas no de nivel superior que fueron filtradas
$ fuzzable analyze --include-nontop <TARGET>
# incluir símbolos específicos que fueron filtrados
$ fuzzable analyze --include-sym <SYM> <TARGET>
En Binary Ninja, esto se admite a través de Settings > Fuzzable > Include non-top level calls y Symbols to Exclude.
Ahora que ha encontrado sus candidatos ideales para fuzzear, fuzzable también le ayudará a generar harnesses de fuzzing que están (casi) listos para instrumentar y compilar para usar con un fuzzer basado en archivos (ej. AFL++, Honggfuzz) o un fuzzer en memoria (libFuzzer). Para hacerlo en la CLI:
# generar harness a partir de un candidato
$ fuzzable create-harness target --symbol-name=some_unsafe_call
# hacer modificaciones mínimas y necesarias al harness
$ vim target_some_unsafe_call_harness.cpp
# ejemplo de compilación para AFL-QEMU, que se especifica en los comentarios del harness generado
$ clang target_some_unsafe_call_harness.cpp -no-pie -o target_some_unsafe_call_harness -ldl
# crear sus semillas base, idealmente deberían estar mejor formadas para la entrada
$ mkdir in/
$ echo "seed" >> in/seed
# iniciar fuzzing de caja negra
$ afl-fuzz -Q -m none -i in/ -o out/ -- ./target_some_unsafe_call_harness
Si este objetivo es una base de código fuente, se utilizará la plantilla de código fuente genérica.
Si el objetivo es un binario, se utilizará la plantilla genérica de caja negra, que idealmente puede usarse con un modo de emulación de fuzzing como AFL-QEMU. También se creará una copia del binario como un objeto compartido si el símbolo no se exporta directamente para ser dlopen utilizando LIEF.
Por el momento, esta característica es bastante rudimentaria, ya que simplemente creará un harness C++ independiente poblado con los parámetros apropiados, y no generará automáticamente código necesario para comportamientos en tiempo de ejecución (por ejemplo, instanciar y liberar estructuras). Sin embargo, las plantillas creadas para fuzzable deberían permitirle comenzar rápidamente de todos modos. Aquí hay algunas características ambiciosas que me gustaría implementar en el futuro:
fuzzable admite la generación de informes en varios formatos. Los actuales compatibles son JSON, CSV y Markdown. Esto puede ser útil si está utilizando esto como parte de una automatización donde desea ingerir la salida en un formato serializable.
En la CLI, simplemente pase el argumento --export con un nombre de archivo con la extensión adecuada:
$ fuzzable analyze --export=report.json <TARGET>
En Binary Ninja, vaya a Plugins > Fuzzable > Export Fuzzability Report > ... y seleccione el formato al que desea exportar y la ruta donde escribirlo.
Esta herramienta se desarrollará continuamente, ¡y se agradece cualquier ayuda de mantenedores externos!
Fuzzable está licenciado bajo la Licencia MIT.
| Heurística | Descripción | Peso |
|---|
| Fuzz Friendly Name | El nombre del símbolo implica un comportamiento que ingiere entrada de archivo/búfer | 0.3 |
| Risky Sinks | Argumentos que fluyen hacia llamadas riesgosas (ej. memcpy) | 0.3 |
| Natural Loops | Número de bucles detectados con la frontera de dominancia | 0.05 |
| Cyclomatic Complexity | Complejidad del objetivo de función basada en aristas + nodos | 0.05 |
| Coverage Depth | Número de funciones llamadas que el objetivo atraviesa | 0.3 |