Facilidad de Automatización para Fuzzing

Body

La automatización para el proceso de pruebas puede ser muy simple o muy duro, dependiendo esto de la aplicación a evaluar. Algunas aplicaciones proporcionan diversos mecanismos, como funciones API exportadas, y capacidades de “scripting”, lo cual facilita la automatización. En casos donde tales capacidades no están disponibles, es posible utilizar herramientas dedicadas y especializadas en automatización de software. En diferentes escenarios, las herramientas específicas para automatización pueden simplificar el proceso de “Fuzzing”, haciéndolo más fácil de realizar. Antes de seleccionar o utilizar las herramientas, se debe tener una lista de requerimientos para la automatización del software de destino. Las referencias cruzadas de la lista de requerimientos con la funcionalidad ofrecida por cada solución, debe proporcionar la mejor herramientas para el trabajo.

A continuación algunas consideraciones para elegir un software de automatización.

  • Precio y licencias. En escenarios de “Fuzzing” distribuidos, una única licencia de software de computadora, puede no ser suficiente para implementar el software en una granja de Fuzzing compuesta de muchas computadoras o máquinas virtuales. Diferentes soluciones utilizan diferentes precios y esquemas de licenciamiento, por lo cual si el presupuesto es preponderante, este debe ser el primer filtro.
  • Lenguaje de automatización. Algunas herramientas para automatización utilizan lenguajes de “script” conocidos como LUA o Phyton, mientras otros usan lenguajes propietarios o archivos de configuración personalizados. Dependiendo del lenguaje, el tiempo para implementar y desarrollar un script para automatización puede variar bastante, así seleccionar un lenguaje familiar o estilo de configuración, puede ayudar a acelerar el proceso. Sin embargo, los idiomas personalizados no deben ser ignorados fácilmente, pues el tiempo en aprender un nuevo lenguaje puede ser beneficioso a largo plazo, siempre y cuando se requiera menos tiempo de desarrollo y ofrezca más flexibilidad. Una regla de otro es preferir soluciones requiriendo menos codificación.
  • Velocidad. Este requisito puede algunas veces ser pasado por alto cuando se compara el software para automatización, porque todos pueden parecer instantáneos. Dependiendo de la escala del “Fuzzig”, la velocidad de automatización puede poseer un problema significativo para lograr un alto número de pruebas realizadas. Realizar la ejecución de pruebas sobre candidatos de automatización en miles de muestras, y comparar su velocidad de ejecución puede ayudar a seleccionar la mejor.

Algunas soluciones populares para automatización son las siguientes:

  • Selenium. Un framework de automatización para el navegador, el cual puede ser utilizado para probar aplicaciones web, como también navegadores. Soporta dos tipos de automatización. Selenium IDE y Selenium WebDriver
  • AutoIt. Este software popular soporta la escritura de scripts para automatización para los sistemas operativos Windows, en un lenguaje de scripting similar al BASIC. La simplicidad de este lenguaje de scripting, acompañado de muchos recursos y documentación de su uso, lo hace un candidato muy popular. Este software podría ser una buena elección para cualquier tipo de automatización en Windows.
  • Expect. Un programa el cual es capaz de comunicarse con otros programa interactivos, y automatizar la interacción en Linux. El lenguaje de configuración Expect soporta TCL, pero también algunos comandos específicos de Expect. También la librería “libexpect” expone la funcionalidad de Expect hacia C/C++

Fuentes:

https://www.seleniumhq.org/
https://www.seleniumhq.org/projects/ide/
https://www.seleniumhq.org/projects/webdriver/
https://www.autoitscript.com/site/
https://linux.die.net/man/1/expect

Tipos de Entradas para Fuzzing

Body

Una distinción importante entre los objetivos de evaluación, es la capacidad en lo referente a su interfaz, lo cual dicta la facilidad de automatización para el proceso de Fuzzing. Las interfaces simples, como pasar comandos sobre una línea de comandos, son más fáciles de utilizar y automatizar, comparado con aplicaciones las cuales únicamente aceptan comandos desde su interfaz gráfica de usuario. Diferentes tipo de interfaces pueden también dictar la disponibilidad de las estrategias de Fuzzing y parámetros de configuración, lo cual resulta en ya sea un Fuzzing más fácil o más complicado.

