El enunciado del reto decía lo siguiente:
"Una técnica esteganográfica relativamente habitual consiste en utilizar el relleno para ocultar información, entendiendo éste como aquellos métodos que introducen información irrelevante con ciertos fines en mensajes, imágenes y, en general, cualquier tipo de objeto. Por ejemplo, tal y como se explicaba en este post, en un archivo bmp los valores correspondientes a cada línea de la imagen se disponen de izquierda a derecha con una longitud de línea múltiplo de 4 Bytes, agregándose en caso necesario los Bytes con valor 0 que se precisen hasta completar la longitud múltiplo de 4. Estos Bytes de relleno se ignoran a la hora de visualizar la imagen, por lo que su contenido no afecta a su visualización, y son precisamente esos Bytes de relleno los que se pueden utilizar para ocultar un mensaje y, por tanto, se podría utilizar la imagen como objeto portador del secreto que pretendemos esconder a los ojos de aquellos con acceso al canal de comunicación empleado pero a los que no va destinado".
Y como recurso asociado al reto se proporcionaba el siguiente: Reto33.jpg.
Solución: tal y como decía en la primera pista que puse para ayudar a resolver este reto, en los retos de esteganografía los metadatos pueden contener información valiosa, por lo que voy a investigar los metadatos del archivo asociado al reto (Reto33.jpg), por ejemplo con 'ExifToolGUI':
Veo que en 'Comment' hay un valor codificado en base64: "UGFzc3dvcmQ6IHIzMTEzbjA=", que decodifico utilizando una herramienta 'online', por ejemplo 'CyberChef':
Y parece que tengo una contraseña, pero: ¿para utilizar dónde?, ¿con qué software?.
Veo que en 'Software' hay también un valor codificado en base64 ("c3RlZ2hpZGU=") que decodifico con la misma herramienta 'online':
Por lo que ya sé el software utilizado para ocultar el mensaje, 'steghide'.
Voy a ver que obtengo con ese software y la contraseña hallada:
Evidentemente, lo primero que hago es decodificar estas líneas para ver el texto en claro, lo que hago usando la misma herramienta 'online' que la utilizada para ello en este reto hasta este momento, 'CyberChef':
Y lo que obtengo al decodificar el contenido del archivo extraído es un texto en claro que habla sobre la esteganografía, pero en el que no veo cuál es la solución al reto.
Sin embargo, parece claro que la solución debe estar oculta, de una forma u otra, en la información extraída, y es aquí cuando tanto el título del reto como la segunda pista que puse para ayudar a resolverlo nos dan la clave para buscar la solución. ¿Cómo se codifica en base64?, ¿Qué significa el carácter "=" que pueden aparecer, uno o dos, al final de la cadena codificada?.
Pues bien, el símbolo "=" es el carácter de relleno y para verlo más claramente pongo ejemplos de codificación base64 y de cuándo y cómo se utiliza el relleno (se incluye/n uno o dos caracteres "="):
1.- Base64 codifica o convierte tres caracteres ASCII (3 x 8 = 24 bits) en cuatro caracteres codificados (4 x 6 = 24 bits). Por ejemplo:
En este caso, tal y como se observa, no es necesario añadir relleno, ya que el último bloque codificado (codificación de menos de 4 caracteres ASCII, en el ejemplo 3) tiene un tamaño de 24 bits.
2.- Supongo ahora que el último bloque codificado (codificación de menos de 4 caracteres ASCII) es de 2. Por ejemplo:
En este caso, para que el último bloque codificado tenga un tamaño de 24 bits se le añaden 2 bits de relleno a cero más un carácter "=" que le indica al decodificador que ignore los dos últimos bits de relleno a cero y a él mismo.
3.- Supongo ahora que el último bloque codificado (codificación de menos de 4 caracteres ASCII) es de 1. Por ejemplo:
En este caso, para que el último bloque codificado de caracteres ASCII tenga un tamaño de 24 bits se le añaden 4 bits de relleno a cero más dos caracteres "=" que le indican al decodificador que ignore los cuatro últimos bits de relleno a cero y a ellos mismos.
En resumen: si la cadena codificada no tiene ningún carácter de relleno no hay bits de relleno a cero al final de la misma, si tiene 1 carácter de relleno ("=") hay dos bits de relleno a cero antes del carácter "=", y si tiene 2 caracteres de relleno ("==") hay cuatro bits de relleno a cero antes de éstos.
Y, como en el reto, son precisamente estos caracteres de relleno los que se pueden utilizar para ocultar información, ya que como se ignoran en la decodificación su contenido no afecta a ésta.
Por tanto, para obtener la solución al reto bastará con ir extrayendo los bits de relleno, concatenarlos en grupos de 8 bits y obtener los valores ASCII correspondientes a dichos octetos.
Para verlo más claro obtengo a mano el primer carácter de la solución al reto (los bits de relleno se resaltan en color rojo):
- Primer código base64:
TGEgZXN0ZWdhbm9ncmFmw61hIChkZWwgZ3JpZWdvIHN0ZWdhbm9zLCAiY3ViaWVydG8iIHUgIm9jdWx0byIsIHkgZ3JhcGhvcywgImVzY3JpdHVyYSIp (SIN RELLENO).
- Segundo código base64:
IHRyYXRhIHNvYnJlIGVsIGVzdHVkaW8geSBsYSBhcGxpY2FjacOzbiBkZSB0w6ljbmljYXN= (2 BITS DE RELLENO); Carácter base64 = "N"; Índice base64 = 13; Binario = 001101.
- Tercer código base64:
IHF1ZSBwZXJtaXRlbiBvY3VsdGFyIG1lbnNhamVzIHUgb2JqZXRvcyBkZW50cm8gZGUgb3Ryb3MgbGxhbWFkb3MgcG9ydGFkb3Jlcywg (SIN RELLENO).
- Cuarto código base64:
cGFyYSBzZXIgZW52aWFkb3MgZGUgbW9kbyBxdWUgbm8gc2UgcGVyY2liYSBlbCBoZWNoby4g (SIN RELLENO).
- Quinto código base64:
RXMgZGVjaXIsIHByb2N1cmEgb2N1bHRhciBtZW5zYWplcyBkZW50cm8gZGUgb3Ryb3Mgb2JqZXRvcyC= (2 BITS DE RELLENO); Carácter base64 = "C"; Índice base64 = 2; Binario = 000010.
eSBkZSBlc3RhIGZvcm1hIC== (4 BITS DE RELLENO); Carácter base64 = "C"; Índice base64 = 2; Binario = 000010.
Primer carácter de la solución al reto: 01100010; Carácter ASCII = "b".
Y así sucesivamente.
Para obtener la solución completa al reto, aunque podríamos seguir haciéndolo manualmente, creo el siguiente script en python:
#!/usr/bin/python
import binascii
flag=''
caracteres_base64='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
fichero=open('Reto33.txt','rb')
linea=fichero.readline().rstrip('\n')
while linea!='':
print linea
if linea.find('==')!=-1:
binario=str(bin(caracteres_base64.find(linea[len(linea)-4]))[2:8].zfill(4))
bits_ocultos=binario[len(binario)-4:len(binario)]
flag+=bits_ocultos
elif linea.find('=')!=-1:
binario=str(bin(caracteres_base64.find(linea[len(linea)-3]))[2:8].zfill(2))
bits_ocultos=binario[len(binario)-2:len(binario)]
flag+=bits_ocultos
linea=fichero.readline().rstrip('\n')
print ''
print '[+] Flag (binario) ...', flag
print '[+] Flag (ASCII) .....', binascii.unhexlify('%x' % int(flag,2))
fichero.close()
Reto 34: "El secreto compartido".
Comentarios
Publicar un comentario