Todo sobre Fuzzing o Fuzz Testing
Todo sobre Fuzzing o Fuzz Testing

¿Qué es Fuzzing (Fuzz Testing)? Esto Necesitabas Saber

Mucha gente piensa que la “investigación de vulnerabilidades” es una tarea fácil. Dadas algunas pautas y algunas herramientas, debería ser bastante sencillo encontrar vulnerabilidades en el software. Sin embargo, todos hemos visto los informes de investigación que proclaman que un software es “seguro” a pesar de que está plagado de agujeros.

Es bastante fácil creer que la “seguridad por oscuridad” te protegerá contra cualquier tipo de ataque. De hecho, hay varias razones por las que este método no es suficiente para defender un software. (¡Las investigaciones han demostrado que un enorme 90% de todo el software tiene al menos un problema de seguridad!)

En este artículo, hablaremos sobre uno de los métodos de ataque más comunes utilizados para encontrar vulnerabilidades: fuzzing.

¿Qué es el fuzzing?

El fuzzing es una técnica que se utiliza para encontrar bugs en el software. Esencialmente, es una forma de colapsar el software para forzar al desarrollador a corregir el error. Sin embargo, es un poco más complicado.

Fuzz Testing o Fuzzing
Fuzz Testing o Fuzzing

El término Fuzzing apareció ya en 1988 en “The Fuzz Generator“, publicado por Bart Miller. Fue en esa brillante cabeza donde se le ocurrió por primera vez la idea para alimentar el programa con datos conscientemente incorrectos y a menudo aleatorios, atrapando situaciones en las que no podía procesarlas y se estrellaba. La eficacia de de este enfoque sigue siendo muy eficaz.

El objetivo del Fuzzing es pasar a un programa (me refiero a cualquier código ejecutable, biblioteca dinámica o controlador) cualquier flujo de datos no estándar para tratar de causar problemas en tiempo de ejecución.

@esgeeks

Entonces, ¿qué buscamos con Fuzzing? Se trata de una gama bastante amplia de errores de software, que incluye cosas como desbordamientos de búfer, procesamiento incorrecto de datos de usuario, diversas fugas de recursos (incluyendo el manejo de la memoria), diversos errores de sincronización, etc. Cada uno de estos sucesos es captado por el fuzzer (la herramienta) y se investiga con más detalle.

Fuzzers

Las herramientas que utilizamos para el Fuzzing se denominan fuzzers. Funcionan bombardeando las aplicaciones con todo tipo de datos y entradas procedentes de una amplia variedad de fuentes, con la esperanza de lograr que la aplicación falle o se comporte de forma inesperada.

Cabe mencionar que el fuzzing se utiliza como mecanismo de seguridad tanto ofensivo como defensivo. En el lado ofensivo, la idea es encontrar vulnerabilidades en el software como una forma de hackear un sistema. El lado defensivo, por otro lado, se utiliza para encontrar fallos en el software para parchearlos antes de que los hackers puedan hacerlo.

Ejemplo

Un ejemplo común de fuzzing es el bug heartbleed. Este es un error de seguridad que resultó en el compromiso de los servidores que utilizan la biblioteca de cifrado OpenSSL.

Estructura del fuzzing

Han pasado casi 30 años desde que se construyó el primer sistema de fuzzing. Se han introducido varias técnicas nuevas en los sistemas de fuzzing, que son cada vez más complicados.

La estructura del sistema de fuzzing original es simple, como se muestra en el marco azul discontinuo de la siguiente imagen (Fuente: A systematic review of fuzzing techniques). Las palabras vinculadas a la función del módulo son las técnicas implementadas en este módulo. La relación entre los módulos conectados por flechas rojas es de control, y la relación entre los módulos conectados por flechas negras es de transferencia de datos. El sistema contiene cinco módulos: el programa objetivo (target program), el generador de casos de prueba (test case generator), el módulo de entrega (delivery module), el detector de fallos (bug detector) y el filtro de fallos (bug filter).

Estructura del fuzzing
Estructura del fuzzing

En resumen:

  • El programa objetivo (target program) es el programa que se está probando. Puede ser un código binario con o sin código fuente, un programa de consumo de archivos o un programa de servicio de red, un programa de aplicación, un sistema operativo, un compilador, un navegador, una biblioteca, etc.
  • El generador de casos de prueba (test case generator) normalmente muta una muestra y crea una entrada para la aplicación que se va a probar. La entrada generada puede ser un tipo particular de archivo o un flujo de datos de red.
  • El módulo de entrega (delivery module) acepta muestras del generador de casos de prueba y las envía al programa de destino para su aprovechamiento.