Se debe anotar también las aplicaciones pueden tener soporte para múltiples tipos de entradas, de tal manera es importante distinguir entre cada una de ellas, y tener en consideración únicamente aquellas siendo de interés para nuestros propósitos de prueba. Un ejemplo de software el cual usualmente soporta entradas desde diferentes tipos de fuentes son los reproductores de medios. Una manera de utilizarlos es para reproducir música desde un archivo local almacenado en un dispositivo de almacenamiento; otro podría ser estaciones de radio a través de Internet. Dependiendo del tipo de entrada (archivo versus audio en red), una configuración diferente de Fuzzing podría ser requerida. También, se debe mencionar la complejidad de las pruebas de Fuzzing para estos dos tipos de entradas son diferentes. El hacer Fuzzing de archivos típicamente es más fácil comparado con Fuzzing a protocolos de red, esto porque la red añade otra capa entre los datos generados y la aplicación. Esta capa adicional incrementa la complejidad y puede influenciar las pruebas, además de hacer la reproducción de vulnerabilidades más difícil.

A continuación se mencionan algunos tipos comunes de interfaces para entradas.

  • Red (Por ejemplo, protocolo HTTP)
  • Linea de comandos (Por ejemplo, herramientas shell)
  • Entrada de archivo (Por ejemplo, reproductores de medio)

Fuentes:

https://en.wikipedia.org/wiki/Fuzzing
https://www.owasp.org/index.php/Fuzzing
https://www.mwrinfosecurity.com/our-thinking/15-minute-guide-to-fuzzing/
https://www.guru99.com/fuzz-testing.html

Seleccionar un Objetivo para Fuzzing

Body

El primer paso relacionado con un proyecto para realizar un “Fuzzing”, implica decidir cual será el objetivo de evaluación. En aquellos escenarios donde el objetivo puede ser elegido de manera arbitraria, es una buena idea el tratar de maximizar las probabilidades de encontrar una funcionalidad en donde sea factible realizar el procedimiento de “Fuzzing”.

Algo heurístico puede ser utilizado para realizar la evaluación de los objetivos basados en función de potencial “Fuzzing”. A continuación se detalla una lista de algunos temas heurísticos interesantes.

  • Soporte para diferentes tipos de entadas. Asegura la existencia de desviación suficiente entre los tipos de entradas, de tal manera si uno resulta difícil de probar, los otros podrían ser examinados y utilizados.
  • Fácil automatización. Permite al programa objetivo ser fácilmente y programáticamente automatizado para propósitos de las pruebas. Esto usualmente significa el programa puede ser manipulado de tal manera permita la ejecución automática de los casos de prueba generados por un “fuzzer”.
  • Complejidad del software. Comúnmente utilizado como heurística para determinar la probabilidad del software contenga una falla. Esto se debe a la premisa de cosas complejas son más probables de contener errores debido a la cantidad de trabajo necesario para verificar y probar su corrección. Por lo tanto, programas interpretando formatos de archivos soportan muchas opciones y parámetros, siendo más propensos a contener problemas relacionados a la seguridad, porque son más difíciles de entender, y por lo tanto más difíciles de revisar y verificar por fallas.

Fuentes:

https://obj.umiacs.umd.edu/acm_ccs18/Fuzz_testing_CCS18.pdf
http://lcamtuf.coredump.cx/afl/
https://groups.google.com/forum/#!topic/libfuzzer/PSPeG1rmtY4

Introducción al Fuzzing

Body

Una de las maneras más rápidas de entrar en la investigación de vulnerabilidades, es a través de las pruebas de software. Las pruebas tradicionales de software de tipo caja negra, son interesantes desde la perspectiva de investigación de vulnerabilidades, porque no requieren una comprensión de los mecanismos internos del software. El único requerimiento para empezar a buscar por vulnerabilidades, es conocer cuales interfaces permiten la interacción con el software, y generar los datos pasados a través de estas interfaces.

El “Fuzzing” o pruebas de “fuzz” son una clase de pruebas a software y hardware, en el cual los datos utilizados para realizar las pruebas son aleatoriamente generados. De esta manera, el problema de generar entradas se simplifica enormemente, además de no requerir ningún conocimiento sobre el funcionamiento interno del software, o la estructura de los datos de entrada. Esto puede parecer una perspectiva simplificada, pero se ha comprobado produce resultados, y permite encontrar vulnerabilidades relevantes de seguridad en el software.

