Crypto 400: Breaking ECB Block Cipher

By Los Androides

Descripcion del reto:



En la descripción del reto se indicó que en el archivo adjunto API.json se describe la manera de interactuar con un Web Service, el contenido de este archivo es el siguiente:


{
"info": {
"_postman_id": "aea31d86-933e-46c1-83e0-f39b7ad39858",
"name": "HackDef2019 - Quals",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
},
"item": [
{
"name": "Hack",
"request": {
"method": "POST",
"header": [
{
"key": "Content-Type",
"name": "Content-Type",
"value": "application/json",
"type": "text"
}
],
"body": {
"mode": "raw",
"raw": "{\"equipo\":\"The Handsomes\"}"
},
"url": {
"raw": "http://189.240.x.x:1337/Hack",
"protocol": "http",
"host": [
"189.240.x.x"
],
"port": "1337",
"path": [
"Hack"
]
}
},
"response": []
},
{
"name": "Defender",
"request": {
"method": "POST",
"header": [
{
"key": "Content-Type",
"name": "Content-Type",
"value": "application/json",
"type": "text"
}
],
"body": {
"mode": "raw",
"raw": "{\"ticket\":\"fr5-F54-SECeUchXoqztCdno55KV3DA-roDTaijYwZczHR-Dz-ZSd3dNYSzYj5YO94DXHu5OBpJNQThoDQf2JQ==\"}"
},
"url": {
"raw": "http://189.240.x.x:1337/Defender",
"protocol": "http",
"host": [
"189.240.x.x"
],
"port": "1337",
"path": [
"Defender"
]
}
},
"response": []
}
]
}


Se puede observar que es posible hacer una petición con el método POST al recurso:

 hxxp://189.240.119.26:1337/Hack

Este regresa como respuesta un ticket cifrado en base64. Al enviar la siguiente petición:


POST /Hack HTTP/1.1
Host: 189.240.119.26:1337
Content-Type: application/json 
 
{"equipo": "The Handsomes"}


Se recibía el siguiente ticket:

fr5-F54-SECeUchXoqztCdno55KV3DA-roDTaijYwZczHR-Dz-ZSd3dNYSzYj5YO94DXHu5OBpJNQThoDQf2JQ==

Al enviar este ticket al recurso hxxp://189.240.119.26:1337/Defender de la
siguiente manera:


POST /Defender HTTP/1.1
Host: 189.240.119.26:1337
Content-Type: application/json

{"ticket": "fr5-F54-SECeUchXoqztCdno55KV3DA-roDTaijYwZczHR-Dz-ZSd3dNYSzYj5YO94DXHu5OBpJNQThoDQf2JQ=="}

Se recibía un mensaje que contenía el nombre "The Handsomes" , donde se indicaba que el ticket contiene la bandera. Al repetir este proceso con otro nombre de equipo, se recibía un ticket distinto, al enviar este ticket al recurso /Defender se mostraba ahora el nombre de este otro equipo. Con esta información se puede inferir que el ticket cifrado obtenido como respuesta en el recurso /Hack contiene no sólo la bandera buscada, también el nombre del equipo que es enviado en la
petición.

Al jugar con el recurso /Defender se observó que al enviar varias peticiones con nombres de equipos distintos pero de la misma longitud, se recibían tickets que al ser decodi cados de base64, diferían en los primeros 16 bytes, pero el resto era igual para todos, si se enviaba un nombre de equipo más largo de 16 bytes, también cambiaba el siguiente bloque de 16 bytes.

Por ejemplo, a continuación se muestran varios nombres de equipo seguidos de los tickets asociados a ellos en hexadecimal, separados en bloques de 16 bytes.


rondom: 
fda588a8df347ceabe61109bc95618d3
ebd5af0ee582e52c563511bf325080d8
6699eded9dbca397e14aa080559beb5f
f780d71eee4e06924d4138680d07f625

fandon: 
0883fa562efdb5a567b4446432a06e5c
ebd5af0ee582e52c563511bf325080d8
6699eded9dbca397e14aa080559beb5f
f780d71eee4e06924d4138680d07f625

landon: 
2dcf12c30a470c9595c61dd86cd727cf
ebd5af0ee582e52c563511bf325080d8
6699eded9dbca397e14aa080559beb5f
f780d71eee4e06924d4138680d07f625

thwopy: 
27bf30a2abbbfc92af1b0aa7979e79f8
ebd5af0ee582e52c563511bf325080d8
6699eded9dbca397e14aa080559beb5f
f780d71eee4e06924d4138680d07f652

Con esta información se pudo inferir que se estaba utilizando un algoritmo de cifrado con bloques de 128 bits de longitud, y más aun, se utilizaba el modo de operación ECB, donde el cifrado de cada bloque es independiente de los demás.
El texto cifrado se supuso constituía del nombre del equipo concatenado con la bandera, por esto es que se modi caba sólo el principio de los tickets con distintos nombres.

Puede aprovecharse la inseguridad del modo ECB para tratar de descifrar el ticket completo, sabemos que se tiene control sobre los primeros carácteres del ticket, al enviar un nombre de equipo de 16 bytes, sabemos que el primer bloque cifrado en el ticket contiene el nombre, mientras que queremos conocer los siguientes bloques, para esto se puede enviar un nombre de equipo de 15 bytes de longitud, por ejemplo AAAAAAAAAAAAAAA.
En el ticket resultante, el primer bloque estará constituido por la cadena AAAAAAAAAAAAAAA concatenada con la primer letra del texto que quiere ser descifrado (la bandera).

Se puede entonces enviar varias peticiones con el nombre AAAAAAAAAAAAAAAx (15
veces A mas otro caracter), donde se modi ca x iterativamente, cuando el primer bloque del resultado sea igual al primer bloque del ticket anterior, sabremos que se ha encontrado el primer caracter del texto a descrifrar.

Este proceso se puede repetir hasta obtener todo el texto en claro, para automatizar esta tarea se realizó el siguiente script :


def ticket(e):
r = req.post(
"http://189.240.119.26:1337/Hack",
json={"equipo":e}
)
return base64.b64decode(
r.text.split(' ')[-1].replace('-','+').replace('_','/'))
s = 'A' * 32
o = ''
for x in range(32):
s = s[:-1]
inicio = ticket(s)[:32]
for y in range(32,127):
fin = ticket(s + o + chr(y))[:32]
if inicio == fin:
o += chr(y)
print s+o
break

Al correrlo se pudo obtener la bandera:


Comments