Cabecera blog ciberseguridad

OWASP FSTM, etapa 8: Análisis en tiempo de ejecución

El análisis en tiempo de ejecución de los ejecutables de un firmware se puede llevar a cabo siguiendo la metodología OWASP FSTM

El análisis estático del firmware y sus ejecutables ofrece únicamente una cantidad limitada de información sobre su funcionamiento y realizar análisis más profundos en esa fase es poco eficiente en tiempo y esfuerzo. Debido a esto, es habitual que sea necesario continuar el análisis en un entorno dinámico, en el que el firmware y sus componentes puedan ser observados (y manipulados) en ejecución.

El análisis en tiempo de ejecución se apoya en las fases anteriores para obtener acceso a los ejecutables y procesos internos del sistema, ya sea en un entorno real a través de un acceso de administrador o en un entorno virtualizado, construido específicamente para los ejecutables de este firmware y en el que se tiene mucho más control sobre la ejecución.

En caso de ejecutar el sistema en el hardware original, sin emulación, es necesario obtener acceso de administrador o de depuración para continuar con esta fase del análisis, además de disponer en el sistema de las herramientas de depuración e instrumentación que se vayan a utilizar.

De no tener acceso de administrador o no contar con hardware original, se puede construir un entorno virtual aislado con todas las herramientas, archivos y bibliotecas necesarias para los ejecutables que se van a analizar. Este entorno se puede construir con chroot o herramientas similares y permite un control mayor sobre todo el proceso, aunque es más propenso a errores y requiere una mayor inversión en tiempo y esfuerzo.

En este artículo se discuten las diferentes herramientas que se pueden utilizar en el análisis en tiempo de ejecución.

1. Principales técnicas para realizar un análisis en tiempo de ejecución

Existen múltiples técnicas y herramientas que son de utilidad para el análisis dinámico de un ejecutable. Las principales categorías son las siguientes:

  • Instrumentación y depuración: los depuradores ofrecen la capacidad de inspeccionar la memoria de un proceso en ejecución y de controlar su flujo de ejecución, colocando breakpoints en puntos estratégicos del código. La instrumentación es una técnica que permite obtener más información sobre un proceso en ejecución inyectando código de depuración extra. En muchos casos, las funciones de un depurador requieren de instrumentación para observar el estado de un proceso.
  • Tracing: consiste en registrar los eventos y llamadas al sistema que se producen durante la ejecución de un proceso y puede ofrecer un esquema fundamental de las operaciones que se realizan.
  • Logging: los registros producidos por el mismo ejecutable pueden arrojar mucha información sobre errores y, en general, el estado de un proceso.

2. Instrumentación y depuración

La instrumentación se refiere a un conjunto de técnicas usadas para supervisar, medir, controlar y modificar la ejecución de un trozo de software. Se trata de técnicas que aportan información para el análisis del comportamiento de un programa como el tiempo que tarda en ejecutarse, el estado de la memoria a la que accede… Estas técnicas se usan en herramientas con muy diversos fines, como puede ser comparar el desempeño de distintas implementaciones de un programa con la misma tarea o la supervisión de la ejecución de un programa para verificar que no haya accesos indeseados a zonas de memoria debido a fallos de programación, etc.

Los depuradores, usando técnicas de instrumentación, son herramientas que se utilizan para detectar, identificar y comprobar puntos críticos en un programa, bien durante el desarrollo del software o durante un análisis de seguridad. Gracias a estas herramientas, los desarrolladores pueden diagnosticar fácilmente el estado del software cuando se encuentran bugs, agilizando las correcciones. El código depurado puede estar corriendo en un simulador o en el dispositivo que está siendo estudiado.

Los depuradores pueden ser de varios tipos. El depurador puede ser un instrumento software, pero también se puede referir a una herramienta hardware que se usa para programar o descargar el firmware de un dispositivo, como se ha visto en la etapa 2 de OWASP. Estos depuradores hardware suelen ir acompañados de software de depuración propio.

A continuación, se listan múltiples alternativas de depuradores hardware, software y otros softwares de instrumentación útiles para el análisis dinámico.

2.1 Depuradores hardware

Los depuradores hardware pueden estar basados en diversos estándares como pueden ser SWI, BDM o CADI aunque la interfaz de depuración hardware más común es JTAG. El término JTAG se refiere al estándar IEEE 1149 y su nombre es acrónimo de Junction Test Action Group. La normalización apareció en 1985 de mano del comité europeo JETAG. Básicamente se refiere a un estándar de condiciones hardware y software que deben cumplir depuradores y microprocesadores.

