Ir al contenido principal

Criptografía (CLVII): Solución Reto picoCTF 2018 "James Brahm Returns"

Solución a otro reto de la plataforma picoCTF 2018 sobre criptografía. Este desafío es, supuestamente, el más complicado de los catalogados en dicha categoría, y, en mi opinión, así es, por lo que le voy a asignar un nivel de dificultad muy alto ().

James Brahm Returns - Points: 700:

Su enunciado dice lo siguiente: '
Dr. Xernon has finally approved an update to James Brahm's spy terminal. (Someone finally told them that ECB isn't secure.) Fortunately, CBC mode is safe! Right? Connect with nc 2018shell.picoctf .com 14263Source'.
Solución: en el enunciado se deja claro que en este desafío también se ve involucrado el modo de operación CBC ('Cipher Block Chaining') de los algoritmos de cifrado por bloques y, efectivamente, en el código fuente que se proporciona (source.py) veo que se utiliza el algoritmo AES en dicho modo.

En este desafío, para identificar el ataque a realizar y, por tanto, poder resolverlo, es fundamental la pista que se da en la pestaña 'Hints' ('What killed SSL3?'). Busco en 'Google', literalmente, el texto de dicha pista y obtengo como primer resultado 'SSL 3 is dead, killed by the POODLE attack', por lo que ya tengo identificado el ataque, pero me toca investigar más sobre el mismo.

Tal y como nos cuenta wikipedia, el ataque POODLE (cuyo nombre no viene de caniche :), sino de'Padding Oracle On Downgraded Legacy Encryption') es un 'exploit' 'man-in-the-middle' que aprovecha Internet y la característica del software de clientes para forzar la bajada a SSL 3.0 con objeto explotar una vulnerabilidad en su diseño y poder así descifrar criptogramas. Además, existe también una variante de este ataque que explota las vulnerabilidades de implementación del modo de cifrado CBC en los protocolos TLS 1.0 al 1.2 sin necesidad de rebajar los clientes a SSL 3.0.

Antes de comenzar a intentar resolver el reto, me conecto al servicio; se me da la bienvenida como agente 006 y se me pide que: elija entre cifrar un mensaje, y enviar y verificarElijo la primera de ellas ('Encrypt message (E)'): se me pide que introduzca mi informe de situación, incluyo cualquier cosa, por ejemplo: 'My situation report', y se me muestra un mensaje cifrado:
Conforme al código fuente que se proporciona en el reto (source.py), el criptograma que se muestra se obtiene cifrando lo siguiente:
Es decir: el mensaje a cifrar se compone de un formato preestablecido, en el que se incluyen el informe de situación introducido y el código de agente, más lo introducido cuando se pregunta si se desea incluir alguna cosa más ('Anything else?'), más el resultado de calcular el hash sha1 de la concatenación de ambas cosas anteriores. Después se produce el relleno del mensaje y se cifra el resultado de todo ello mediante AES en modo CBC.

Ahora utilizo la segunda opción ('Send & Verify (S)'): se me pide que introduzca el mensaje cifrado (copio y pego el que se me ha mostrado cuando he utilizado la primera opción) y se me informa de que el descifrado se ha realizado con éxito.
Pruebo otra vez la segunda opción, pero ahora sólo incluyo una parte del mensaje cifrado anterior y se muestra un mensaje de error:
Acudo otra vez al código fuente que se proporciona en el reto (source.py) y veo que ese mensaje de error se muestra tanto si el relleno es inválido como si falla la verificación MAC ('Message Authentication Code'), es decir, si la validación del hash es incorrecta:
Por tanto, entiendo que en este caso un ataque 'padding oracle' como tal no funcionaría, ya que para que tenga éxito se necesita conocer con precisión cuando el relleno es incorrecto y cuando es válido, por lo que, tal y como se indica en la pista que se da, creo que hay que utilizar el ataque POODLE.

