Skip to content

Ataques

1. Ataques a cifrados

1.1. Clasificación de ataques

Los ataques a un criptosistema se clasifican según la información que el atacante debe conocer para romperlo. El objetivo siempre es el mismoobtener la clave de cifrado. Estos son:

Ataque Descripción Ejemplo
CO - Ciphertext-Only El atacante conoce el algoritmo de cifrado (normalmente público) y solo dispone de textos cifrados. El cifrado César
KPA - Known-Plaintext-attacks El atacante conoce el algoritmo de cifrado y además dispone de algunos pares texto plano–texto cifrado para intentar deducir la clave o el método de descifrado. Un ejemplo es con un cifrado XOR: si se tiene el texto original y el texto cifrado, se puede obtener la clave aplicando XOR.
CPA - Chosen-Plaintext-attacks El atacante tiene acceso a un servicio de cifrado y puede elegir qué texto cifrar y ver el resultado cifrado, sin necesidad de interceptar comunicaciones. Un ejemplo es una aplicación web que cifra automáticamente cookies de sesión, por ejemplo user:nombre_de_usuario; el atacante puede enviar valores escogidos para ver cómo se cifran.
CCA - Chosen-Ciphertext-attacks El atacante, además de tener el texto cifrado, tiene acceso a un sistema de descifrado y puede enviar textos cifrados (legítimos o modificados) para ver su resultado descifrado. Un ejemplo son los ataques de “padding oracle”, en los que se modifica ligeramente el texto cifrado y se usan los mensajes de error para inferir información sobre la clave o el texto plano.

Hay varias maneras de romper un cifrado, que recordemos era o infiriendo la clave de descifrado o encontrando alguna vulnerabilidad en los algoritmos como repeticiones o patrones.

Espacio de claves

El espacio de claves es el número total de combinaciones posibles para una contraseña dada una longitud y un conjunto de caracteres.

En el Cifrado César, el espacio de claves es de "27" posibilidades, que son todos los desplazamientos posibles del alfabeto. En este caso da igual la longitud del texto cifrado.

Esto es una buena medida para evaluar si una contraseña es robusta o no. Esto sigue esta función matemática:

número de caracteres posibles^longitud de la contraseña = Espacio de claves
5 dígitos alfanuméricos -> 62^5 = 916.132.832 combinaciones


1.2. Clasificación de ataques

Es un método de ataque que consiste en probar claves candidatas de forma sistemática hasta encontrar la correcta. Suele aplicarse en escenarios de texto cifrado conocido (CO).

Puede haber dos modalidades:

Ataque Descripción
Ataque de diccionario Se prueba con una lista de claves predefinidas probables (un diccionario). Es más rápido, pero solo funciona si la clave real está incluida en esa lista. Ej: pass123, abc123, 000000...
Fuerza bruta pura Se prueban todas las combinaciones posibles de caracteres (más lento y exhaustivo). Es más costoso, pero cubre todo el espacio de claves; aunque solo funciona si recorrer ese espacio lleva un tiempo o recursos viables. Ej: 000000, 000001, 000002...

También dos variantes según el tipo de dato:

  • Sobre texto cifrado: el atacante descifra el texto cifrado con cada clave candidata hasta obtener un resultado que tenga sentido o un formato esperado. Por ejemplo, el texto resultante sea "Hola" en lugar de b'3_1

  • Sobre hashes de contraseñas: cuando solo se tiene un hash y no un texto cifrado, no se puede descifrar directamente. En su lugar se calcula el hash de cada candidato y se compara bit por bit con el hash original hasta encontrar coincidencia.


2. Cracking de hashes

Es común almacenar las contraseñas hasheadas en bases de datos y sistemas. El hashing es un proceso unidireccional, por tanto el enfoque de los ataques será el de probar numerosas cadenas de texto plano hasta dar una que produzca el mismo hash. Esto demostrará que esa cadena es la contraseña original.

Las técnicas comunes son usar tablas arcoíris (rainbow tables), realizar ataques de diccionario (dictionary attacks) y, típicamente como último recurso, realizar ataques de fuerza bruta (brute-force attacks).


2.1. Las rainbow tables

Las tablas arcoíris son grandes mapas precompilados de valores de entrada y salida para una función de hash determinada. Se pueden usar para identificar muy rápidamente la contraseña si su hash correspondiente ya ha sido mapeado.