Los encargados de las pruebas de seguridad deben dejar claro si el error/bug resultante puede ser explotado. El filtrado de las vulnerabilidades suele hacerse manualmente y, por tanto, suele requerir mucho tiempo y ser difícil de resolver.

Clasificación de fuzzing

Las técnicas de fuzzing pueden clasificarse desde múltiples perspectivas.

  • Pueden dividirse en fuzzing de caja negra, caja blanca y caja gris según la comprensión del programa objetivo.
  • En fuzzing basado en mutaciones y basado en generación según el tipo de generación de datos; y
  • en fuzzing con y sin retroalimentación según el tipo de retroalimentación.

White-box, black-box y grey-box

El fuzzing de caja negra (white-box) no tiene en cuenta la lógica interna del programa sino que proporciona continuamente datos de entrada y observa los resultados de salida resultados. El fuzzing de caja negra se encuentra en un extremo en cuanto al nivel de comprensión del programa.

En el otro extremo se encuentra el fuzzing de caja blanca (black-box), que puede obtener información detallada sobre el programa, incluyendo el código fuente, especificaciones de diseño e información detallada sobre el tiempo de ejecución. Esta información de información se utiliza para mejorar la eficiencia del proceso de proceso de fuzzing.

Entre estos dos extremos se encuentra el fuzzing de caja gris (grey-box), que obtiene cierta información pero no detalles, por ejemplo, información de cobertura en tiempo de ejecución.

Basado en la mutación y basando en generación

Existen dos técnicas principales de Fuzzing: las pruebas mutacionales y las generativas.

En las pruebas mutacionales, la generación de secuencias se basa en datos y plantillas predefinidas. Estos son los que conforman el corpus de partida del Fuzzer. Cambiando byte a byte los valores de entrada y comprobando el rendimiento del programa, el fuzzer puede sacar conclusiones sobre el éxito de ciertas “mutaciones” para generar secuencias más eficaces en la siguiente ronda.

Como puedes ver, el concepto en sí es bastante sencillo. Pero debido a que el número de iteraciones alcanza cientos y miles de millones (el tiempo de prueba es de varios días incluso en máquinas potentes), los fuzzer encuentran los errores menos triviales de los programas.

A su vez, la prueba generativa es una técnica de fase más avanzada, que implica la construcción de gramáticas de datos de entrada basadas en especificaciones. Pueden ser tanto archivos de diferentes formatos como paquetes de red en protocolos de intercambio. En este caso, nuestros resultados deben ajustarse a reglas predefinidas. Las pruebas generativas son más difíciles de aplicar que las mutacionales, pero la probabilidad de éxito en este caso es mucho mayor.

Feedback y no-feedback

La retroalimentación/feedback se refiere a si la información en tiempo de ejecución puede servir para guiar la generación del caso de prueba en el siguiente bucle. El fuzzing sin retroalimentación no obtiene ninguna información de la ejecución del programa.

Técnicas de fuzzing

Cada técnica ofrece diferentes compensaciones entre solidez integridad, velocidad, precisión, escalabilidad y nivel de automatización. Según el papel que desempeñan las técnicas de fuzzing estas técnicas pueden dividirse en tres categorías: técnicas de generación de muestras, técnicas de análisis dinámico y técnicas de de análisis estático.

Técnicas de generación de muestras

Las técnicas de generación de muestras se utilizan para seleccionar y mutar semillas y para restringir y generar nuevas muestras. Estas técnicas se implementan en el generador de casos de prueba e incluyen tres tipos principales:

Mutación aleatoria

La idea central de la mutación aleatoria es generar nuevas entradas a partir de una semilla preparada mutando aleatoriamente algún campo. Estas muestras generadas se introducen en un programa, que luego se vigila para detectar los fallos que puedan que puedan producirse.

Representación gramatical

La técnica de mutación aleatoria no es eficiente para encontrar errores profundos en el programa objetivo debido a su emisión ciega de datos aleatorios. La mayoría de los casos de prueba son rechazados en los primeros pasos de la ejecución del programa en el análisis sintáctico o la verificación de la suma de comprobación. La técnica de representación gramatical supera este problema utilizando la gramática para restringir la estructura de datos del caso de prueba.

Algoritmos de programación