A través de los años, mucha investigación ha sido realizada para mejorar las pruebas de software y técnicas de fuzzing. En la actualidad, el fuzzing no implica más el uso de datos generados aleatoriamente como un medio para probar las entradas, pero en su lugar es más un sinónimo para cualquier tipo de prueba automática de software y hardware.

El objetivo principal es tener ideas para mejorar las diferentes etapas del fuzzing, lo cual permitirá encontrar más vulnerabilidades de seguridad. Algunos términos utilizados de manera similar son software, programa y aplicación. También “fuzzing”, pruebas de fuzz, y pruebas. Y finalmente agujero, vulnerabilidad o falla.

Fuentes:

https://en.wikipedia.org/wiki/Fuzzing
https://www.owasp.org/index.php/Fuzzing

Herramientas Automáticas para Análisis Binario

Body

Para auditar automáticamente un binario por potenciales vulnerabilidades, cualquier herramienta debe primero comprender el formato del archivo ejecutable utilizado por el binario, ser capaz de interpretar las instrucciones en lenguaje máquina contenidas dentro del binario, y finalmente determinar si el binario realiza algunas acciones probablemente explotables. Tales herramientas son mucho más especializadas comparadas con las herramientas para auditar el código fuente. Por ejemplo, código fuente C puede ser automáticamente escaneado no importando la arquitectura para la cual se compiló el código, mientras una herramienta para auditar el binario necesita un módulo separado para cada formato de archivo ejecutable capaz de interpretar, como también un módulo separado para cada lenguaje máquina capaz de reconocer.

Adicionalmente, un lenguaje de alto nivel utilizado para escribir una aplicación y el compilador utilizado para compilarlo, puede influir en como se ve el código compilado. El código fuente compilado C/C++ se ve muy diferente de código Delphi o Java. El mismo código fuente compilado con dos diferentes compiladores puede poseer muchas similitudes, pero también posee muchas diferencias. El principal reto de tales productos se centra en la habilidad de caracterizar precisamente el comportamiento, lo cual conduzca hacia una condición explotable. Ejemplos de tales comportamientos incluyen acceso hacia fuera de la memoria asignada (ya sea “stack” o “heap”), uso de variables sin iniciar, o pasar directamente entradas del usuario hacia funciones peligrosas.

Para realizar cualquiera de estas tareas, una herramienta automática debe ser capaz de calcular precisamente rangos de valores tomados por variables indice y punteros, siguiendo el flujo de los valores ingresados por el usuario conforme son utilizados dentro del programa, y rastrear la iniciación de variables referidos por el programa. Finalmente para ser verdaderamente efectivos, las herramientas automáticas para el descubrimiento de vulnerabilidades, deben ser capaces de realizar cada una de estas tareas de manera fiable, mientras tratan con muchas diferentes implementaciones algorítmicas utilizadas por los programadores y sus compiladores.

Cada herramienta para el análisis automático de binarios tiene sus propias capacidades, como Bugscam, binary Analysis Tool (BAT), BANG, bindiff, etc. Se sugiere leer la documentación de cada una de ellas desde su correspondiente sitio web.

Fuentes:

http://www.openrce.org/downloads/details/69/Bugscam
http://www.binaryanalysis.org/old/home
https://github.com/armijnhemel/binaryanalysis-ng
https://www.zynamics.com/bindiff.html
https://linuxsecurity.expert/security-tools/binary-analysis-tools

IDA

Body

IDA es un desensamblador y depurador multi procesador para Windows, Linux o Mac OS X, el cual ofrece muchas características . IDA es un desensamblador interactivo, el cual permite a los usuarios tomar participación activa en el proceso de desensamblamiento. IDA no es un analizador automático de programas. IDA proporcionará sugerencias sobre instrucciones sospechosas, problemas no resueltos, etc. Es el trabajo del profesional informar a IDA como debe proceder. Todos los cambios hechos son guardados hacia el disco. Cuando se ejecute IDA nuevamente, toda la información del archivo siendo desensamblado es leído desde el disco, de tal manera se podrá reiniciar el trabajo en el punto pertinente.

