Ir directamente al contenido

Máquinas Microarquitectónicas Informales(µWM): técnica emergente con potenciales implicaciones en seguridad y ofuscación de código.

23 diciembre, 2024

Pueden entenderse como construcciones de código que permiten realizar computaciones a través de efectos secundarios y conflictos entre entidades microarquitectónicas como son los predictores de saltos y cachés.

Estas arquitecturas operan utilizando eventos no observables por las herramientas anti-ofuscación convencionales, lo que las hace ideales para la ofuscación de malware. Pueden usarse para realizar actividades fuera del modelo de seguridad. Además, dado que el estado actual de una arquitectura informal no se encuentra en la memoria regular sino que está codificado en el estado de los componentes microarquitecturales, las herramientas forenses tradicionales no pueden utilizarse para estudiar estas arquitecturas informales.

Se debe considerar que la capa microarquitectónica no es accesible directamente para los programas. Los programas pueden manipular implícitamente los componentes microarquitecturales (MA) al realizar una actividad regular. Ejemplos de componentes MA incluyen cachés, prefetchers y determinados buffers de la arquitectura. Muchos de estos mecanismos tienen estructuras de datos internas con un espacio de estados muy complejo. Aparte de los efectos en el tiempo (sobre todo nos importa el tiempo) de ejecución, estos mecanismos son completamente transparentes a los programas que ejecuta el procesador.

Al igual que las arquitecturas convencioanles, esta arquitectura informal construída virtualmente sobre las arquitecturas formales se componen de registros, puertas y circuitos. Pero se les denomina de otra forma:

  • Registros informales: Son capaces de almacenar datos, están implementados sobre los estados de componentes microarquitectónicos.
  • Puertas informales: Componentes básicos de computación que transforman los datos almacenados en los registros informales.
  • Circuitos informales: Conjuntos de puertas que implementan una lógica más compleja.

Ejemplo: Una arquitectura informal puede ofuscar código de malware para que su operación pasiva sea invisible hasta que se reciba un disparador. Y esto debemos comenzar a tenerlo MUY presente.

Aplicación práctica: FLEXO.

Como ejemplo de este concepto podemos citar a FLEXO. Ya que Flexo demuestra que las arquitecturas informales son una amenaza práctica a corto plazo.Permite crear máquinas informales a partir de código C/C++. Demuestra la practicidad al extender el empaquetador UPX para encriptar su carga útil y usar una máquina informal para la desencriptación. Flexo, permite calcular cualquier función booleana de N entradas.

Las máquinas informales son un nuevo enfoque para la computación que aprovecha las características microarquitectónicas de los procesadores. Tienen un gran potencial para la ofuscación de código y el desarrollo de malware.

Las arquitecturas informales son una tecnología emergente con el potencial de impactar significativamente el panorama de la seguridad. Recomiendo que se revise el github proporcionado acerca de Flexo pues demuestra la viabilidad de estas arquitecturas para aplicaciones del mundo real, lo que exige un mayor escrutinio y el desarrollo de estrategias de mitigación.

A fondo:

La idea subyacente consiste en utilizar efectos secundarios y conflictos en componentes microarquitecturales de los procesadores para realizar operaciones encubiertas.

El usar alternativas (canales laterales) para explotar el comportamiento no habitual de las arquitecturas en favor de un potencial ataque ya lo vimos con Spectre, en este caso ya se inferían estados de la microarquitectura usando medidas de tiempo. En este artículo se va a tratar el concepto de máquina (o arquitectura) informal, que son construcciones de código que aprovechan efectos secundarios en la microarquitectura (como predicción de saltos y efecto en las cachés) para realizar cálculos. Estos efectos no son observables mediante herramientas tradicionales como depuradores o emuladores, y ahí es precisamente donde radica su potencia para el desarrollo de malware (por ejemplo), especialmente peligroso en el caso de ransomware.

Las arqutecturas informales presentan grandes desafíos para los modelos de análisis y para las herramientas de detección de malware, dado que operan fuera del modelo arquitectónico de las herramientas de seguridad convencionales, como hemos visto en la introducción. Por ejemplo, pueden realizar tareas computacionales complejas (como implementar un SHA-1). Hay que remarcar que los cálculos realizados por estas arquitecturas son invisibles a las herramientas de análisis estático o dinámico, lo que supone un potencial enorme en la capacidad de ocultar código (tanto beneficioso como malicioso -es posible ocultar un código malicioso que crea una shell inversa, activado solo cuando recibe un disparador-).

¿Cómo funcionan?