Según el estándar IEEE 1149, un dispositivo compatible debe disponer de los siguientes pines:

  • TCK: reloj para ejecución de las ordenes de la depuración
  • TMS: junto con los flancos ascendentes del reloj determina el estado de disponibilidad del puerto de depuración
  • TDI: entrada de instrucciones y datos de pruebas serie durante la depuración
  • TDO: salida de instrucciones y datos de pruebas serie durante la depuración

Adicionalmente, el estado del controlador del puerto de depuración puede no estar determinado tras el arranque. En ese caso, el dispositivo debe disponer del siguiente pin:

• TRST*: establece el estado controlador del puerto de depuración en la posición de reinicio para sincronizar el hardware y el software durante la ejecución.

Dentro del sector del desarrollo de productos electrónicos existen multitud de herramientas de depuración. Los distintos fabricantes de hardware ofrecen respuestas diferentes a las necesidades de depuración.

Los depuradores software pueden ser especializados en un kit de desarrollo concreto o ser de uso general. Los especializados suelen ser desarrollados por el fabricante del kit de desarrollo y tienen capacidades limitadas, mientras que los de uso general se desarrollan siguiendo un estándar y tienen más funcionalidades. La siguiente tabla muestra algunos de los depuradores hardware con depurador software propio más conocidos:

Fabricante Modelo Hardware Software Depuración
Segger J-Link Depurador hardware con soporte para Arquitectura ARM V7 y V8, principalmente para la gama Cortex-M Software privativo. Aplicación J-Link muy extendida y soportada en la mayoría de los IDEs de desarrollo
Microchip ICP (Pic-Kit) Depurador hardware con soporte para la arquitectura PIC con soporte para las series 8 bits, 16 bits, 32 bits y DSP Software privativo. Aplicación con soporte para la familia PIC en la mayor parte de los IDEs de desarrollo con soporte
YIC System OPENIce-A1000 Depurador y Emulador hardware con soporte para Arquitectura ARM V7, V10, y V11 principalmente para la gama Cortex-A y Cortex-M Software privativo. Aplicación OPENIce-EDS provee soporte para la emulación y depuración software, posee la posibilidad de emular una base de datos de procesadores
Texas Instrument TMDSEMU110-U (XDS1100) Depurador y Emulador hardware con soporte para Arquitectura ARM V7, V8 y V9 principalmente para la gama Cortex-A, Cortex-R y Cortex-M Software privativo. Aplicación dbgjtag del IDE propio actualizado para la versión de la herramienta XDS110
FTDI FT2232HX Concentrador 2 en 1 USB multi-formato con JTAG. Reconfigurable con JTAG / USART / I2C / SPI Software de código abierto OpenOCD. Es posible depurar en la mayoría de los IDEs de código abierto o con interfaz consola
Microchip / Atmel ICSP (UART+ RST) Hace referencia a la configuración de pines y lel estándar aplicado al conector de 2×3 usado en las placas de desarrollo de Atmel. Son compatibles con std IEEE 1149 y generalmente se controlan con un puerto USART Software de código abierto o cerrado, admite el depurador de PIC-Kit, OpenOCD, y flashtools extensivas. Es la gran flexibilidad de la plataforma hardware la que la ha popularizado
Dangerous prototypes BUS-Pirate Depurador multiformato, USART, JTAG, SPI, I2C… Cuenta con soporte hardware para ARM V7, PIC ICP, ATMEL ICSP, etc Software de código abierto OCSP. Admite configuraciones genéricas en varios IDE de desarrollo y análisis de seguridad
ST Microelectronics ST-Link Hace referencia a la configuración de pines propia de SWD (IEEE 1149.7) para el fabricante ST y es compatible para la mayoría de los micros ARM V6, V7 y V8 de las gamas Cortex-M y Cortex-R aunque el fabricante no asegura la compatiblidad con micros fuera de su ecosistema Depuración de código abierto y cerrado. Admite la depuración con software como J-Link o con OpenOCD. Se trata de una adaptación lógica del estándar a nivel de software, pero de la que no se asegura la compatibilidad fuera del elenco del propio fabricante ST

2.2. Depuradores Software