IDA es quizás la herramienta por excelencia para desensamblar. IDA entiende un gran número de lenguajes máquina y formatos de archivos ejecutables. En su núcleo, IDA es de hecho una aplicación de base de datos. Cuando un archivo binario es cargado para su análisis, IDA carga cada byte del binario dentro de una base de datos, y asocia varias opciones o banderas con cada byte. Estas opciones o banderas pueden indicar si un byte representa código, datos, o información más específica como el primer byte de una instrucción de múltiples bytes. Los nombres asociados con diversas ubicaciones del programa o comentarios generados por IDA, o ingresados por el usuario son también almacenados dentro de la base de datos.

IDA puede analizar un programa cuando este no está ocupado realizando una acción solicitada. Es factible desensamblar un programa junto con IDA, pero las solicitudes tienen la prioridad.

El estado de un análisis en segundo plano es mostrado en la esquina superior derecha de la pantalla. Es factible también deshabilitar el análisis automático, pero en este caso algunas funciones de IDA producirán resultados extraños (por ejemplo, si se intenta convertir datos en instrucciones, IDA no rastreará todos los hilos del control de flujo, y los datos serán convertidos en instrucciones únicamente sobre la pantalla).

La versión de pago de IDA tiene las siguientes funcionalidades:

  • Capacidades para crear gráficos del código y representar relaciones de funciones
  • Capacidades de diagramas de flujo para representar flujos de funciones
  • Una ventana de cadenas para mostrar secuencias de caracteres ASCII o UNICODE contenidas en el archivo binario
  • Una gran base de datos de disposiciones comunes de estructuras de datos y prototipos de funciones
  • Una poderosa arquitectura de “plugins”, el cual permite extender fácilmente las capacidades de IDA
  • Un motor de scripting para automatizar muchas tareas de análisis
  • Varios depuradores integrados

IDA tiene una versión “freeware” para Windows, Linux y Mac OS X con las siguientes limitaciones:

  • No está permitido su uso comercial
  • Ausencia de todas las características incorporadas en IDA versión mayor a 7.0
  • Ausencia de soporte para muchos procesadores, formatos de archivos, depuradores, etc.
  • Viene sin soporte técnico.

IDA tiene un gran equipo de soporte y una activa comunidad. Así mismo tiene una gran cantidad de documentación técnica sobre los diferentes aspectos y capacidades de la herramienta.

Fuentes:

https://www.hex-rays.com/products/ida/
https://www.hex-rays.com/products/ida/support/idadoc/415.shtml
https://www.hex-rays.com/products/ida/support/download_freeware.shtml

Desensambladores

Body

Mientras la descompilación de un código compilado es una tarea extremadamente retadora, desensamblar el mismo código fuente no lo es. Para cualquier programa compilado se ejecute, este debe comunicar alguna información hacia el sistema operativo anfitrión. El sistema operativo necesitará conocer un punto de entada del programa (la primera instrucción la cual debe ser ejecutada cuando el programa sea iniciado); la disposición de memoria deseada del programa, incluyendo la ubicación del código y datos; y cuales librerías el programa necesitará acceder mientras se ejecuta.

Toda esta información está contenida dentro de un archivo ejecutable, y es generada a través de las fases de compilación y enlazado durante el desarrollo del programa. Los cargadores interpretan estos archivos ejecutables para comunicar la información requerida hacia el sistema operativo, cuando el archivo es ejecutado.

Dos formatos comunes para archivos ejecutables son, el formato de archivo ejecutable portátil (PE), utilizado por los ejecutables de Microsoft Windows, y el formato ejecutable y enlazado (ELF), utilizado por Linux y otras variantes Unix. Los desensambladores funcionan mediante la interpretación de estos formatos de archivos ejecutables (de una manera similar al cargador del sistema operativo), y así conocer la disposición del ejecutable, para luego procesar el flujo de instrucciones empezando desde el punto de entrada para dividir el ejecutable en sus funciones componente.

Fuentes:

https://en.wikipedia.org/wiki/Disassembler
https://docs.microsoft.com/en-us/windows/desktop/debug/pe-format
https://linux-audit.com/elf-binaries-on-linux-understanding-and-analysi…

Descompiladores

Body

