Nuevas Entradas

Arduino P0wn3d - Desbordando Arduino

by hdbreaker

Hace bastante tiempo que con mi amigo Q3rv0 estamos estudiando a fondo los renombrados Buffer Overflow en distintas arquitecturas.

En una charla a altas horas de la noche salio la incognita... 

¿¿¿Se podra Overflodear un Arduino???


La verdad fue un gran interrogante. Como gran aficionado a la electrónica y habiendo trabajando desarrollando varios sistemas telemétricos industriales bajo la misma plataforma, no podía faltar en mi colección varios de estos increíbles aparatitos.

El problema era el siguiente... como funciona internamente el procesador de un Arduino?

Antes de empezar a probar decidí estudiar un poco mas en profundidad la arquitectura Harvard, en la cual se basan la mayoría de los sistemas embebidos PIC y derivados centrados en Atmel AVR.

Lo primero a destacar de la arquitectura Harvard es que a diferencia de arquitecturas como x86 y x64, Harvard tiene 2 espacios de memoria separados, los cuales gestionan partes distintas del procesador, un sector se encarga de gestionar la sección ejecutable o de código y otra, la sección de datos no ejecutables, donde se almacenan las funcionalidades especiales del integrado donde se almacena el firmware principal o bootloader del micro controlador lo que equivaldría a root en un sistema linux!

EXECUTABLE SPACE <-------------> CPU ATMEL <-------------> DATA SPACE

El CPU ATMEL tiene la habilidad de poder interactuar con ambos espacios de memoria a la vez y en base a las direcciones en el DATA SPACE gestionar los saltos de memoria en el EXECUTABLE SPACE (CODE SPACE)

La idea principal era de alguna forma lograr explotar una función que no validara el largo de los buffer y de esta forma poder pisar la memoria reservada en el stack hasta sobre escribir el EIP y lograr modificar el salto del procesador a una nueva dirección de memoria donde esconderíamos algún código malicioso que se ejecutara a nivel bootloader y de esta forma conseguir nuestro "pseudo root" y lograr acceder a la habilidad de retrogravación que poseen los Arduino e intentar cargar un bootloader modificado que guardara a escondidas los valores de distintos sensores y los enviara a un servidor ftp o los escribiera en algún archivo que luego el atacante obtendría por sus propios medios.

Lo primero a solucionar... la funcion que no validara el largo de los buffer... La verdad esto no fue muy dificil, ya que Arduino se basa en C para trabajar podemos utilizar la función strcpy sin sanitizar para lograr overflodear el stack y así lograr pisar el EIP.

Para realizar mis pruebas realice un pequeño sketch que me permitiera analizar de forma controlada las distintas respuestas que podía observar en Arduino.

Sketch:

int led = 13;

//Buffer to be Smashed
char bufferOUT[1];

//Buffer Payload
char bufferIN[5];
  
void setup() {
  Serial.begin(9600);
  pinMode(led,OUTPUT);
}

void loop() {
  
   Serial.readBytes(bufferIN, 5);
   // MAGIC HERE
   strcpy(bufferOUT,  bufferIN);
   // MAGIC END
   
   Serial.print(bufferOUT);
  
   //LED BLINK
   digitalWrite(led, HIGH);
   delay(500);
   digitalWrite(led, LOW);
   delay(500);
}


Como no encontré forma de debuggear Arduino de forma remota y lograr ver que sucedía en sus llamadas a memoria me vi en la obligación de interpretar las salidas físicas que me dictaba Arduino y sacar conjeturas para saber si iba por el camino correcto.

Me valí de dos grandes factores para esto:


En el loop inifito de Arduino cree un simple script que hiciera parpadear un LED de forma intermitente con una diferencia de medio segundo.

Dentro del loop agregué una llamada a la función Serial que me permitiera leer un valor ingresado por teclado del largo que yo quisiera con el fin de simular un sensor, de esta forma lograr controlar el flujo de memoria del buffer de datos enviados y lograr sobre escribir el EIP con la ayuda de strcpy.

¿El resultado esperado?


Ya que no encontré forma de depurar el proceso en ejecución dentro del Atmel decidí basarme en mis conocimientos en las arquitecturas x86 y x64 y llegue a la siguiente conclusión:

"... El procesador Atmel en algún punto realiza un PUSH con la dirección de memoria para iniciar la función que enciende el LED luego un RET donde carga el valor del siguiente salto memoria en el EIP para llamar a la función que apaga el LED, y posterior mente un POP para eliminar de la pila (stack) la función ya ejecutada para realizar el mismo proceso con la función de apagado en el loop principal ..."

Si lograba pisar el EIP al momento de desbordar el buffer el EIP no sabría a donde saltar por lo que el programa en ejecución en Arduino colapsaría y al quedar huerfano dejaría de prender y apagar el LED.

bufferOUT[1] seria el espacio reservado ínfimo en el stack que intentaría desbordar.

bufferIN[5] seria mi long payload ingresado por Serial.

strcpy seria el CÓMPLICE, la función encargada de copiar sin ningún control nuestro long payload dentro de nuestro mini buffer reservado y de esta forma lograr, con el payload correcto, destrozar el EIP.