Los depuradores software son una parte fundamental dentro de toda tarea de desarrollo o de análisis de seguridad en la vida de un dispositivo IoT. Es evidente que hoy en día el mejor hardware del mundo no sirve para nada sin un software apropiado que permita exprimir al máximo su potencial. Como ejemplos se pueden citar los vehículos, los sistemas de telefonía, o los mismos ordenadores personales.

Hay que hacer un alto en el camino durante esta explicación y tratar de separar ideas muy próximas pero que son partes distintas de un todo. Dentro del ordenador durante la depuración habrá que tener dos partes en funcionamiento que constituyen el paquete del depurador. En el lado del PC está por un lado el sofware de depuración del jlink (o el depurador físico elegido) que transforma los paquetes provenientes del dispositivo hardware en datos o frames completos. Por otro lado está el depurador o suite de depuración, como es GDB (o el usado por el entorno escogido por el usuario para esta tarea). Cada una de estas partes se debe configurar por separado.

GDB es el depurador software más ampliamente utilizado tanto en desarrollo como en tareas de análisis. Permite la instrumentación y depuración en tiempo real de casi cualquier software y, aunque usualmente no se asocia al desarrollo de sistemas empotrados, se usa a menudo. Permite inyectar valores y observar el funcionamiento de un firmware completo de una máquina externa en tiempo de ejecución. Así mismo también se pueden depurar programas que corren dentro de un sistema operativo exponiendo el mismo gracias a la localización de su código en la sección de la RAM que ocupa.

Se trata de una herramienta de línea de comandos, pero existen múltiples herramientas que hacen de front-end para GDB y que facilitan su uso:

Nombre Lenguajes soportados IDE Sistema Operativo
gdbgui C, C++, golang, Rust, Fortran Interfaz de texto GNU-Linux, Windows (MinGW / Cygwin)
BVRDE C, C++ Interfaz GUI Windows
CLion C, C++ JetBeans GUI GNU-Linux, MacOs, Windows
Eclipse CDT C, C++ Eclipse GUI GNU-Linux, MacOs, Windows, StandAlone
Kdevelop C, C++, Python, QML/JavaScript, PHP Plasma GUI GNU-Linux, FreeBSD, Solaris, MacOs, Windows
NetBeans Java, C, C++, Fortran, Ensamblador NetBeans GUI GNU-Linux, MacOs, Windows
Nemiver C, C++ Gnome GUI GNU-Linux
Pyclewn C, C++ Interfaz de texto Vim GNU-Linux
WinGDB C, C++ Visual Studio GUI GNU-Linux, MacOs, Windows
CodeLite C, C++ GUI GNU-Linux, FreeBSD, MacOs, Windows
QT Creator C++ QT GUI GNU-Linux, MacOs, Windows
GNU EMACS C, C++, golang, Rust, Fortran Interfaz de texto Emacs GNU-Linux, FreeBSD, MacOs, Windows
SlickEdit C, C++ Slick Edit GUI GNU-Linux, HP-UX, AIX, Solaris, MacOs, Windows
Lazarus Free-Pascal QT GUI GNU-Linux, FreeBSD, MacOs, Windows
Seer C, C++ QT GUI GNU-Linux

Además de los interfaces de GDB, PEDA (Python Exploit Development Assistance for GDB) es una herramienta que extiende la funcionalidad de GDB para facilitar las tareas de análisis de binarios. Mejora las capacidades de visualización coloreando y mostrando el código desensamblado, los registros y la información de la memoria durante el proceso de depuración y proporciona un entorno de ejecución de comandos que ayudan a la explotación. A continuación, se presentan algunos de los más interesantes:

Si bien es cierto que no es un software de instrumentación puro, gracias a este amplio abanico de comandos se pueden hacer algunas tareas similares a las que desempeñan las herramientas de instrumentación tradicionales.

patch — Patch memory start at an address with string/hexstring/int
pattern — Generate, search, or write a cyclic pattern to memory
procinfo — Display various info from /proc/pid/
pshow — Show various PEDA options and other settings
pset — Set various PEDA options and other settings
readelf — Get headers information from an ELF file
ropgadget — Get common ROP gadgets of binary or library
ropsearch — Search for ROP gadgets in memory
searchmem|find — Search for a pattern in memory; support regex search

2.3. Caso práctico de depuración