# valores en texto plano 🡆 MD5
123456 -> e10adc3949ba59abbe56e057f20f883e
12345 -> 827ccb0eea8a706c4c34a16891f84e7b
password -> 5f4dcc3b5aa765d61d8327deb882cf99

La salt

Para evitar estos ataques se utiliza el salting, dónde se añade la salt, una secuencia aleatoria de bytes que se añade a una contraseña antes de que sea hasheada. Estas salts no se deben repetir para todas las contraseñas de una base de datos.

Por ejemplo, si la salt Th1sIsTh3S@lt_ se antepone a la misma contraseña, el hash MD5 ahora sería el siguiente:

$: echo -n Th1sIsTh3S@lt_Soccer06! | md5sum  
# 90a10ba83c04e7996bc53373170b5474

Una salt no es un valor secreto; cuando un sistema va a verificar una solicitud de autenticación, necesita saber qué salt se utilizó para poder comprobar si el hash de la contraseña coincide.

Por esta razón, las salts suelen anteponerse a los hashes correspondientes. Para lo uníco que sirven las salts es para que la contraseña mapeada en la tabla arcoiris no coincida

Para que las tablas arcoíris vuelvan a ser efectivas, un atacante necesitaría actualizar su mapeo para tener en cuenta cada salt posible. Una salt que consista en un solo byte significaría que los 15 mil millones de entradas anteriores tendrían que convertirse en 3.84 billones (factor de 256).


2.2. Ataques de fuerza bruta

Un ataque de fuerza bruta implica probar cada combinación posible de letras, números y símbolos, hashearlos y comparar este hash con el dado hasta descubrir la contraseña correcta. Esto hace que sea una ténica 100% efectiva.

Obviamente si la contraseña es lo suficientemente larga y tiene gran variedad de caracteres, este proceso puede alargarse hasta necesitar recursos de almacenamiento y tiempo inviables.

Diccionarios con crunch

Con la herramienta crunch podemos crear diccionarios de manera automática. Solo hay que seguir esta sintaxis

$: crunch <longitud> <caracteres> -o <diccionario>

El problema esque el escalado es exponencial. Por ejemplo, para un diccionario de 4 letras y 36 caracteres alfanuméricos, obtenemos 8MB. En cambio si aumentamos a 6 caracteres, pesará unos 14GB. 36^6 = 2.176.782.836 (más de dos billones) = 14 Gigas aprox


Diccionarios personalizados

Como muchos usuarios crean contraseñas simples, los sistemas implementan la política de contraseñas para hacer cumplir requisitos específicos: una longitud mínima y requieren al menos un carácter especial. Esto hace que la fuerza bruta sea más compleja, pero aun así la gente syele usar patrones predecibles al crear contraseñas (el nombre de la empresa, de amigos, mascotas o hobbys).

Mediante técnicas OSINT se puede averiguar datos personales de la víctima y crear un diccionario personal. Para ello podemos usar la herramienta cewl, que nos permite escanear las posibles palabras del sitio web de una empresa y guardarlas en una lista separada

cewl https://web.com -d 4 -m 6 --lowercase -w web.wordlist
# -d 4 : profundidad de rastreo
# -m 6 : longitud mínima de la palabra 
# --lowercase: guardarlo en minusculas

Luego podemos aplicar mutaciones para conseguir una lista mayor y aumentar las probabilidades de contener la contraseña correcta de un empleado.


Mutaciones

Podemos usar hashcat para generar listas de posibles nombres y etiquetas con reglas de mutación específicas

Función Descripción
: No hacer nada
l Poner todas las letras en minúscula
u Poner todas las letras en mayúscula
c Poner en mayúscula la primera letra y en minúscula las demás
sXY Reemplazar todas las instancias de X por Y
$! Añadir el carácter de exclamación al final

Tanto Hashcat como JtR vienen con listas de reglas predefinidas que se pueden usar para la generación y el cracking de contraseñas. Uno de los conjuntos de reglas más efectivos y ampliamente utilizados es best64.rule, que aplica transformaciones comunes que frecuentemente resultan en adivinaciones de contraseñas exitosas.

hashcat --force password.list -r best64.rule --stdout | sort -u > mut_password.list


2.3. Ataque de diccionario

Este ataque consiste tambien en hashear valores posibles hasta dar con el que coincida, solo que con la diferencia de que tenemos una lista de palabras comunes en lugar de todas las posibles. Esta lista se denomina diccionario y la efectividad del ataque dependerá de que la contraseña elegida se encuentre allí.