Como en el caso de SSL 3.0, el servicio al descifrar sólo mira el último Byte cuando comprueba el relleno, y elimina tantos Bytes como éste indique. Por ejemplo: si el último Byte es \x10 (16 en decimal) elimina 16 Bytes, es decir un bloque completo. 
¿Cómo puedo utilizar esto para implementar el ataque y obtener la solución del reto?. Explico brevemente lo que he entendido (por favor, como siempre, agradecería que si no lo he comprendido bien y/o no lo explico correctamente, se realicen las correcciones y/o ampliaciones de información oportunas en forma de comentarios a esta entrada).

1.- Obtengo un criptograma con un bloque completo de relleno. ¿Cómo hago esto?. Pues voy probando con un informe de situación con diferentes longitudes para el mismo hasta que con una determinada longitud obtenga un criptograma de un tamaño de 16 Bytes más que con la longitud anterior. Por ejemplo: probando con un informe de situación cumplimentado únicamente con caracteres "a"; en primer lugar introduzco "a", después "aa", posteriormente "aaa", y así sucesivamente hasta obtener con un cierto número concreto de caracteres "a" un criptograma de tamaño 16 Bytes mayor que el precedente.

En nuestro caso, tal y como se observa en la figura siguiente, veo que esto ocurre cuando introduzco 14 caracteres "a"; la longitud del criptograma que obtengo es de 208 Bytes frente a 192 Bytes en el caso de incluir 13 caracteres "a":

Como en el reto se proporciona la estructura del criptograma, e incluso parte del texto en claro, y, además, se puede incluir texto antes y después de la parte del mismo que me interesa descifrar, puedo obtener un criptograma que me permita ir directamente a descifrar dicha parte.

2.- En base a lo anterior, 14 caracteres "a" como informe de situación, y uilizando "\" para indicar el salto de línea, divido el texto en claro en bloques:

P1 = Agent,\Greetings
P2 = . My situation r
P3 = eport is as foll
P4 = ows:\aaaaaaaaaaa
P5 = aaa\My agent ide
P6 = ntifying code is
P7 = : xxxxxxxxxxxxxx
P8 = xxxxxxxxxxxxxxx.
P9 = \Down with the S
P10 = oviets,\006\????
P11 = ????????????????
P12 = ????????????????

Los caracteres "x" se corresponderían con la flag y, por tanto, la solución de este reto (el código de identificación del agente 006 que tengo que robar) y que, lógicamente, entiendo que tiene el formato estándar de la plataforma (picoCTF{...}), mientras que los últimos caracteres "?" se corresponderían con el hash sha1 (20 Bytes) más el relleno (16 Bytes, último bloque completo).

3.- Incluyo caracteres "a" antes de los caracteres "x" hasta conseguir que el primero de estos últimos se encuentre al final de un bloque de texto plano (como más adelante se verá el número de caracteres "a" que finalmente se hallen en esta posición debe ser mayor que el número de caracteres "x"), y para mantener el bloque de relleno completo introduzco tanto caracteres "a" como sean necesarios para ello después de los caracteres "x":

P1 = Agent,\Greetings
P2 = . My situation r
P3 = eport is as foll
P4 = ows:\aaaaaaaaaaa
P5 = aaaaaaaaaaaaaaaa
P6 = aaaaaaaaaaaaaaaa
P7 = \My agent identi
P8 = fying code is: x
P9 = xxxxxxxxxxxxxxxx
P10 = xxxxxxxxxxxx.\Do
P11 = wn with the Sovi
P12 = ets,\006\aaa????
P13 = ????????????????
P14 = ????????????????

4.- Obtengo el criptograma correspondiente a un reporte de situación (43 caracteres "a") y a la información adicional (3 caracteres "a" cuando el servicio pregunte: 'Anything else?'):
Es decir, en este caso:

C0 = 97ca0fcf7499260f6a9094db0046fb93; [Vector de inicialización] 
C1 = c608d1f7b3f44879f0860a227c5affc3P1 = Agent,\Greetings
C2 = f77515621dc87ef663e837e608406fd6P2 = . My situation r
C3 = df58770a01e2fc9058184d0f13ed80adP3 = eport is as foll
C4 = c34b0706165e4a25f1e2ab409b7d0ac3P4 = ows:\aaaaaaaaaaa
C5 = f9de61fab17ef653c4d2a3bbe0c3ad8dP5 = aaaaaaaaaaaaaaaa
C6 = 7b7a29d99fa75c0e7e4c7e08f5392c8cP6 = aaaaaaaaaaaaaaaa
C7 = 96ad4bfdb76749f8e3d5571081596861P7 = \My agent identi
C8 = 00fdf2e02996dbf2cb654fc6f24074ffP8 = fying code is: x
C9 = 1b5cc8abc9903352095e45722c5a2d38P9 = xxxxxxxxxxxxxxxx
C10 = 31e30758758e1dfadcb83fcdb3e41022P10 = xxxxxxxxxxxx.\Do
C11 = 29b1e68993c22693b94847e51d908ba9P11 = wn with the Sovi
C12 = d313c256bf00855040ebc6e2ddac6aafP12 = ets,\006\aaa????
C13 = 9b2ece32a716ece56454641ded3f9cb8P13 = ????????????????
C14 = 24e6eeb6301a237cccfc6f1c165e9caeP14 = ????????????????

5.- Y, finalmente, cambio el bloque final de relleno (C14por el bloque de texto cifrado por el que comenzar el ataque (C8):

C0 = 97ca0fcf7499260f6a9094db0046fb93; [Vector de inicialización] 
C1 = c608d1f7b3f44879f0860a227c5affc3P1 = Agent,\Greetings
C2 = f77515621dc87ef663e837e608406fd6P2 = . My situation r
C3 = df58770a01e2fc9058184d0f13ed80adP3 = eport is as foll
C4 = c34b0706165e4a25f1e2ab409b7d0ac3P4 = ows:\aaaaaaaaaaa
C5 = f9de61fab17ef653c4d2a3bbe0c3ad8dP5 = aaaaaaaaaaaaaaaa
C6 = 7b7a29d99fa75c0e7e4c7e08f5392c8cP6 = aaaaaaaaaaaaaaaa
C7 = 96ad4bfdb76749f8e3d5571081596861P7 = \My agent identi
C8 = 00fdf2e02996dbf2cb654fc6f24074ffP8 = fying code is: x
C9 = 1b5cc8abc9903352095e45722c5a2d38P9 = xxxxxxxxxxxxxxxx
C10 = 31e30758758e1dfadcb83fcdb3e41022P10 = xxxxxxxxxxxx.\Do
C11 = 29b1e68993c22693b94847e51d908ba9P11 = wn with the Sovi
C12 = d313c256bf00855040ebc6e2ddac6aafP12 = ets,\006\aaa????
C13 = 9b2ece32a716ece56454641ded3f9cb8P13 = ????????????????
C14 = 00fdf2e02996dbf2cb654fc6f24074ffP14 = fying code is: x

6.- Y ya estoy preparado para llevar a cabo el ataque. En primer lugar voy a intentar descifrar el primer carácter "x" de la flag, que como ya he dicho antes muy probablemente sea una "p" debido al formato estándar de flag que utiliza la plataforma.

Para ello, envío al servicio el criptograma anterior: si el descifrado no se realiza correctamente (se devuelve el mensaje ''Ooops! Did not decrypt successfully. Please send again.) vuelvo al punto 4 para obtener otro criptograma, mientras que si se realiza correctamente (se devuelve el mensaje 'Successful decryption'), la única manera de que esto se produzca es si P14[16] es \x10 (16 en decimal), ya que de esta forma se eliminará un bloque completo de relleno y se pasará también con éxito la validación del hash, puedo obtener el último Byte del texto plano (P8[16]), que es el que intento descifrar, de la siguiente manera:

Dk(C8[16])  = C13[16] XOR \x10
P8[16] = C7[16] XOR Dk(C8[16])

7.- Para conseguir el siguiente Byte de la flag basta con volver al punto 4 para obtener el criptograma correspondiente a un reporte de situación compuesto por 42 caracteres "a" (uno menos que para el Byte anterior) y a la información adicional formada por 4 caracteres "a" cuando el servicio pregunte: 'Anything else?' (uno más que para el Byte anterior), y así sucesivamente hasta conseguir descifrar todos los Bytes de la solución.

Creo un script en python para automatizar este proceso. Lo ejecuto y voy obteniendo el texto plano correspondiente a la flag. Cuando finaliza puedo ver la solución a este reto:

Comentarios

Entradas populares de este blog

Criptografía (I): cifrado Vigenère y criptoanálisis Kasiski

Hace unos días mi amigo Iñaki Regidor ( @Inaki_Regidor ), a quien dedico esta entrada :), compartió en las redes sociales un post titulado "Criptografía: el arte de esconder mensajes"  publicado en uno de los blogs de EiTB . En ese post se explican ciertos métodos clásicos para cifrar mensajes , entre ellos el cifrado de Vigenère , y , al final del mismo, se propone un reto consistente en descifrar un mensaje , lo que me ha animado a escribir este post sobre el método Kasiski  para atacar un cifrado polialfabético ( conociendo la clave descifrar el mensaje es muy fácil, pero lo que contaré en este post es la forma de hacerlo sin saberla ). El mensaje a descifrar es el siguiente: LNUDVMUYRMUDVLLPXAFZUEFAIOVWVMUOVMUEVMUEZCUDVSYWCIVCFGUCUNYCGALLGRCYTIJTRNNPJQOPJEMZITYLIAYYKRYEFDUDCAMAVRMZEAMBLEXPJCCQIEHPJTYXVNMLAEZTIMUOFRUFC Como ya he dicho el método de Vigenère es un sistema de sustitución polialfabético , lo que significa que, al contrario que en un sistema de

