ctf_manual
inicio / fundamentos / carril avanzado / bloque 3
XREF
// carril avanzado · bloque 3 de 4 · malware / reversing clásico

Del archivo
a la comparación

No ejecutes primero. Identifica el formato, conserva hashes, reduce el programa a sus puntos de interés y sigue referencias hasta la comprobación de la flag.

salida de este bloque

Triage reproducible de ELF y PE · lectura estática con Ghidra o radare2 · criterio para pasar a GDB · reconocimiento de seis patrones escolares · una flag reconstruida desde pseudocódigo local.

aislamiento obligatorio Analiza únicamente binarios creados por ti o retos autorizados. Una muestra desconocida se trata como hostil: VM desechable, snapshot previo, carpetas compartidas y portapapeles desactivados, red deshabilitada y sin credenciales. Este bloque no aloja, descarga ni ejecuta malware real.

Triage de 15 minutos: reduce antes de decompilar

Trabaja sobre una copia y registra cada hallazgo con offset o dirección. El hash identifica el artefacto exacto; no demuestra que sea benigno. No subas muestras privadas a servicios públicos de análisis.

01 · fileformato, arquitectura, endian, enlazado y símbolos
02 · hashesSHA-256 de la copia antes de tocarla
03 · stringsmensajes, rutas, formatos y falsos positivos
04 · imports / sectionscapacidades y regiones anómalas
05 · main / xrefsentrada lógica, llamadas y comparación
EtapaComando de lecturaQué anotarCorte
Identidadfile ./retoELF/PE, 32/64 bits, arquitectura, dinámico/estático, stripped1 min
Integridadsha256sum ./reto
certutil -hashfile reto SHA256
hash + nombre + origen autorizado; MD5 solo como identificador legado, nunca como integridad1 min
Cadenasstrings -a -n 5 ./reto | lesséxito/error, %s, rutas, claves aparentes; luego busca sus xrefs3 min
ELFreadelf -hSWd ./reto
readelf -Ws ./reto
.text/.rodata/.data, intérprete, NEEDED, símbolos e imports4 min
ELF o PErabin2 -I -S -i ./retoheaders, secciones, imports; tamaños/entropía inusuales y entrypoint fuera de código normal4 min
Ruta lógicar2 -A ./retoaflizaxtmain, validadores, callers/callees y comparación que conduce al mensaje de éxito2 min inicial
orden de confianza Una cadena es una pista, un import es capacidad y el decompilado es una aproximación. La evidencia fuerte es el dataflow: input → transformación → comparación → rama de éxito. Contrasta siempre el pseudocódigo con unas pocas instrucciones cuando el tipo, signo o longitud cambien la conclusión.

ELF vs PE · estático vs dinámico

PreguntaELF (Linux)PE (Windows)Decisión
Cabecera0x7f ELF; program/section headers; PT_INTERPMZ + firma PE\0\0; DOS/COFF/optional headersConfirma arquitectura y ABI antes de interpretar registros o calling convention.
Secciones típicas.text, .rodata, .data, .plt/.got.text, .rdata, .data, .idata, .rsrcNombres raros no prueban packing; cruza permisos, tamaño, entropía e imports.
Importslibc y símbolos dinámicos; strcmp, memcmp, ptraceDLL/IAT; lstrcmp*, memcmp, IsDebuggerPresentVe a xrefs de lectura de input, comparación y mensaje de éxito.
EstáticoHeaders, bytes, strings, imports, CFG, decompilado. Es reproducible y no dispara el programa.Empieza aquí; suele bastar para contraseñas, XOR y comparaciones escolares.
DinámicoGDB observa registros/memoria de un ELF autorizado.GDB puede servir con targets compatibles, pero el entorno Windows suele exigir otro depurador; no improvises aquí.Úsalo solo para responder una pregunta concreta que el estático no resolvió.

Ghidra: del import a nombres que expliquen

Descarga Ghidra únicamente desde el repositorio oficial de la NSA ↗. Su documentación de instalación actual pide JDK 21 de 64 bits; revisa allí los avisos de seguridad y la release vigente, sin fijar una versión de Ghidra en tus notas.

  1. Import. Proyecto local → Import File; confirma formato, procesador, endian y compiler spec. Si Ghidra los infiere mal, corrige antes de analizar.
  2. Analyze. Acepta el análisis estándar para el primer pase. Guarda language/compiler, entrypoint, funciones recuperadas y si faltan símbolos.
  3. Encuentra main. Busca el símbolo; si está stripped, parte del entrypoint/runtime y sigue la función pasada al arranque. Alternativamente sigue xrefs desde mensajes de éxito/error.
  4. Decompiler + Listing. Lee el pseudocódigo para orientar el dataflow, pero valida longitud, tipos y salto decisivo en Listing.
  5. Xrefs. Desde una cadena, import o global: References → Show References To. Sigue el caller que consume el input, no cada función del programa.
  6. Rename y tipos. Renombra FUN_*, variables y buffers por hipótesis explícitas: read_candidate, xor_key, expected. Corrige tipos; si una hipótesis cae, renómbrala otra vez.
salida mínima de Ghidra Captura dirección de main/validador, xref que te llevó allí, tres nombres semánticos y una frase de dataflow. Si llevas 20 minutos renombrando helpers sin acercarte a la rama de éxito, vuelve a las cadenas e imports.

radare2: recorrido corto y auditable

Usa como referencia el libro oficial de radare2 ↗. Los comandos siguientes abren para análisis, no escriben el archivo.

Mapa inicial

r2 -A ./reto afl iz s main pdf pdc

-A analiza; afl lista funciones; iz lista strings; pdf muestra el desensamblado de la función y pdc una vista pseudocódigo. Si no hay main, empieza en entry0 o desde xrefs.