Un caso muy común para desarrollo y análisis de seguridad con dispositivos físicos es simular el dispositivo físico con una tarjeta de desarrollo del mismo fabricante. Para ilustrar este hecho se va a poner un caso real. Se trata de un dispositivo analizado de alto desempeño. Equipando una variante del micro ARM-Cortex M4 del fabricante ST Microelectronics, modelo stm32F3xx. Se adquirió una placa de desarrollo NUCLEO-F303RE, esta tarjeta integra el depurador ST-Link V2.1.

Esta tarjeta se hizo trabajar con OpenOCD, un depurador software de código abierto y se instrumentó la depuración con GDB. Se ha procedido a depurar el programa de prueba que hace parpadear un led.

$ openocd -f /usr/local/share/openocd/scripts/interface/stlink.cfg -f /usr/local/share/openocd/scripts/board/st_nucleo_f3.cfg

En la configuración del archivo stlink.cfg el puerto por defecto es el 3333, así se lanza la orden:

$ gdb-multiarch
GNU gdb (GDB) 12.1
Copyright (C) 2022 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later http://gnu.org/licenses/gpl.html
This is free software: you are free to change and redistribute it.


(gdb) target remote :3333

Tras analizar la hoja de características del fabricante se sabe que en la posición 0x20000000 comienza la RAM, la zona donde estará cargado el programa y se comprueba la memoria obteniendo esta captura:

En este punto se puede empezar a comprobar el funcionamiento del firmware del microprocesador en tiempo real. Para usar GDB los comandos más comunes son: setp, next, continue, disas, nexi, break y step in. Debido a que no se dispone del código ni del software compilado con símbolos este proceso será algo angosto, pero con algo de práctica termina siendo intuitivo para el usuario.

2.4. Frida

Es un toolkit de instrumentación dinámica enfocado al desarrollo, la ingeniería inversa y la ciberseguridad. Permite inyectar inyectar fragmentos de JavaScript o una librería propia en aplicaciones nativas en Windows, macOS, GNU/Linux, iOS, Android y QNX. Frida también proporciona algunas herramientas simples construidas sobre la API de Frida que se pueden usar tal cual, ajustarse a las necesidades del investigador, o servir como ejemplos de cómo utilizar la API.

Gracias a esta capacidad de inyección de scripts se facilita el análisis de procesos de caja negra. Entre los casos de usos más comunes destaca el seguimiento de funciones, espiar APIs criptográficas o rastrear el código de las aplicaciones (sin disponer del código fuente). En lo referente a la compatibilidad y accesibilidad de la herramienta, es software libre y gratuito, funciona en Windows, macOS, GNU/Linux, iOS, Android y QNX.

2.5. Qiling

Qiling puede ser usado como herramienta para realizar un análisis en tiempo de ejecución

El framework de emulación Qiling, ya introducido en el capítulo 6, puede ser utilizado para la instrumentación de un ejecutable. El objetivo de diseño de Qiling es precisamente el de servir como plataforma de instrumentación e ingeriería inversa, por lo que implementa muchas de las funcionalidades necesarias, además de una API con la que interactuar desde un lenguaje de programación.

Está basado en el framework Unicorn e implementado en Python, por lo que la emulación e instrumentación se realiza a través de scripts en los que se establecen los parámetros, como es el caso del ejemplo del manual:

from qiling import Qiling
from qiling.const import QL_VERBOSE

if name == “main“:
# set up command line argv and emulated os root path
argv = r’examples/rootfs/netgear_r6220/bin/mini_httpd -d /www -r NETGEAR R6220 -c **.cgi -t 300′.split()
rootfs = r’examples/rootfs/netgear_r6220′

# instantiate a Qiling object using above arguments and set emulation verbosity level to DEBUG.

# additional settings are read from profile file

ql = Qiling(argv, rootfs, verbose=QL_VERBOSE.DEBUG, profile=’netgear.ql’)

# map emulated fs ‘/proc’ dir to the hosting os ‘/proc’ dir

ql.add_fs_mapper(‘/proc’, ‘/proc’)

# do the magic!

ql.run()

Además de la emulación y contar con un depurador propio, Qiling puede conectarse con un cliente de depurador para controlar el flujo de ejecución o llamar a herramientas como AFL desde el script, de modo que facilita en gran medida la tarea de ejecutar pruebas en tiempo de ejecución.

3. Tracing

El registro de las llamadas al sistema realizadas o tracing por un programa es una de las técnicas más útiles tanto para desarrolladores como para analistas a la hora de depurar un software. En muchos casos, las tareas más críticas de un ejecutable requieren interacción con el kernel, por lo que observar las llamadas al sistema puede desvelar mucho sobre su comportamiento.