Criptografía (XXIII): cifrado de Hill (I)

En este post me propongo explicar de forma comprensible lo que he entendido sobre el cifrado de Hill , propuesto por el matemático Lester S. Hill , en 1929, y que se basa en emplear una matriz como clave  para cifrar un texto en claro y su inversa para descifrar el criptograma correspondiente . Hay tres cosas que me gustan de la criptografía clásica, además de que considero que ésta es muy didáctica a la hora de comprender los sistemas criptográficos modernos: la primera de ellas es que me "obliga" a repasar conceptos de matemáticas aprendidos hace mucho tiempo y, desgraciadamente, olvidados también hace demasiado tiempo, y, por consiguiente, que, como dice  Dani , amigo y coautor de este blog, me "obliga" a hacer "gimnasia mental"; la segunda es que, en la mayoría de las ocasiones, pueden cifrarse y descifrase los mensajes, e incluso realizarse el criptoanálisis de los criptogramas, sin más que un simple lápiz y papel, es decir, para mi es como un pasat

¿Qué significa el emblema de la profesión informática? (I)

Todas o muchas profesiones tienen un emblema que las representa simbólicamente y en el caso de la  informática: " es el establecido en la resolución de 11 de noviembre de 1977  para las titulaciones universitarias superiores de informática, y  está constituido por una figura representando en su parte central  un  núcleo toroidal de ferrita , atravesado por  hilos de lectura,  escritura e inhibición . El núcleo está rodeado por  dos ramas : una  de  laurel , como símbolo de recompensa, y la otra, de  olivo , como  símbolo de sabiduría. La  corona  será la  de la casa real  española,  y bajo el escudo se inscribirá el acrónimo de la organización. ". Veamos los diferentes elementos tomando como ejemplo el emblema del COIIE/EIIEO (Colegio Oficial de Ingenieros en Informática del País Vasco/ Euskadiko Informatikako Ingeniarien Elkargo Ofiziala ) . Pero no sólo el COIIE/EIIEO adopta el emblema establecido en dicha resolución, sino que éste se adopta también como im