De una pista a su uso

iz~Correct axt @ str.Correcto s <direccion_del_xref> pdf @ sym.main pdc @ sym.main

axt lista referencias hacia la dirección. Repite sobre imports como sym.imp.strcmp o sobre el buffer esperado. Nombra hallazgos con afn check_flag @ <addr> y guarda direcciones en la bitácora.

Cuándo sí pasar a GDB

SeñalPregunta concretaObservación mínima en VM
Valor solo existe en runtime¿Qué buffer queda justo antes de memcmp?breakpoint en la comparación; inspecciona argumentos según ABI y memoria, luego termina.
Bucle byte a byte confuso¿Qué índice/byte provoca la primera divergencia?breakpoint en el salto de fallo; registra índice, candidato y esperado.
Indirectas o símbolos ausentes¿Qué función se llama realmente?breakpoint por dirección del call; stepi hasta el destino.
Anti-debug básico¿La rama depende de ptrace u otra comprobación?confirma el call y la rama; explica el mecanismo antes de modificar nada.

No abras GDB “para ver qué pasa”. Hazlo únicamente con un ELF de reto autorizado en una VM aislada y una hipótesis escrita. Si la respuesta ya está en el estático, ejecutar añade riesgo sin añadir evidencia.

Patrones escolares y punto de corte

Contraseña hardcodeada

String legible o bytes globales llegan a strcmp/memcmp. Sigue xrefs y confirma la rama de éxito; no entregues la primera palabra “secreta” que veas.

8 min · strings → xref → compare

Comparación byte a byte

Loop sobre índice, fallo temprano y longitud fija. Recupera orden, terminador y transformaciones previas; cuidado con signed char y off-by-one.

15 min · tabla índice/candidato/esperado

XOR / cifrado casero

Busca constante/clave, periodicidad e inversión. XOR se deshace con la misma operación; suma/rotación requieren respetar ancho y overflow.

18 min · reconstruye 4 bytes antes de escalar

UPX

Secciones/nombres, pocos imports y entry stub sugieren packing, no lo prueban. Confirma firma y versión compatible antes de intentar desempacar una copia.

10 min · si falla, no inventes flags de upx

Anti-debug básico

ptrace, IsDebuggerPresent, timing o lectura de estado alteran una rama. Identifica check → retorno → salto; parchear a ciegas oculta la lógica.

15 min · explica el mecanismo o aparca

Fuera de alcance

VMs custom, múltiples capas, drivers, ofuscación pesada o anti-VM sostenido no caben en este bloque. Conserva hash/notas y cambia de reto.

30 min sin dataflow nuevo · aparcar
UPX y anti-debug no autorizan ejecución En una muestra permitida, primero verifica firmas y documentación. Desempaca solo una copia dentro de la VM, conserva hash del original y del derivado, y mantén la red apagada. Nunca pruebes una muestra real desde esta guía.

Micro-reto local: reconstruye la flag

Lee este pseudocódigo como decompilado: identifica input, transformación, esperado y condición de éxito. Resuelve a mano o con una nota local y pega la flag completa. Este ejercicio entrena lectura de dataflow; no sustituye analizar un binario, su layout, xrefs ni instrucciones.

check_candidate.c · pseudocódigo reconstruido
bool check_candidate(char *candidate) {
    uint8_t expected[15] = {
        0x60, 0x77, 0x65, 0x58, 0x57,
        0x51, 0x4a, 0x42, 0x44, 0x46,
        0x7c, 0x5b, 0x4c, 0x51, 0x5e
    };

    if (strlen(candidate) != 15) return false;
    for (int i = 0; i < 15; i++) {
        if ((candidate[i] ^ 0x23) != expected[i]) return false;
    }
    return true;
}

Ruta externa mínima · en este orden

Los catálogos cambian: usa categorías y criterios vigentes, no nombres congelados. No descargues una colección; elige un solo artefacto autorizado y registra su hash.

  1. 35 min · mínimo

    1 · Documentación oficial

    Reproduce el flujo de esta hoja sobre un binario propio trivial usando el repositorio oficial de Ghidra y el libro oficial de radare2 enlazados arriba. Debes llegar al mismo validador por decompiler y por iz → axt → pdf/pdc.

    salida: SHA-256 + dirección del validador + xref + tres nombres semánticos
  2. 45 min · mínimo

    2 · picoCTF / picoGym

    Entra por la guía oficial de picoCTF ↗, abre picoGym y filtra Reverse Engineering. Elige un reto vigente de dificultad inicial que entregue un binario; aplica el pipeline completo antes de consultar pistas.

    salida: 1 flag + write-up: identidad, hash, pista, xref, transformación y corte
  3. opcional · solo con aislamiento preparado

    3 · crackmes.one

    Lee primero y entra únicamente por la FAQ de crackmes.one ↗. No se enlaza ningún crackme concreto: tú validas licencia, plataforma y dificultad antes de descargar.

    condición de entradaVM aislada y desechable · snapshot limpio · red deshabilitada antes de abrir el archivo · sin carpetas compartidas, portapapeles ni credenciales. Si no puedes cumplir las cinco, omite esta parada.
    salida: criterio de selección + hash + análisis estático; ejecución no requerida
bitácora de competencia 0–5 min: identidad/hash/strings · 5–15: imports/secciones/main · 15–30: xrefs y transformación · 30 min: decide resolver, pedir pista o aparcar. Reanuda solo si puedes escribir qué evidencia nueva buscas.
← anterior · bloque 2 siguiente · bloque 4 → exfiltración + simulacro
ctf_manual · carril avanzado · bloque 3 · malware / reversing clásico inicio