Reto Hack-It de la Euskal Encounter 17
Dice el refrán popular que “más vale tarde que nunca” y en este caso particular más vale publicar la solución de este reto cinco meses después de la Euskal, que no hacerlo nunca :)
Este año, al igual que hice el año pasado, he realizado mi modesta aportación al Hack-It de la Euskal Encounter con una prueba para gozo y disfrute del personal que tuvo a bien participar en lo que, en mi opinión personal, es una de las mejores actividades que se realizan durante este evento y al que llevo acudiendo ya la friolera de 13 años si mi memoria no me falla. Agradecer a hey_neken el haber incorporado mi reto al Hack-It de este año.
Bien, basta de rollos, ¡pasemos a la acción! :)
El sufrido participante del Hack-It, una vez llega a mi prueba, se encuentra con que lo único que se le proporciona es una dirección IP, correspondiente al servidor del Hack-It en la LAN de la party, y un puerto TCP. Lógicamente, el primer paso es hacer uso de lo que nos dicen y conectar mediante un telnet a ver qué pasa. La conexión se establece sin problemas, apareciendo lo siguiente en el terminal desde el que realizamos el telnet:
# telnet 1.2.3.4 9999
Trying 1.2.3.4...
Connected to 1.2.3.4.
Escape character is '^]'.
CONNECTED
Enter received access code:
Nos pide que introduzcamos un código, pero no sabemos la longitud del mismo o incluso el juego de caracteres válido. De igual forma, en unos pocos segundos la conexión se corta, por lo que parece que hay un timeout definido, durante el cual es necesario que introduzcamos el código que nos pide. Ahora bien, ni en la página del reto se nos da pista alguna sobre este código, ni parece que haya información oculta de ningún tipo. Debe ser que hay que extraer algo más de información de esta conexión que establecemos, que parece que es lo único que tenemos en este momento para seguir investigando.
En retos de este tipo, siempre es buena idea tener un ojo en la red, ver qué se mueve por el cable (o las radiofrecuencias) más allá de lo que vemos, así que es buena idea repetir la conexión telnet pero con un sniffer capturando todo el diálogo, no sea que haya cosas que no vemos pero que nos pueden aportar información útil. Para ello, podemos usat tcpdump, snoop, wireshark o cualquier aplicación de captura de tráfico. Repetimos el telnet y veamos que se mueve por la red…
18:01:46.461990 IP 5.6.7.8.45385 > 1.2.3.4.55555: S 2307708527:2307708527(0) win 5840 <mss 1460,sackOK,timestamp 3301879450 0,nop,wscale 5>
18:01:46.650067 IP 1.2.3.4.55555 > 5.6.7.8.45385: S 2158051019:2158051019(0) ack 2307708528 win 5792 <mss 1460,sackOK,timestamp 1964456258 3301879450,nop,wscale 3>
18:01:46.650092 IP 5.6.7.8.45385 > 1.2.3.4.55555: . ack 1 win 183 <nop,nop,timestamp 3301879497 1964456258>
18:01:48.109403 IP 1.2.3.4.31337 > 5.6.7.8.31337: UDP, length 90
18:01:48.113211 IP 1.2.3.4.55555 > 5.6.7.8.45385: P 1:11(10) ack 1 win 724 <nop,nop,timestamp 1964456624 3301879497>
18:01:48.113228 IP 5.6.7.8.45385 > 1.2.3.4.55555: . ack 11 win 183 <nop,nop,timestamp 3301879862 1964456624>
18:01:48.306398 IP 1.2.3.4.55555 > 5.6.7.8.45385: P 11:39(28) ack 1 win 724 <nop,nop,timestamp 1964456673 3301879862>
18:01:48.306415 IP 5.6.7.8.45385 > 1.2.3.4.55555: . ack 39 win 183 <nop,nop,timestamp 3301879911 1964456673>
18:02:03.120239 IP 1.2.3.4.55555 > 5.6.7.8.45385: P 39:40(1) ack 1 win 724 <nop,nop,timestamp 1964460376 3301879911>
18:02:03.120293 IP 5.6.7.8.45385 > 1.2.3.4.55555: . ack 40 win 183 <nop,nop,timestamp 3301883614 1964460376>
18:02:03.124090 IP 1.2.3.4.55555 > 5.6.7.8.45385: FP 40:67(27) ack 1 win 724 <nop,nop,timestamp 1964460376 3301879911>
18:02:03.124220 IP 5.6.7.8.45385 > 1.2.3.4.55555: F 1:1(0) ack 68 win 183 <nop,nop,timestamp 3301883615 1964460376>
18:02:03.308138 IP 1.2.3.4.55555 > 5.6.7.8.45385: . ack 2 win 724 <nop,nop,timestamp 1964460423 3301883615>
Analicemos la captura, paso por paso:
- Los tres primeros paquetes intercambiados es el establecimiento de conexión TCP.
- Nada más establecerse la conexión con el servidor, éste nos envía un paquete UDP.
- Hay un intercambio de segmentos TCP, ya que el servidor también nos envía los datos correspondientes a lo que nos aparece en el terminal, la petición del código.
- Tras 15 segundos, durante los cuales nosotros no hacemos nada, el servidor finaliza la conexión.
¡Bingo!. ¿Qué es ese paquete UDP que nos envía el servidor cada vez que conectamos?. Si se hace un dump del contenido del paquete y se realizan varias conexiones para comparar varios paquetes UDP se advierte que:
- El juego de caracteres es limitado, aparece el espacio y los caracteres _ – |
- Siempre se devuelven 90 caracteres.
- Cada conexión devuelve una secuencia de caracteres distinta.
Por tanto, viendo esto, ¿estará el código codificado con esos caracteres?. Eso parece improbable, al igual que pensar que es algún tipo de cifrado, ya que la cadena que se devuelve en el paquete UDP desde el servidor únicamente hace uso de estos 4 caracteres (los tres tipos de barras y el espacio). Ahora bien, y si estos caracteres son una representación “gráfica” de algún tipo (ASCII art) del código. Eso podría ser… ;)
Si os digo “display de 7 segmentos”… ¿a que a muchos se os acaba de encender un LED de alta luminosidad sobre la cabeza? ;)
Pues efectivamente… lo que nos está llegando en el paquete UDP es la representación “7 segmentos” del código. Si intentamos “dibujar” un digito (suponemos inicialmente que el juego de caracteres del código es exclusivamente numérico) como lo hacen los displays de 7 segmentos en ASCII nos damos cuenta de que necesitamos 9 caracteres para “dibujar” el dígito. Por tanto, podemos suponer que nos están enviando una secuencia de 10 digitos.
Hagamos una prueba. Vamos a hacer el telnet, y en otro terminal, con un nc vamos a visualizar la secuencia de caracteres que nos llegan en el paquete UDP:
# nc -l -u -p 31337 > /tmp/datos.txt
# cat /tmp/datos.txt
_ _ _ _ _ _ _ _ |_ |_||_||_| | ||_| _|| ||_ |_||_| | | | ||_||_ |_||_|
Vamos a validar la teoría, reformateamos esta secuencia, insertando un CR/LF cada 30 caracteres y… ¡et voilà!
# cut -b1-30 </tmp/datos.txt; cut -b31-60 </tmp/datos.txt; cut -b61-90 </tmp/datos.txt
_ _ _ _ _ _ _ _ |_ |_||_||_| | ||_| _|| ||_ |_||_| | | | ||_||_ |_||_|
Ante nuestros ojos (para esto mejor tener una fuente de espaciado fijo) aparece la secuencia numérica, en este caso, 6894178206. Ahora bien, únicamente nos queda resolver un pequeño “problema”. La recepción del paquete UDP, decodificación de la secuencia y envío de la contestación debe, de alguna forma, automatizarse para poder realizar toda esta secuencia de pasos dentro del timeout que cierra la conexión, o bien ser muy rápidos cambiando de un terminal a otro y tecleando el código :)
Por cierto, recordad que cada vez que nos conectamos la secuencia numérica cambia, por lo que no vale eso de conectarse, capturar y decodificar, volver a conectarse y dar como respuesta el código enviado en la conexión anterior… el malvado diseñador del reto nos obliga a programar para automatizar la decodificación, jeje ;)
Hacemos el programa, se conecta, decodifica la secuencia, la devuelve y… ¡mierda! esto aún no ha terminado, obtenemos nueva información en nuestro terminal ;)
Access Granted!
Your code is correct, use it to select the right characters and get the passphrase ;)
0 1 2 3 4 5 6 7 8 9 0 M V U S H c C s L D 1 L T J r U X d P o p 2 m Y O o q t A N j d 3 A x h W e q A s k N 4 A O j J q F g V X i 5 O N K f D F c F S N 6 S U M B r g r t H f 7 J c e s l W B V t Y 8 L M n S r r Z V x u 9 k T Q w W L L P H L
NO CARRIER
La conexión se corta tras presentar esta matriz de caracteres. De nuevo, con cada conexión tanto el código numérico como la matriz de caracteres que se obtiene al devolver el código correctamente cambia. la passphrase del nivel está oculta dentro de esa matriz de caracteres, así que parece que hay que seleccionar la secuencia de caracteres correcta para obtener la passphrase alfanumérica del nivel, y así continuar con el siguiente reto.
¿Qué coordenadas elegir?, ¿qué fila y columna seleccionar y en qué orden?… Parece lógico pensar que el código numérico y la matrix están relacionados, además ambos cambian con cada conexión. La matriz de caracteres además viene indexada del 0 al 9 tanto para filas como para columnas… ¿y si el código numérico nos indica la fila y la columna de cada caracter de la passphrase que buscamos?
Siguiendo con el razonamiento anterior, y tras algunas pruebas fallidas hasta que damos con la lógica del maquiavélico diseñador del reto ;) damos con la solución. Cada digito del código indica la columna que se debe seleccionar en cada una de las filas, y esto nos permite extraer los caracteres de la matriz. En este ejemplo concreto, los caracteres correctos son los correspondientes a las posiciones:
Caracter 0 = Fila 0, Columna 6 => C
Caracter 1 = Fila 1, Columna 8 => o
Caracter 2 = Fila 2, Columna 9 => d
Caracter 3 = Fila 3, Columna 4 => e
Caracter 4 = Fila 4, Columna 1 => O
Caracter 5 = Fila 5, Columna 7 => F
Caracter 6 = Fila 6, Columna 8 => H
Caracter 7 = Fila 7, Columna 2 => e
Caracter 8 = Fila 8, Columna 0 => L
Caracter 9 = Fila 9, Columna 6 => L
La passphrase buscada en este caso concreto es… CodeOFHeLL
Espero que os haya gustado, y a los que la pasastéis en el Hack-It de la Euskal, espero que os divirtiese romper este reto :)
Comments
Leave a Reply