Utilizan instrucciones del repertorio (especialmente cargas de memoria o saltos condicionales) y observan el tiempo de ejecución para inferir resultados. Aprovechan características tales como la ejecución especulativa (ver programa de ejemplo) para alterar estados microarquitecturales (observables indirectamente a través del tiempo de respuesta de las operaciones que usan la caché, los predictores de saltos, etc.) sin cambios en el estado arquitectónico observable.

Este tipo de comportamientos impacta directamente en las capacidades de defensa que actualmente conocemos. La complejidad de los efectos microarquitecturales dificulta significativamente el análisis y la emulación precisa, asegurando que los cálculos no puedan ser replicados fácilmente. Las técnicas actuales basadas en pruebas formales y análisis forense ya son prácticamente inutilizables contra estas máquinas informales ya que su estado no se encuentra en la memoria convencional, y por tanto estas herramientas de análisis tradicionales no pueden detectarlas.

¿Pero cuales son esos estados microarquitecturales que estas técnicas pueden usar para hacerse más difíciles de detectar?

Los procesadores modernos tienen múltiples capas funcionales, estos conceptos son fundamentales para todo ingeniero en informática. De hecho se dedican asignaturas obligatorias que guardan relación con este concepto en las titulaciones universitarias:

Capa arquitectónica (ISA, Instruction Set Architecture): La interfaz «visible» para los desarrolladores, que define cómo funcionan las instrucciones que un programa puede ejecutar.

Capa microarquitectural: Los componentes internos que implementan físicamente la arquitectura y optimizan la ejecución, como:

-Cachés.
-Predictores de saltos.
-Buffers de reordenamiento (relacionados con la optimización aplicada por los compiladores o por las unidades de hardware).
-Unidades de ejecución especulativa (relacionados con los predictores de saltos).

La microarquitectura no está diseñada para ser directamente manipulada por los programas, pero sus efectos indirectos (efectos secundarios) pueden ser analizados, por ejemplo, midiento el tiempo de las operaciones que se apoyan en ellos.

Considerando lo anterior, ¿cómo podemos -por ejemplo, midiendo el tiempo, aprovechar los elementos de la capa microarquitectural- para realizar otros cómputos no evidentes?

Efectos Secundarios

Consideremos el cambio de estado no intencionado en la microarquitectura que ocurre al ejecutar una instrucción.

Por ejemplo:

Evicción de caché: Acceder a una ubicación de memoria puede desplazar datos en la caché, dejando rastros que pueden ser medidos y utilizados para inferir información. Ver código de ejemplo 1.

Ejecución especulativa: El procesador predice el resultado de una rama condicional y ejecuta instrucciones antes de saber si eran correctas, dejando cambios temporales en componentes internos. Ver código de ejemplo 2.

Conflictos Microarquitecturales

Los conflictos ocurren cuando varios componentes del procesador compiten por los mismos recursos, lo que introduce comportamientos observables.

Ejemplos:

Colisiones en caché: Dos procesos que acceden a la misma línea de caché pueden provocar un «choque» que altera el rendimiento, detectable mediante la latencia de acceso.

Contención de recursos: Varias instrucciones que utilizan las mismas unidades funcionales (como ALU o FPU) pueden causar demoras detectables.

¿Cómo aprovechan estas cuestiones las máquinas informales?

Lo aprovechan para crear un sistema computacional basado en las transiciones de estados microarquitecturales, en lugar de depender exclusivamente de las instrucciones tradicionales.

Por ejemplo:

Los estados microarquitecturales, como el estado de la caché o las colisiones de un predictor de saltos, se usan como «memoria» para almacenar datos. Esto es lo que se conoce en el argot de este tipo de técnicas como registro informal. Ver código de ejemplo 1.

Las instrucciones regulares, como un acceso a memoria o una predicción de salto, se manipulan para alterar esos estados de manera controlada, realizando operaciones como suma o comparación. Que es algo parecido a una «operación», antes lo habíamos llamado puerta informal.

Al encadenar múltiples efectos secundarios y conflictos, somos capaces de construir operaciones completas, como una función de hash.

La potencia de esta técnica es evidente. Conseguimos invisibilidad ya que las operaciones realizadas a nivel microarquitectural no dejan rastros visibles en registros y memoria. Esto da paso a implementar funcionalidades en «canales laterales» del procesador. La complejidad es que debemos conocer exhaustivamente el hardware sobre el que trabajamos para poder explotarlo.

Y aquí, un ejemplo, en C. (poner código y ejemplo de ejecución) de la suma especulativa. Ver código de ejemplo 2.

Acceso a más documentación:

Slides sobre estas microarquitecturas.

Artículo y anexo al artículo

No comments yet

Deja un comentario