Virtual Machine
- Dificultad: Difícil
- Categoría: Reversing
- Herramientas: (Ghidra, Python)
Descripción
Este binario simula una máquina virtual; tiene sus propias instrucciones. Nuestra tarea es simularla y obtener la flag.
Análisis general del binario
Prueba del programa
kali reversing-5 18:47 ./vm_challenge=== Virtual Machine Challenge ===A custom VM protects the flag.Reverse the bytecode to find the key.
VM Instructions: LOAD(0x01) XOR(0x02) CMP(0x03) JNE(0x04) SUCCESS(0x05) INPUT(0x06) HALT(0xFF)
Bytecode (290 bytes):06 00 02 00 aa 01 01 e2 03 00 01 04 06 00 02 00aa 01 01 9e 03 00 01 04 06 00 02 00 aa 01 01 ff03 00 01 04 06 00 02 00 aa 01 01 d1 03 00 01 0406 00 02 00 aa 01 01 dc 03 00 01 04 06 00 02 00aa 01 01 c7 03 00 01 04 06 00 02 00 aa 01 01 f503 00 01 04 06 00 02 00 aa 01 01 d8 03 00 01 0406 00 02 00 aa 01 01 99 03 00 01 04 06 00 02 00aa 01 01 dc 03 00 01 04 06 00 02 00 aa 01 01 9903 00 01 04 06 00 02 00 aa 01 01 d8 03 00 01 0406 00 02 00 aa 01 01 d9 03 00 01 04 06 00 02 00aa 01 01 99 03 00 01 04 06 00 02 00 aa 01 01 f503 00 01 04 06 00 02 00 aa 01 01 99 03 00 01 0406 00 02 00 aa 01 01 c4 03 00 01 04 06 00 02 00aa 01 01 cd 03 00 01 04 06 00 02 00 aa 01 01 9b03 00 01 04 06 00 02 00 aa 01 01 c4 03 00 01 0406 00 02 00 aa 01 01 99 03 00 01 04 06 00 02 00aa 01 01 99 03 00 01 04 06 00 02 00 aa 01 01 d803 00 01 04 06 00 02 00 aa 01 01 d7 03 00 01 0405 ff
Enter the key (24 chars):Luego de probar el programa, nos damos cuenta de que la flag tiene 24 caracteres (lo dice el mismo programa). Es lo único que vi al inicio (lol). Ahora procedo a desensamblar.
Ingeniería inversa
Luego de desensamblar, identificamos nuestra función main y vemos lo que hace.

Por lo que procedo a desensamblar FUN_001012c0. Luego de leer el código de FUN_001012c0, cambiar el nombre de las variables para entender mejor y tratar de entender por 30 minutos, lo único que entiendo es que todo ese código valida lo que ingresamos, y no se me ocurre cómo podría obtener la flag de él.
Por lo que me puse a analizar el programa y veo esto:
VM Instructions: LOAD(0x01) XOR(0x02) CMP(0x03) JNE(0x04) SUCCESS(0x05) INPUT(0x06) HALT(0xFF)
y pienso… ¿estará aquí la flag?
Y comienzo a analizarlo, y me doy cuenta de las instrucciones como si fuera assembly:
06 00 -> lee un carácter y lo guarda en el registro 0002 00 aa -> le hace XOR a 00 con la key 0xaa01 01 e2 -> carga e2 en el registro 0103 00 01 -> compara que lo que hay en 00 sea igual a lo que hay en 0104 -> si no es igual, deja de comprobar los demás caracteres y acaba esoEntonces, viendo los demás bytes, notamos ese patrón de que carga, aplica XOR y compara, por lo que se me ocurre que tal vez aquí está la flag encodeada con XOR, y cada byte que se compara es un carácter de la flag, por lo que se lo aplico en: Cyberchef

YA VEMOS LA FLAG!!!!
Pero me da pereza tener que quitarle los espacios manualmente, así que mejor hago un script en Python para ahorrarme eso (tardé más de lo que hubiera tardado haciéndolo manual).
Primero guardo el hex en un archivo reversing5variable.txt, que lo leeré desde Python.
Código de descifrado
import re
with open("reversing5variable.txt", "r") as f: lines = [linea.rstrip('\n') for linea in f.readlines()] flag = "" vytes = "".join(lines).split(" ") for vyte in vytes: if not (vyte == "06" or vyte == "01" or vyte == "02" or vyte == "03" or vyte == "04" or vyte == "05" or vyte == "00" or vyte == "aa"): xor = int(vyte, 16) ^ 0xaa flag += chr(xor) print(flag[:-1])Como lo que me interesa es obtener los valores con los ^ 0xaa, lo que hice fue simplemente obviar las instrucciones, los bytes nulos y el valor de 0xaa (no usé regex porque no me acordaba cómo hacerlo en Python), y solo se le hizo XOR a los valores que interesan. Al final le quito el último carácter, porque se me cuela un carácter: el de 0xff, que está al final del hex.
![]()
Flag
H4U{vm_r3v3rs3_3ng1n33r}