Los algoritmos de programación son métodos factibles para maximizar el resultado del fuzzing utilizando una estrategia optimizada de elección y mutación de semillas. Estos algoritmos pueden mejorar la eficiencia del fuzzing, pero no pueden resolver el problema básico del fuzzing.

Técnicas de análisis dinámico

Las técnicas de análisis dinámico se utilizan para obtener información dinámica sobre el programa en ejecución para ayudar a generar la nueva muestra.

Ejecución simbólica dinámica

La ejecución simbólica dinámica es un método para determinar las posibles entradas de un programa. Esta tarea se lleva a cabo utilizando valores simbólicos como entrada para ejecutar el programa

Retroalimentación de cobertura

La técnica de retroalimentación de cobertura se utiliza para generar entradas para atravesar diferentes rutas en la ejecución del programa. Utiliza la instrumentación para obtener información sobre la cobertura de la ruta en el programa en ejecución.

Análisis dinámico Taint

El Dynamic taint analysis se utiliza para inferir las propiedades estructurales de los datos de entrada y qué desviaciones de la entrada influyen en las condiciones de la rama. Esta información puede utilizarse para elegir y mutar las semillas de forma eficiente.

El análisis dinámico de taint ejecuta el programa objetivo alimentándolo con datos de entrada con etiquetas, que pueden utilizarse para especificar cómo el programa utiliza los datos de entrada y qué elementos del programa fueron contaminados por los datos.

Técnicas de análisis estático

El análisis estático incluye el análisis del flujo de control y los cortes de flujo de datos. Ambas técnicas se utilizan para localizar, dirigir la ejecución y verificar de forma eficiente las posibles vulnerabilidades.

Aunque el análisis estático suele producir resultados falsos positivos, puede combinarse con otros enfoques para obtener información de preprocesamiento muy valiosa.

¿Qué pasa con los fuzzers web?

Fuzzing para Aplicaciones Web
Fuzzing para Aplicaciones Web

Deliberadamente no he mencionado en este artículo los llamados fuzzers basados en la web que trabajan a nivel de HTTP y sobrecargan el servidor web con peticiones especialmente creadas en busca de errores en las aplicaciones web.

En el caso de que se trate de aplicaciones web, es posible que se desee realizar fuzzing a los parámetros POST y GET, las cabeceras y las cookies (como hemos visto en ejemplos anteriores, utilizando ffuf).

Ya se ha dicho que uno de los principales objetivos del fuzzing es buscar comportamientos anómalos. Este comportamiento puede manifestarse de diversas formas:

  • Errores en la respuesta del servidor web;
  • Cambios en la longitud de la respuesta (no siempre es la causa del error, pero es una buena razón para entender que algo ha sido afectado);
  • Errores en la lógica de la aplicación;
  • Cambios en las cabeceras de respuesta;
  • Además, el comportamiento anómalo puede manifestarse de las siguientes formas: respuestas especialmente generadas, aumento del tiempo de respuesta, redireccionamiento, desaparición de algún contenido de la página, etc. Estas anomalías requieren una investigación más profunda para comprender su verdadera causa.

Si hablamos de plataformas universales para fuzzers, es una pena no mencionar el framework Sulley, que se presentó en Blackhat en 2007. Desgraciadamente, desde entonces no ha recibido actualización pero, a pesar de ello, sigue siendo una solución eficaz.

Herramientas para Fuzzing Web

Burp Intruder es una poderosa herramienta fuzzer para realizar ataques personalizados automatizados contra aplicaciones web. Es extremadamente flexible y configurable, y se puede utilizar para automatizar todo tipo de tareas que surgen al probar aplicaciones. Muy útil para buscar vulnerabilidades en aplicaciones web.

Entre otras herramientas tenemos:

Métodos de protección contra Fuzzing

Aunque la práctica del fuzzing es útil para descubrir errores, existen algunos métodos para mitigar los efectos del fuzzing:

  • Filtrar los datos procedentes del usuario (todo parámetro que pueda ser afectado por el usuario debe someterse a un filtrado);
  • Desactivar la depuración (desactivará la salida de errores, lo que dificultará el seguimiento de las anomalías);
  • Investigación exhaustiva de la lógica de la aplicación;
  • Delimitación correcta del acceso.

Conclusión

El fuzzing es una forma extremadamente útil de encontrar fallos en el software que no pueden detectarse con los métodos estándar. Esto lo convierte en una herramienta crítica en la caja de herramientas de seguridad. Con este conocimiento, estarás más equipado para asegurar tu sistema.

Mi Carro Close (×)

Tu carrito está vacío
Ver tienda