Noticias

Diferentes interpretaciones de X86 Bytecode

Mientras creaba un detector de shellcode genérico y verificaba los resultados con entradas generadas al azar, terminé empleando con éxito la técnica fuzzing en diferentes bibliotecas de desensambladores de código abierto. La biblioteca de desensambladores que elegí para mi proyecto es libdasm debido a su historia relativamente larga y su licencia de dominio público. Pero escribir un desensamblador x86 exitoso y completo no es una tarea fácil dada la compleja naturaleza del grupo de instrucciones x86.

Libdasm solía tener problemas para desensamblar algunas instrucciones en coma flotante de manera correcta, pero esto sólo se debía a un error en las tablas de búsqueda del opcode (código de operación), en las que faltaban tres columnas NULL, por lo que encontrar la solución no fue tan difícil.

Lo que encontré hoy no parece un problema específico del opcode, sino un error en la decodificación correcta de instrucciones. Cuando libdasm desensambla las instrucciones con un prefijo de dirección de 16 bit, decodifica la dirección de forma incorrecta:

La instrucción en la dirección de la memoria virtual del usuario 008fe0f0 se decodifica con errores:

  • 67 es el prefijo de dirección de 16 bit antes mencionado
  • a0 es el opcode para mov al, moffs8
  • 2232 es la dirección de 16 bit que se debe interpretar como el operando
  • e830 no pertenece a esta instrucción

Así como siempre se debe pedir una segunda opinión médica en casos de enfermedades inusuales, yo utilicé udis86, una biblioteca de desensambladores diferente:

Por suerte, esta vez se desensambló la instrucción mov con éxito. Además, como e830 ya no se interpreta como parte de mov, se desensambla de forma correcta como una llamada de instrucción rel32. Es una pena que udis86 sea un desensamblador x86-64, por lo que extiende de manera interna el operando a una llamada, cometiendo otro error al desensamblarlo.

¿Qué es lo que mi CPU ejecuta y ve en realidad? Como esto es parte de un código de virtualización/emulación, podemos sólo agregar un cc breakpoint al prólogo del bloque y continuar con gdb (omitiendo lo innecesario):

Entonces el CPU ve una instrucción de llamada y trata de ejecutarla. En este caso particular, esto hubiese sido devastador porque habría permitido una vulnerabilidad de aumento de privilegios para entradas arbitrarias de usuarios, más que seguro shellcodes, para poder escapar del aislamiento virtual. Para que este método específico funcione de manera correcta, todas las instrucciones de modificación del control del flujo como llamadas tienen que ser emuladas en un programa. Pero si no vemos esa instrucción en el desensamblado, no podemos manejarla de forma adecuada.

Después de parchar libdasm (que terminó ignorando por completo los prefijos de dirección para el análisis sintáctico del operando), se lo logra desensamblar con éxito:

Lo que aprendimos:

  • Es una buena idea usar el método fuzzing en tus programas con entradas aleatorias como parte de tu proceso de pruebas y puede revelar vulnerabilidades interesantes. Explotar este caso en particular habría sido muy difícil porque el descriptor de código de segmento y los descriptores de segmentos de datos dirigían a diferentes direcciones base, pero un atacante hábil lo hubiese logrado de cualquier manera.
  • La versión pública de libdasm desensambla de forma incorrecta todas las instrucciones con prefijos de dirección. Esto creará vectores de ataque interesantes contra algunos proyectos en los que se usó libdasm. ¡Consigan un parche para libdasm!

Diferentes interpretaciones de X86 Bytecode

Su dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

 

Informes

BlindEagle vuela alto en LATAM

Kaspersky proporciona información sobre la actividad y los TTPs del APT BlindEagle. Grupo que apunta a organizaciones e individuos en Colombia, Ecuador, Chile, Panamá y otros países de América Latina.

MosaicRegressor: acechando en las sombras de UEFI

Encontramos una imagen de firmware de la UEFI infectada con un implante malicioso, es el objeto de esta investigación. Hasta donde sabemos, este es el segundo caso conocido en que se ha detectado un firmware malicioso de la UEFI usado por un actor de amenazas.

Suscríbete a nuestros correos electrónicos semanales

Las investigaciones más recientes en tu bandeja de entrada