Los diccionarios más famosos son rockyou.txt y las incluidas en SecLists y las herramientas son john the ripper y hashcat.


John the ripper

John the Ripper (john) es una herramienta de pentesting de código abierto desarrollado utilizada para descifrar contraseñas a través de varios ataques, como los de fuerza bruta y de diccionario.

Esta herramienta cuenta con los siguientes modos:

  • El modo single crack: es muy útil con credenciales Linux. Genera contraseñas posibles tomando datos como el nombre de usuario de la víctima, el nombre de su directorio personal y los valores GECOS (nombre completo, teléfono, etc...) y aplicando modificaciones comunes como añadir números o cambiar mayusculas y minusculas.

  • El modo Wordlist: utiliza un ataque de diccionario. Aun así se pueden aplicar transformaciones con el parámetro --rules

  • Modo incremental: utiliza un ataque de fuerza bruta generando contraseñas basándose en un modelo estadístico (acena de markov) dçonde prioriza las más probables. Este modo es el más exhaustivo, pero también el que más tiempo consume.

$: cat hash
# r0lf:$6$ues25dIanlctrWxg$nZHVz2z4kCy176(...)y3/:0:0:Rolf Sebastian:/home/r0lf:/bin/bash
$: john --single hash # modo single crark
$: john -w=/usr/share/wordlists/rockyou.txt # modo wordlist
$: john --incremental hash

Historial

John guarda el historial de hashes crackeados en el archivo ~/.john/john.pot. Por tanto si le pedimos que vuelva a crackear de nuevo un hash, nos saldrá un mensaje que nos dice que no queda nada para crackear.

Para ver el hash de nuevo tenemos que poner john --show hash.txt --format=raw-sha256

Puede que la herramienta no sepa identificar el formato del hash, por lo que habrá que especificarlo explicitamente mediante un parámetro. En el caso de john el parámetro es --format. Por ejemplo crypt para hashes del shadow

$: john -w=/usr/share/wordliss/rockyou.txt --format=crypt 

Una forma de hacerse una idea es consultar la documentación de hashes de ejemplo de JtR, o esta lista de PentestMonkey. Ambas fuentes enumeran múltiples hashes de ejemplo, así como el formato de jhon correspondiente.


Hashcat

Hashcat es otra herramienta famosa de cracking que lleva siendo open source desde el 2015. A diferencia de john, esta se apoya principalmente en la GPU.

Sigue esta sintaxis:

hashcat -a 0 -m 0 <hashes> [wordlist, rule, mask, ...]
# -a: especifica el modo de ataque (attack mode)
# -m: especifica el tipo de hash

Diferentes tipos de hash

Con hascat -h podemos listar los hashes posibles, aunque la web de la herramienta aloja una lista completa de hashes de ejemplo que puede ayudar a identificar manualmente un tipo de hash desconocido y determinar el identificador de modo de hash de Hashcat correspondiente.

$: hashcat -a 0 -m 0 hash /usr/share/wordlists/rockyou.txt
$: hashcat -m 1000 hashes.txt /usr/share/wordlists/rockyou.txt # hashes NTLM
$: hashcat -m 2100 security /usr/share/wordlists/rockyou.txt # hashes DCC2

# Aplicar reglas (modificaciones)
$: hashcat -a 0 -m 0 hash /usr/share/wordlists/rockyou.txt -r /usr/share/hashcat/rules/best64.rule

Ataque de mascara

El Ataque de máscara (-a 3) es un tipo de ataque de fuerza bruta dónde el usuario define el espacio de claves (

Ej: Sabemos que la contraseña utiliza 8 caracteres y queremos probar combinaciones de seis letras seguidas de dos números)

Símbolo Conjunto de caracteres Símbolo caracteres
?l letras minusculas ?H hexadecimal en mayusculas
?u letras mayusculas ?s caracteres especiales
?d digitos ?a Todos los caracteres
?h hexadecimal (digitos y letras hasta la "f") ?b
bytes: 0x00 - 0xff

Ej: comenzar con una mayúscula continua con cuatro minúsculas, un dígito y luego un símbolo -> ?u?l?l?l?l?d?s.

hashcat -a 3 -m 0 hash '?u?l?l?l?l?d?s'  


2.4. Descifrar archivos

También es posible descifrar archivos protegidos por contraseña o cifrados con JtR.

