AVILX

REVERSING WRITEUP · CRACKMES.ONE · 2026

VVSC

Password numérico hardcodeado — conversión hex a decimal

Autor retoelijunior01
Plataformacrackmes.one
Dificultad1.0 / 5.0
Arquitecturax86-64 — Unix/Linux
ModoNormal Mode — Análisis estático
AnalistaJesús Ávila (Avilx)
Fecha22 de Septiembre 2026
Portafolioavilx.dev
PASSWORD ENCONTRADO REVERSING · ASSEMBLY · CRACKME · x86-64

Documentación de aprendizaje en reversing | Entorno controlado

Información del Binario

Campo Valor
NombreVVSC
TipoELF 64-bit LSB executable
Arquitecturax86-64
Enlazadodynamically linked
Strippedno
BuildID7ea0eace145e89811a030f9914f6637e69d29d66
Stack CanaryNo Canary Found
NXEnabled
PIEPIE Disabled
RELROPartial RELRO
Nota
La combinación de No Canary y PIE Disabled hace que este binario sea potencialmente vulnerable a buffer overflow con direcciones predecibles. Sin embargo, el mecanismo de validación resultó ser una comparación directa de entero en el disassembly, sin necesidad de explotar ninguna vulnerabilidad de memoria. Partial RELRO deja el GOT escribible — relevante si existiera un vector de escritura arbitraria.

Reconocimiento

File y checksec

$ file ./VVSC
./VVSC: ELF 64-bit LSB executable, x86-64, version 1 (SYSV),
dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2,
for GNU/Linux 2.6.24,
BuildID[sha1]=7ea0eace145e89811a030f9914f6637e69d29d66,
not stripped

$ checksec file ./VVSC
Partial RELRO | No Canary Found | NX enabled | PIE Disabled | 80 symbols

Strings

$ strings -a ./VVSC | grep -v "^_Z\|GLIBC\|\.so\|\."

Enter the numerical password:
Hallazgo
El output de strings no contiene ningún password en texto claro. El único string relevante es el prompt “Enter the numerical password:”, que indica que el binario valida un número entero, no una cadena de texto. Esto descarta el vector de texto claro directo y apunta al disassembly como siguiente paso.

Ejecución inicial

$ ./VVSC
Enter the numerical password:
3
Access denied.
Hipótesis
El binario pide un entero y lo compara internamente contra un valor hardcodeado. La comparación debe ser visible en el disassembly como una instrucción cmp contra un valor inmediato, justo después de la llamada a cin.

Análisis del Disassembly

Flujo de main

$ objdump -d -M intel ./VVSC | grep -A 50 "<main>"

400a93:  call   _ZNSirsERi          ; cin >> variable (lee entero)
400a98:  cmp    DWORD PTR [rsp+0xc],0xd80b1
400aa0:  je     400b68              ; si igual -> "Allowed access."
400aa6:  mov    edx,0xf
400aab:  mov    esi,0x400d59        ; "Access denied."
Hallazgo
El patrón es inmediato: cin lee el input del usuario en [rsp+0xc], y la siguiente instrucción lo compara contra el valor inmediato 0xd80b1. Si son iguales, je salta al bloque de éxito. Este es el mismo patrón lectura + comparación + salto condicional visto en challenges anteriores, pero con un entero en lugar de un string.
Nota
La diferencia clave respecto a challenges anteriores: aquí no hay strcmp ni operator==. La comparación es directa contra un valor inmediato en el código. En C/C++, esto corresponde a if (input == 884913). El compilador lo optimiza a un cmp directo sin llamada a función.

Conversión del valor

El password está en hexadecimal en el disassembly. La conversión a decimal es directa:

>>> 0xd80b1
884913
Hallazgo
El password numérico es 884913 (0xd80b1 en hex). Identificado directamente en la instrucción cmp del disassembly de main.

Solución

Password encontrado

884913
PASSWORD ENCONTRADO
$ ./VVSC
Enter the numerical password:
884913
Allowed access.
Hallazgo
El password 884913 fue identificado convirtiendo el valor hexadecimal 0xd80b1 de la instrucción cmp del disassembly. El binario respondió “Allowed access.” confirmando el vector.

Reflexión Final

Qué salió bien

Reconocer inmediatamente que la ausencia de password en strings significaba que el valor estaba en el disassembly como inmediato. El patrón cin + cmp + je es ahora reconocible a primera vista.

La conversión de hex a decimal es directa — 0xd80b1 a 884913 sin necesidad de herramientas externas.

Qué salió mal

Al leer el disassembly inicialmente hubo dificultad para separar el ruido del compilador C++ (símbolos de cout/cin mangleados) de las instrucciones relevantes. La clave es enfocarse únicamente en cmp, test, je/jne y las llamadas a funciones conocidas como cin/strcmp.

Lecciones aprendidas

Cuando strings no revela el password, el siguiente paso es siempre el disassembly. En binarios que piden enteros, la comparación aparece como cmp contra un valor inmediato en hexadecimal — no hay llamada a strcmp ni operator==.

El patrón universal de validación en crackmes:

  1. Leer input (cin, scanf, gets)

  2. Comparar contra valor esperado (cmp, strcmp, operator==)

  3. Salto condicional (je/jne) al bloque de éxito o fallo

Identificar este patrón en cualquier variante es la base del análisis de crackmes. Todo lo demás es ruido del compilador.

Tiempo total

Fase Tiempo
Reconocimiento (file, checksec, strings)3 minutos
Análisis del disassembly10 minutos
Conversión hex a decimal1 minuto
Verificación2 minutos
Total16 minutos