La descompilación es quizá el santo grial de la auditoria binaria. Con una verdadera descompilación, la noción de un producto de fuente cerrada se desvanece, y la auditoría binaria revierte hacia el código fuente. Sin embargo, la verdadera descompilación es una tarea excepcionalmente difícil. Algunos lenguajes se prestan muy bien para la descompilación, mientras otros no. Los lenguajes ofreciendo mejor esta oportunidad, son por lo general lenguajes híbridos compilados / interpretados, como Java o Python. Ambos ejemplos de lenguajes los cuales son compilados hacia una forma intermedia independiente de la máquina, generalmente llamado “código byte”. Este código byte es luego ejecutado por una interprete independiente de la máquina. En el caso de Java a este interprete se le denomina Java Virtual Machine (JVM).

Dos características del código byte de Java lo hacen particularmente fácil para descompilar. Primero, los archivos de código byte Java, llamados archivos clases, contiene una significativa cantidad de información descriptiva. Segundo, el modelo de programación para JVM es bastante simple, y su conjunto de instrucciones es bastante pequeño. Ambas propiedades son verdaderas para archivos compilados en Python (.pyx), así también el interprete de Python.

Diversos descompiladores Java de fuente abierta hacen un excelente trabajo recuperando el código fuente Java, incluyendo al “proyecto Decompilador de Java” (JDP). Para los archivos “pyc” de Python, se tienen por ejemplo a los proyectos “Decompyle++” o “uncompyled6”, los cuales ofrecen la posibilidad de recuperar el código fuente.

Fuentes:

https://www.javaworld.com/article/3272244/core-java/what-is-the-jvm-int…
http://jd.benow.ca/
https://github.com/zrax/pycdc
https://pypi.org/project/uncompyle6/
https://en.wikipedia.org/wiki/Decompiler

Auditoría Manual de Código Binario

Body

Dos tipos de herramientas simplifican enormemente la tarea de realizar ingeniería inversa hacia una archivo, estos son los desensambladores y los descompiladores. El propósito de un desensamblador es generar lenguaje ensamblador desde un binario compilado, mientras el propósito de un descompilador es intentar generar código fuente desde un binario compilado. Cada tarea tiene sus propios desafíos, y ambos son de hecho difíciles, con la descompilación siendo la más difícil de las dos. Esto debido al hecho de compilar el código fuente es a la vez una operación con pérdida, lo cual significa la información se pierde durante el proceso para la generación del lenguaje máquina, y una operación de uno hacia muchos, lo cual significa la existencia de muchas traducciones válidas de una sola línea de código fuente hacia declaraciones equivalentes en lenguaje máquina.

La información perdida durante la compilación puede incluir nombres de variables y tipos de datos, lo cual hace la recuperación del código fuente original desde el binario compilado sea casi imposible. Adicionalmente, un compilador al cual se le solicite optimizar un programa por cuestiones de velocidad, generará un código muy diferente al generado si se le solicita se optimice el mismo programa por un tema de tamaño. Aunque ambas versiones compiladas serán funcionalmente equivalentes, se percibirán muy diferentes a un descompilador.

Fuentes:

https://trailofbits.github.io/ctf/vulnerabilities/binary.html
https://www.blackhat.com/presentations/bh-europe-06/bh-eu-06-Wheeler-up…

Análisis Binario

Body

El análisis del código fuente no siempre es posible. Esto es particularmente cierto cuando se evalúan aplicaciones propietarias con código fuente cerrado. Esto de ninguna manera previene el profesional en ingeniería inversa examine la aplicación; simplemente hace el examen sea algo más difícil. La auditoría binaria requiere un conjunto de habilidades más amplio comparado con la auditoría del código fuente. Mientras un programador competente en lenguaje C, puede auditar el código fuente independientemente del tipo de arquitectura en el cual haya sido compilado, la auditoría al código binario requiere habilidades adicionales en lenguaje ensamblador, formatos de archivos ejecutables, comportamiento de un compilador, componentes internos del sistema operativo, y varias otras habilidades de nivel bajo.

De hecho existen libros los cuales ofrecen enseñar a programar en 24 horas, mientras otros libros, como aquellos abarcando el tema de ingeniería inversa a binarios son pocos y distantes. El dominio de la ingeniería inversa a binarios requiere paciencia, práctica, y una buena colección de material para referencia. Todo lo necesario es considerar la cantidad de diferentes lenguajes ensambladores, lenguajes de alto nivel, compiladores y sistemas operativos, para comenzar a entender cuantas posibilidades existen para una especialización.

Fuentes:

http://www.binaryanalysis.org/
https://n0p.me/dynamic-binary-analysis/