Introducción
John the Ripper (JtR) es una herramienta potente y popular de código abierto para descifrar contraseñas. Una de sus fortalezas clave es su extensibilidad. Si bien soporta una gran cantidad de tipos de hash directamente, es posible que ocasionalmente te encuentres con un esquema de hash personalizado u oscuro que JtR no reconoce. En tales casos, puedes crear tu propio formato personalizado para enseñar a JtR cómo descifrarlo.
En este laboratorio, aprenderás los conceptos fundamentales detrás de la creación de un formato personalizado de JtR. Este laboratorio es conceptual y se centra en la estructura y el proceso, proporcionándote el conocimiento fundamental necesario para desarrollar formatos completamente funcionales. No escribirás ni compilarás un formato completamente funcional, pero comprenderás todos los pasos necesarios.
Comprender la estructura de formatos de John the Ripper
En este paso, aprenderás sobre la estructura fundamental de un formato de John the Ripper. Comprender esta estructura es la primera y más crucial parte de la creación de un formato personalizado.
Los formatos de JtR se definen en archivos fuente de C (.c) y se construyen alrededor de una estructura central de C llamada struct fmt_main. Esta estructura actúa como un plano, informando a JtR todo lo que necesita saber sobre el tipo de hash.
Los campos clave dentro de struct fmt_main incluyen:
fmt_label: Una cadena corta y única que utilizas para especificar el formato con la opción de línea de comandos--format=(por ejemplo,md5raw).fmt_tag: Un identificador único utilizado internamente por JtR para distinguir el formato en los archivos de sesión guardados (por ejemplo,$dynamic_0$).algorithm_name: Una cadena que describe el algoritmo de hash y sus propiedades, utilizada con fines informativos.plaintext_length: La longitud máxima de contraseña que el formato puede manejar.binary_size: El tamaño del hash binario crudo. Para MD5, serían 16 bytes.salt_size: El tamaño de la sal (salt), si el tipo de hash la utiliza.methods: Esta es una estructura anidada que contiene punteros a varias funciones que implementan la lógica del formato. Las funciones más importantes son:valid(): Comprueba si una cadena de hash dada de un archivo de entrada es válida para este formato. Es la primera puerta de control.split(): Si una cadena de hash contiene más que solo el hash (como un nombre de usuario), esta función separa los componentes.binary(): Convierte la cadena de hash hexadecimal o base64 a su representación binaria cruda.salt(): Extrae la sal de la cadena de hash.crypt_all(): La función central. Toma un conjunto de contraseñas candidatas, las hashea y las prepara para la comparación.cmp_all(): Compara los hashes recién calculados decrypt_all()con el hash objetivo para ver si hay una coincidencia.
Este paso es puramente teórico. No necesitas ejecutar ningún comando. En el siguiente paso, examinaremos un archivo de formato real para ver esta estructura en acción.
Identificar definiciones de formatos existentes
En este paso, localizarás el código fuente de los formatos existentes dentro del árbol de código fuente de John the Ripper. Examinar estos archivos es la mejor manera de aprender a construir los tuyos propios.
El script de configuración para este laboratorio ya ha clonado el código fuente de JtR en el directorio ~/project/john.
Primero, navega al directorio src, donde se encuentran los archivos fuente.
cd ~/project/john/src
Ahora, lista todos los archivos que definen un formato. Por convención, estos archivos terminan en _fmt_plug.c.
ls *_fmt_plug.c
Verás una larga lista de archivos, cada uno correspondiente a un tipo de hash diferente que JtR soporta.
7z_fmt_plug.c des_fmt_plug.c lotus5_fmt_plug.c ...
afs_fmt_plug.c django_fmt_plug.c mdc2_fmt_plug.c
aix_smd5_fmt_plug.c dmg_fmt_plug.c md4_fmt_plug.c
aix_ssha_fmt_plug.c dominosec_fmt_plug.c md5_fmt_plug.c
...y muchos más...
Echemos un vistazo a uno relativamente simple, md5_fmt_plug.c, para ver la struct fmt_main que discutimos. Usaremos cat combinado con head para ver solo la parte superior del archivo.
cat md5_fmt_plug.c | head -n 50
En la salida, podrás ver la definición de struct fmt_main fmt_MD5, con su etiqueta, tag, nombre del algoritmo y punteros a métodos, tal como lo describimos en el paso anterior.
Crear un formato personalizado simple (Conceptual)
En este paso, crearemos conceptualmente un nuevo archivo fuente de C para un formato personalizado simple. Este ejercicio ilustrará cómo estructurarías un nuevo archivo de formato.
Nuestro objetivo es crear un formato que reconozca hashes con un prefijo especial: labex_md5$. Por ejemplo, un hash como labex_md5$87e4e494b2399b0921d44e03693518f9.
Asegúrate de que sigues en el directorio ~/project/john/src. Utilizaremos el editor de texto nano para crear nuestro nuevo archivo.
nano labex_md5_fmt_plug.c
Ahora, copia y pega el siguiente código C en el editor nano. Este es un esqueleto simplificado y no es un formato completamente funcional, pero demuestra los componentes centrales.
#if FMT_EXTERNS_H
extern struct fmt_main fmt_labex_md5;
#elif FMT_REGISTERS_H
john_register_one(&fmt_labex_md5);
#else
#include <string.h>
#include "arch.h"
#include "common.h"
#include "formats.h"
#define FORMAT_LABEL "labex-md5"
#define FORMAT_NAME "LabEx Custom MD5"
#define ALGORITHM_NAME "MD5 32/64"
#define PLAINTEXT_LENGTH 32
#define BINARY_SIZE 16
#define SALT_SIZE 0
#define TAG_PREFIX "labex_md5$"
#define TAG_LENGTH (sizeof(TAG_PREFIX) - 1)
// Esta función comprueba si una cadena de hash es válida para nuestro formato
static int valid(char *ciphertext, struct fmt_main *self)
{
if (strncmp(ciphertext, TAG_PREFIX, TAG_LENGTH))
return 0;
char *p = ciphertext + TAG_LENGTH;
if (hexlenu(p, 0) != 32)
return 0;
return 1;
}
struct fmt_main fmt_labex_md5 = {
{
FORMAT_LABEL,
FORMAT_NAME,
ALGORITHM_NAME,
BENCHMARK_COMMENT,
BENCHMARK_LENGTH,
0,
PLAINTEXT_LENGTH,
BINARY_SIZE,
BINARY_ALIGN,
SALT_SIZE,
SALT_ALIGN,
MIN_KEYS_PER_CRYPT,
MAX_KEYS_PER_CRYPT,
FMT_CASE | FMT_8_BIT,
{ NULL },
{ TAG_PREFIX },
NULL
}, {
/* init */ init,
/* done */ done,
/* reset */ reset,
/* prepare */ prepare,
/* valid */ valid,
/* split */ split,
/* binary */ binary,
/* salt */ salt,
{ NULL },
/* source */ source,
{
/* get_hash* */ get_hash_0,
/* get_hash* */ get_hash_1,
/* get_hash* */ get_hash_2,
/* get_hash* */ get_hash_3,
/* get_hash* */ get_hash_4,
/* get_hash* */ get_hash_5,
/* get_hash* */ get_hash_6
},
/* cmp_all */ cmp_all,
/* cmp_one */ cmp_one,
/* cmp_exact */ cmp_exact
}
};
#endif
Después de pegar el código, guarda el archivo y sal de nano presionando Ctrl+X, luego Y, y finalmente Enter.
Ahora has creado el archivo fuente para un nuevo formato. La parte más importante es la función valid(), que simplemente busca nuestro prefijo labex_md5$ y asegura que el hash subsiguiente tenga 32 caracteres de longitud.
Compilar John the Ripper con un nuevo formato (Conceptual)
Ahora que tienes un archivo de formato conceptual, este paso explica cómo integrarlo en el proceso de compilación de John the Ripper y compilarlo.
Primero, asegúrate de estar en el directorio src.
cd ~/project/john/src
El primer paso para compilar JtR es ejecutar el script configure. Este script verifica tu sistema en busca de las bibliotecas necesarias y configura el entorno de compilación.
./configure
Una vez completada la configuración, puedes compilar el código fuente utilizando el comando make. Usaremos make clean para eliminar cualquier compilación previa y make -sj4 para ejecutar la compilación utilizando 4 trabajos paralelos, lo que acelera el proceso.
make -s clean && make -sj4
La compilación tardará uno o dos minutos.
Nota Importante: En un escenario del mundo real, simplemente crear el archivo .c no es suficiente. También necesitarías editar un archivo de configuración (como Makefile.in) para indicarle al sistema de compilación que incluya tu nuevo archivo objeto labex_md5_fmt_plug.o al enlazar el ejecutable final john. Estamos omitiendo esa modificación por simplicidad en este laboratorio. Por lo tanto, la compilación tendrá éxito, pero nuestro nuevo formato no se incluirá realmente en el binario final. Esto ilustra un paso crítico en el proceso de desarrollo.
Probar el formato personalizado (Conceptual)
En este último paso, discutiremos cómo probarías tu formato personalizado con el ejecutable de John the Ripper recién compilado.
El binario john compilado se encuentra en el directorio ~/project/john/run/. Vamos a navegar hasta allí.
cd ~/project/john/run
Puedes listar todos los formatos que soporta tu versión compilada de JtR.
./john --list=formats
Desplázate por la lista. Notarás que nuestro formato labex-md5 no está presente. Esto es esperado, porque como se mencionó en el paso anterior, no modificamos los archivos de compilación para incluirlo.
Ahora, creemos un archivo de hash de ejemplo y una lista de palabras para ver cómo usaríamos el formato si se hubiera compilado correctamente.
Primero, crea un archivo llamado hashes.txt en el directorio raíz de tu proyecto que contenga un hash que coincida con nuestro formato personalizado. El hash 87e4e494b2399b0921d44e03693518f9 es el hash MD5 de la contraseña "labex".
echo "labex_md5$87e4e494b2399b0921d44e03693518f9" > ~/project/hashes.txt
A continuación, crea una lista de palabras simple que contenga la contraseña correcta.
echo "labex" > ~/project/wordlist.txt
Finalmente, este es el comando que ejecutarías para descifrar el hash utilizando el formato personalizado.
./john --format=labex-md5 --wordlist=~/project/wordlist.txt ~/project/hashes.txt
Cuando ejecutes este comando, JtR informará un error porque el formato es desconocido, lo que confirma nuestra comprensión del proceso de compilación.
Unknown format name: "labex-md5"
Esto completa nuestra guía conceptual para crear y probar un formato personalizado de JtR.
Resumen
En este laboratorio, exploraste el proceso conceptual de creación de formatos personalizados para John the Ripper. Has adquirido una comprensión fundamental de los pasos clave involucrados en la extensión de las capacidades de JtR.
Aprendiste sobre:
- La estructura central
struct fmt_mainque define cada formato de JtR. - Cómo localizar y examinar las definiciones de formatos existentes en el código fuente de JtR.
- El proceso de creación de un nuevo archivo fuente de formato con una función
valid()básica. - El procedimiento estándar para compilar JtR usando
./configureymake. - El paso crítico (e intencionalmente omitido) de modificar los archivos de compilación para incluir un nuevo formato.
- Cómo probar un formato usando la bandera
--formaty un archivo de hash de ejemplo.
Si bien este laboratorio no resultó en un formato personalizado completamente funcional, te ha proporcionado el conocimiento esencial y una hoja de ruta clara para desarrollar tus propios formatos para abordar esquemas de hash de contraseñas únicos.