La herramienta más utilizada para obtener las llamadas al sistema es strace, que, a su vez, hace uso de la llamada al sistema ptrace. Como ejemplo de su uso, se puede observar el resultado de ejecutarla con whoami:

$ strace -ostrace.txt whoami
user

strace.txt:

geteuid() = 1000

openat(AT_FDCWD, “/etc/passwd”, O_RDONLY|O_CLOEXEC) = 3

lseek(3, 0, SEEK_SET) = 0
read(3, “root:x:0:0::/root:/usr/bin/nolog”…, 4096) = 1849
close(3) = 0

write(1, “dummy\n”, 6) = 6

Entre otras, se observan llamadas a geteuid, openat, read, y write, con lo que se puede comprobar que whoami consulta el UID del usuario y la base de datos de usuarios en /etc/passwd, comprueba a qué usuario corresponde el UID y lo devuelve a stdout. Como puede comprobarse, strace permite en muchos casos conocer el funcionamiento básico de un ejecutable sin necesidad de hacer una depuración completa.

Además de strace, el núcleo de Linux ofrece capacidades de tracing de los eventos, interrupciones y MMIO a través de ftrace. Para utilizar ftrace en el análisis de un ejecutable, se pueden utilizar herramientas de espacio de usuario como trace-cmd o KernelShark, que permite registrar eventos de kernel durante la ejecución del ejecutable. Se puede obtener más información en el manual de trace-cmd.

4. Logging

Aunque estas técnicas son de menor utilidad, en los sistemas Unix, generalmente se encuentran habilitados diversos sistemas de logging.

En ocasiones observar los logs de ejecución de algunos servicios en vivo puede ofrecer información sobre qué acciones realizan o sobre su estado.

En caso de tener la capacidad para causar fallos en algún ejecutable, también es interesante habilitar los «coredumps» en el kernel, que guardarán una copia del estado del ejecutable en el momento en el que se produce un fallo para su posterior análisis, por ejemplo, con gdb:

$ gdb ejecutable archivo_coredump

Existen muchas herramientas y técnicas para aplicar durante el análisis dinámico y se trata, en general de un proceso costoso en tiempo y esfuerzo, por lo que es fundamental elegir previamente los ejecutables y procesos de interés para el análisis. Para ello, se deben evaluar los resultados de las fases anteriores y analizar qué componentes son más propensos a crear vulnerabilidades.

Es crucial comprender como estas técnicas habilitan un estudio más profundo a través del cual se pueden descubrir y confirmar vulnerabilidades complejas que serían muy difíciles de detectar con otras técnicas de análisis.

Referencias

https://learn.microsoft.com/es-es/dotnet/framework/debug-trace-profile/tracing-and-instrumenting-applications
https://frida.re/
https://c.a.segger.com/fileadmin/images/products/J-Link/J-Link_PRO/j-link_pro_500.png.webp
https://github.com/longld/peda
https://www.st.com/bin/ecommerce/api/image.PF271415.en.feature-description-include-personalized-no-cpn-large.jpg
https://www.st.com/bin/ecommerce/api/image.PF260945.en.feature-description-include-personalized-no-cpn-large.jpg
https://qiling.io/2022/08/10/intro/
https://www.trace-cmd.org/
https://kernelshark.org/

Más artículos de la serie OWASP

Este artículo forma parte de una serie de articulos sobre OWASP

  1. Metodología OWASP, el faro que ilumina los cíber riesgos
  2. OWASP: Top 10 de vulnerabilidades en aplicaciones web
  3. Análisis de seguridad en IoT y embebidos siguiendo OWASP
  4. OWASP FSTM, etapa 1: Reconocimiento y búsqueda de información
  5. OWASP FSTM, etapa 2: Obtención del firmware de dispositivos IoT
  6. OWASP FSTM, etapa 3: Análisis del firmware
  7. OWASP FSTM, etapa 4: Extracción del sistema de ficheros
  8. OWASP FSTM, etapa 5: Análisis del sistema de ficheros
  9. OWASP FSTM etapa 6: emulación del firmware
  10. OWASP FSTM, etapa 7: Análisis dinámico
  11. OWASP FSTM, etapa 8: Análisis en tiempo de ejecución
  12. OWASP FSTM, Etapa 9: Explotación de ejecutables
  13. Análisis de seguridad IOT con OWASP FSTM