JtR viene con múltiples herramientas "2john" que se pueden utilizar para procesar archivos y producir hashes compatibles con JtR. La sintaxis general para estas herramientas es:

$: locate *2john* | grep SSH    # Buscar el que nos interesa ssh2john.py
$: ssh-keygen -yf ~/.ssh/id_rsa # comprobar si la clave priavada está cifrada
$: ssh2john.py SSH.private > ssh.hash
$: john --wordlist=rockyou.txt ssh.hash

Descifrado de comprimidos

Existen muchos tipos de archivos comprimidos. Algunas de las extensiones de archivo más comunes incluyen targzrarzipvmdb/vmxcpttruecryptbitlockerkdbxdeb7z y gzip.

  • La mayoría, como los zips se pueden crackear con herramientas tipo 2john

  • Otros no tienen cifrado nativo, por lo que se suelen usar herramientas adicionales como openssl o gpg.

Podemos ver si el archivo está cifrado con file y tratar de descifrarlo:

$: file GZIP.gzip # GZIP.gzip: openssl enc'd data with salted password
$: for i in $(cat rockyou.txt); do \
    openssl enc -aes-256-cbc -d -in GZIP.gzip -k $i 2>/dev/null | tar xz; done


Descifrado de Bitlocker

BitLocker es una función de cifrado de disco completo (full-disk encryption) desarrollada por Microsoft para Windows. Disponible desde Windows Vista, utiliza el algoritmo de cifrado AES con longitudes de clave de 128 o 256 bits. Si se olvida la contraseña o el PIN utilizado para BitLocker, el descifrado aún se puede realizar utilizando una clave de recuperación, una cadena de 48 dígitos generada durante el proceso de configuración.

Para descifrar una unidad cifrada con BitLocker, podemos usar un script llamado bitlocker2john para obtener 4 hashes: los dos primeros corresponden a la contraseña de BitLocker, mientras que los dos últimos representan la clave de recuperación (demasaido larga)

$: bitlocker2john -i Backup.vhd > backup.hashes
$: grep "bitlocker\$0" backup.hashes > backup.hash
$: hashcat -a 0 -m 22100 backup.hash /usr/share/wordlists/rockyou.txt

Es posible montar unidades cifradas BitLocker en Linux (o macOS) gracias al paquete disclocker

$: sudo mkdir -p /media/bitlocker && sudo mkdir -p /media/bitlockermount
$: sudo losetup -f -P Backup.vhd # Configuramos el VHD como un loop device
$: sudo dislocker /dev/loop0p2 -u1234qwer -- /media/bitlocker
$: sudo mount -o loop /media/bitlocker/dislocker-file /media/bitlockermount
$: cd /media/bitlockermount/


3. Ataques a RSA

¿Porqué las claves RSA deben ser largas? Vamos a demostrar que pasa si tenemos una clave absurdamente corta. Nos dan una clave pública (public.pem) y un mensaje cifrado con ella. Debemos obtener su correspondiente clave privada para descifrar el mensaje.

Las claves RSA están basadas en una compleja función matemática en la que entran en juego cinco números llamados p, q, n, e, d. Dos de ellos, e y n, los podemos obtener mediante la librería pycrypto de python que se instala con pip install pycryptodome

#!/usr/bin/python3
from Crypto.PublicKey import RSA
with open("./public.pem") as f:
  key = RSA.importKey(f.read());
  print(f"e: {key.e}, n: {key.n}")

Ahora, n es el resultado de multiplicar dos números primos p y q, que debemos obtener para para sacar el resto y fabricar la clave privada. Obtener estos números se denomina "factorizar" y para para ello nos serviremos de esta web

Una vez obtenidos los números, hay que crear este script de python con el que crear la clave privada. El script obtiene un numero m, que utiliza para sacar el número d mediante una operación llamada "algoritmo extendido de Euclides". Las matemáticas involucradas no nos son relevantes, ya que tenemos un par de funciones que realizarán esta tarea.

#!/usr/bin/python3
from Crypto.PublicKey import RSA
p =  ; q =  ; e =  ; # rellenar con los valores que nos han dado
n = p*q; m = n-(p+q-1); d = pow(e,-1,m)
key = RSA.construct((n,e,d,p,q)); print(key.exportKey().decode())

Obtenemos por tanto la clave privada con la que descifrar el mensaje openssl pkeyutl -decrypt -inkey privada.pem -in mensaje.enc