En este punto la incertidumbre era extrema toda la teoría indicaba que gracias al sistema de fragmentación de memoria que posee la arquitectura Hardvard seria casi imposible explotar un Buffer Overflow... sin más remedio me acomode los pantalones, me dije de aquí en adelante no hay vuelta atrás y presione el ENTER!

Luego de algunos segundos y luego del gran parpadeo del led azul que indicaba los RX recibidos por el Arduino, justo en el momento en que el payload termino su carga, el RX azul dejo de parpadear y casi de una forma increíble para mis espectativas el LED ROJO EN EL PIN 13 DEJO DE PARPADEAR!!!Esto realmente era increible para mi, no pensé que esto fuera posible, de forma exitosa había logrado sobre escribir el EIP en la arquitectura HARDVARD y el arduino había quedado colapsado.

Esto es interesante... por que es el punto de inflexión entre el EXECUTABLE SPACE Y EL DATA SPACE ya que strcpy se ejecuta del lado de EXECUTABLE SPACE, pero el EIP que regula los saltos es controlado por el DATA SPACE...

En pocas palabras había logrado pisar un bloque de memoria fuera de mi alcance que se encontraba protegido en DATA SPACE por la arquitectura HARVARD.

Esto pasa por que en algún momento el CPU debe comunicar las direcciones de memoria de la sección ejecutable sin sanitizar a la sección de datos permitiendo de alguna forma pisar los datos privativos de la sección protegida.

La única forma de que el equipo volviera a responder fue reiniciarlo y que el bootloader se encargara de volver a cagar en la sección ejecutable el sketch.

Bootloader el root del Atmel/PIC


Era el momento donde debía intentar ejecutar como "BOOTLOADER" alguna función utilizando la sobre escritura del EIP.

Mi Shellcode se trataba de un código especial que realizaría un print en Serial comunicandome si tenia acceso a clases especiales heredadas para intentar lograr realizar una especie de reflections (java) y lograr ejecutar funciones privativas de bootloader.

La estructura del Payload era la siguiente:

NewEIP + SHELLC0DE

Tristemente luego de muchisimos intentos y mucha lectura entendí lo que estaba pasando y por lo cual esta arquitectura es tan segura...

El CPU Harvard permite interactuar con un sector del stack DATA SPACE que solo permite modificar memorias y punteros en relación al EXECUTABLE SPACE, por lo que todo lo demás que venia pegado al NewEIP era marcado con el byte non-exec y pasado por alto en el DATA SPACE.

Por lo que nunca iba a poder lograr escalar privilegios a bootloader.

Conclución


Luego de entristecerme un tiempo una luz se encendió dentro mio...

No era posible ejecutar comandos dentro del DATA SPACE, pero era capaz de modificar el flujo de ejecución dentro del EXECUTABLE SPACE, por lo que era capaz de matar a un Arduino al dejar el EIP huerfano y además... era capas de llamar por medio del EIP y conociendo el memory address a cualquier otra función definida en el código ya que todos los saltos de memoria se encontrarían dentro del EXECUTABLE SPACE.

Imaginemos que en nuestro sketch tenemos 2 funciones que habilitan o cierran la valvula de gas de un horno industrial y en base a una lectura de un sensor o un input Serial de algún tipo este valor decide que es mejor para el horno industrial si apagarse o arder.


void abrirGas(){ //Direccion de memoria 0xde04beff
   //Abrir valvula de gas
}

void cerrarGas(){ //Direccion de memoria 0xde12baff
  //Cerrar valvula de gas
}

Conociendo las posiciones de memoria de ambas funciones nosotros podriamos sobre escribir el EIP y lograr que el loop del Arduino siempre salte a la función abrirGas() lo que se reflejaría en una industria un probable incendio.

En esta entrada no mostrare el PoC funcional sobre esto ya que el fin de esta entrada no es enseñar a romper sistemas embebidos sino demostrar que el Internet of the Things es un mundo increíble pero también abre un nuevo mundo para los ataques informáticos.

Sin mas me despido pidiendo a todos los desarrolladores IoT que utilicen plataformas HARVARD que antes de publicar o vender un proyecto corroboren la correcta sanitización de las entradas analógicas y las entradas Seriales, ya que en un mundo donde todo se esta empezando a regir por sensores una falla nuestra como programadores puede costarle la vida a alguien, por lo menos en ambientes industriales.

Les dejo el vídeo de como mato el proceso corriendo en Arduino explotando con éxito un Buffer Overflow en el sketch de esta publicación:



En el vídeo se muestra como al enviar 5 caracteres que son leidos por bufferIN, sobre escribo gracias a strcpy bufferOUT y logro pisar el EIP dejando huerfano el proceso por lo que el led rojo deja de parpadear.

Espero que les haya parecido interesante esta investigación personal y despierte la curiosidad en todos los lectores!
Saludos!

Share this:

 
Copyright © 2014 Security Signal.
Designed by OddThemes | Distributed By Gooyaabi Templates