Hack-It GE15 : Nivel 2 “Pilas Duracell”

Vamos con el hack-it 2 de esta Gipu … que no saqué durante el concurso pero que hice luego más tranquilamente en casa y con ayuda de Ramandi (de w0pr) que anduvo resolviéndome muchas dudas 😉

No tengo captura del enunciado pero decía algo así como:

“HACK IT 2: Pilas Duracell”

“Otra de señales. A ver si nos ponemos las pilas!”.

Y teníamos un enlace para descargar un fichero:

Si miramos el tipo de fichero que es:

ASCII? vamos a abrirlo:

Y alguno igual ya dirá … .vcd, está claro qué es, tó esto sobra … bueno, pues yo hasta el sábado pasado no tenía ni idea ni de qué tipo de archivo era este, ni de dónde venía, ni pa qué sirve, ni cómo se ve, ni qué contiene, ni absolutamente ná de ná … lo más semejante que he visto nunca ha sido los video cds de hace años (amos, nada que ver).

Total, que buscando un poco por la wiki encontramos que VCD viene de las siglas “Value Change Dump” y lo que parece contener es información de señales a lo largo del tiempo. En este caso tenemos una única señal:

$var wire 1 ! pin[0] $end

El valor de esta señal está representado por lo que acompaña al ‘!’ y esta es el pin[0] … y como digo no hay más…

Por otro lado, el tiempo, estará representado por el valor que hay después de ‘#’. Y esto no me lo he inventado, viene en la wiki:

Por otro lado nos dice que la sección de $dumpvars contiene los valores iniciales de las variables:
Amos, que el pin[0] (!) empieza valiendo 0 fundamentalmente…

Para tener una idea global del aspecto de la señal podemos utilizar un aplicación (que encontré buscando en google pa variar) y que se llama Gtk Wave:

Al arrastrar la señal a “Signals” aparece el valor de la misma a lo largo del tiempo. Si hacemos un poco de zoom out podremos ver cómo pasa a valer 1 la señal a los 20 nanosegundos (como bien indica el fichero .vcd):

Si hacemos más zoom out podremos ver dónde hay efectivamente más datos útiles en esta señal:
Si hacemos zoom en alguna de estas zonas…:
Pues ya empiezan a verse más cosas útiles.

Todos y cada uno de los tramos que se ven en la captura de en medio tienen un aspecto semejante al de la captura inferior.

Vale, ¿y ahora que?

Pues como yo personalmente no sé si existe alguna aplicación que decodifique/capture directamente estas señales para pasarmelas a datos numéricos, opté por hacer el proceso desde cero a mano con un programilla hecho usando matlab/octave:

Esto hace la lectura del fichero línea a linea hasta la línea 12:

amos, elimina lo que no me interesa ya que yo lo que quiero son los tiempos.

A partir de aquí, si hacemos lo siguiente:

Sencillo, voy leyendo línea a línea y me voy quedando con el valor que hay después de la # (es decir con los tiempos). El valor que toma el pin[0] en esos tiempos no me resulta relevante porque sé que va a ir SIEMPRE alternando 1-0-1-0-1-0-… y también sé que parto del valor 0 porque mi primer valor de tiempo es 1080840604 nanosegundos y:

Y ahora viene el tema de cómo obtener la señal que hemos visto antes en el GTK wave pero para poder tener una tira de 1’s y 0’s y que pueda hacer algo con ellos. Para ello, en primer lugar, lo que tengo que hacer sencillamente es ir recogiendo todos los valores de tiempo que he leído del fichero y, de 2 en 2, ir restando el valor siguiente al valor actual; es decir:

Con esto lo que tengo es un array de diferencia de tiempos, es decir, en la posicion 1 de diffs tengo el tiempo que va a haber 0’s en el ‘cable’ en la posición 2 de diffs tengo el tiempo que va a haber 1’s, en la 3 el tiempo que va a haber 0’s de nuevo, etc…

Si represento esas diferencias en una gráfica tengo lo siguiente:

A ver… esto no dice mucho porque en en torno a diff(3500) la cantidad de 0’s o 1’s seguidos que hay es muy tocha… vamos a hacer zoom a la parte inferior de la gráfica que es donde tendremos algún dato interesante…

Aquí podemos ver cómo el mínimo valor de tiempo en el que cambia de valor la señal de pin[0] está en torno a 1500 ns…

Como vemos no es exacto… y es más, hay algún que otro valor más pequeño aún:

Pero a ver, creo que no hace mucha falta explicar por qué vamos a coger 1500 como unidad mínima y no 667 (que es el valor del pico de la imagen anterior)… la vida es imperfecta … 😛

Vamos con el meollo del asunto… mi idea ahora es representar con un 1 o un 0 un margen de tiempo de 1500ns en la señal; es decir, quiero hacer esto básicamente:

Para hacer esto se nos plantea algún problema…

Los “tiempos muertos”, o sea, donde no se está transmitiendo nada en el cable, aparecerán un mogollonazo de ceros … que sinceramente no sirven para nada y molestarán bastante así que vamos a intentar sortearlos.

Si nos fijamos un poco en la señal NUNCA hay más de 2 ‘bits’ iguales seguidos

NUNCA

Esto nos ayudará luego a deducir una cosilla, pero de momento vamos a utilizar esta propiedad de la señal para hacer lo que necesitamos:

La clave del programilla de arriba es dividir cada una de las diferencias que hemos calculado previamente entre 1500 y quedarnos con el número redondeado y escribir tantos 1’s o 0’s como ese número. Además, si la división sale mayor que 3, significará que estamos en zonas de 0’s, así que las obviamos de un plumazo directamente.

De esta forma tenemos lo siguiente:

No se aprecian mucho; haciendo un poco de zoom en alguna:

Tenemos lo que buscábamos … o al menos tiene mucha pinta así que de momento bien …

Y bueno con esta información, ahora podemos empezar … está guapo no hemos empezado realmente a intentar resolver nada, solamente estábamos transcribiendo los datos… xD

Y bueno, aquí viene lo tocho… para continuar había que interpretar bien la pista que hay en el título “Pilas Duracell”. Del título como digo, sacamos PD -> USB-PD (Power Delivery)

Yo, al ver ese tipo de señal, supuse que podría ser codificación Manchester que tiene esta pinta:

Pero tras pasarlo a manchester y perrear con los bits parriba y pabajo no llegué a ninguna conclusión…

Si buscamos documentación del protocolo USB-PD nos topamos … en primer lugar, con la codificación que lleva sobre la propia señal, que es la que nos interesa:

Ahora, si buscamos cómo va el BMC:

File:Biphase Mark Code.svg

Una de las ventajas de este tipo de señales (ya a nivel informativo, no es relevante para el hack-it 😉 es que el clock lo llevan integrado en la misma señal y por eso NUNCA hemos visto más de dos 1’s o dos 0’s seguidos en la señal que nos ha pasado marcan.

Bueno, vamos a decodificar la señal BMC para obtener los datos que queremos:

Lo que hace este programa básicamente es ir leyendo los bits que tengo en ‘signal’ de 2 en 2 y comparar su valor; si los valores son iguales => ‘0’ ; si son diferentes => ‘1’. Y de este modo obtenemos:

Bueno, pues ya tenemos todo decodificado … o no… porque … qué hacemos ahora con todo esto?

Pues seguir leyendo cómo va el protocolo USB-PD (aquí dejo la especificación de USB-PD por cierto):

Una trama USB-PD tiene esta pinta:

Bueno, pues esta parte la tenemos facil … 10101010…. hasta 64 bits cuadra:

A ver qué tenemos lo siguiente:

Y aquí se viene un poco el lío porque los bits se van a leer al revés y de 5 en 5. ¿que por qué? pues porque lo pone en las especificaciones del protocolo xD; en primer lugar el bit ordering:

El que se transmite primero es el bit de menos peso en su bloque correspondiente con lo que si seguimos por ejemplo con esta trama:

ese 00011 se tendría que leer -> 11000 y así con todos los bloques.

He cogido 5 bits por la codificación:

Tras el preámbulo va el SOP, como hemos visto en alguna captura anterior, y este SOP consta de 4 bloques de 5 bytes en total.

Sabiendo todo esto, vamos a eliminar los preambulos y los SOP y vamos a transformar los headers y los datos de todas las tramas. Lo hacemos con este código:

Primero voy a poner en variables en líneas separadas cada una de las tramas:

Así puedo trabajar con cada línea de forma individual más cómodamente.

Y ahora se viene el programa gordo y que explicaré un poco por encima porque línea a línea es una locura …

Lo que hace este programa es básicamente coger de 5 en 5 bits todas las tramas que contiene ‘bmc_lines’ y las pasa a hexadecimal (decodificándolo según la tabla 4b5b, que como veis, he invertido los bits directamente en la tabla de conversión, en lugar de hacer la lectura en orden y usar la tabla de conversión sin invertir).

Si visualizamos los datos aqui obtenidos veremos lo siguiente:

Con todo este chorizo de datos ya decodificados, no habría ya más que hacer pruebas a ver si se ve algún texto por ahí.

Si juntamos las cifras de 2 en 2 (ya que 1 byte en hexadecimal son 2 digitos de los que se ven en la captura), luego lo podríamos pasar a ascii:

No se ve nada … pero hay que tener en cuenta que los datos nos vienen invertidos con lo que hay que dar la vuelta cada una de las parejas de dígitos:

Y por fin, … ahí esta:

F33lth3P0w3r

Hack-It GE15 : Nivel 1 “Zero Failures Found”

Vamos con el level 1 del Hack-it … el facilito …

Este hackit no nos costó mucho sacar … y nos salió probando cosas a puto bulto al principio prácticamente xD

Lo primero que probamos fue … google translator:

Estaba claro … nada concluyente.

Luego buscando en google los caracteres individuales no llegamos a ninguna conclusión tampoco.

Optamos por otra opción sencilla: echar un ojo al valor unicode de los caracteres a ver qué nos encontrábamos:

Y ahora cogiendo esos datos, en 1 minuto en matlab escribimos:

杕杮朱杣朰杤朳本杮朰杰杒朰杢杬朳杭

caract=[ ‘6755’; ‘676E’; ‘6731’; ‘6763’; ‘6730’; ‘6764’; ‘6733’; ‘672C’; ‘676E’; ‘6730’; ‘6770’; ‘6752’; ‘6730’; ‘6762’; ‘676C’; ‘6733’; ‘676D’; ‘6721’ ];
caractDEC = hex2dec(caract);
char(caractDEC – 26368)’ %26368 = 0x6700

ans =

Un1c0d3,n0pR0bl3m!

(Y mañana el hack-it 2 que ese es BASTANTE más largo de explicar … xD)

Solve-It GE15 : Nivel 3 “De paseo con Gandalf”

Y vamos con el que se nos torció (cómo no…., alguno tenía que haber)… XD

Aquí imobilis nos da una lista escrita a mano de localizaciones por las que ha pasado Gandalf y una serie de letras y números delante de cada una de ellas.

Alguno de nosotros ya conocía esta clase de nomenclatura, pero bueno, tampoco cuesta mucho llegar a ella si se busca cualquiera de las localizaciones en google:

Al final los 4 + 2 caracteres nos indican puntos concretos en el mapa. Google nos muestra la información de lo que significan:

Una de las claves para resolver el nivel era la ultima frase del primer párrafo: “[…]Afirma que es la localización más cercana a cada uno de los lugares […]”. Aunque esta pista también nos despistó, ya que por lugar, no asumimos que eran museos, sino cualquier lugar de interés general.

En cualquier caso, probamos varias combinaciones: lugares de interés general, paradas de bus, museos, sitios emblemáticos de la ciudad (aunque no tuviera que ver con el spot exacto), …

Al final, los lugares los teníamos bastante claros pero tuvimos un problema y es que… la “Nota 2” no se nos dió hasta casi al final… y dado que dimos por hecho que el case sensitive estaba desactivado (es decir, que daba lo mismo que pusieras, por ejemplo, “China” que “chInA”) ya que cuando probamos por primera vez los museos no funcionó… pues se vino el desmadre (pa variar) xDDD

En cualquier caso, las localizaciones más cercanas, asumiendo que Gandalf solo visitó museos, son:

(Este en concreto tuvimos dudas, demasiados museos en los alrededores … xD)

Haciendo copy-paste como dice imo en la nota 2, la solución sale:

Museum of Pop Culture, Musée du Louvre, 国立西洋美術館, Museo Nacional de Ciencias Naturales, San Telmo Museoa, National Gallery of Ireland, Museo de Málaga

Solve-It GE15 : Nivel 2 “Noche de verano”

Y aquí tenemos el segundo solve-it. En este caso uno de estos de marcan de pista de audio … a ver con qué nos sorprende esta vez…

Este nos costó un poco sacarlo porque le dimas más vueltas de las que había que darle… aunque comenzamos bien.

Fundamentalmente primero escuchando el audio, que tenía esta pinta:

Luego directamente pasamos a visualizar el espectro, que muchas veces suele dar una pista de por dónde pueden ir los tiros:

Al ver esto pensamos lo típico: igual era morse … o quizá braille pero para ninguna de ellas cuadraba porque morse? Qué es punto? qué es raya? -> Tenía mala pinta

Braille? podría haber sido, siendo una separación los círculos más pequeños de en medio … pero tampoco tenía mucho sentido porque braille son 3×2 puntos por caracter y tenemos 37 columnas… y qué haces con la pareja de filas de puntos de la parte inferior?? meh!

Y aquí se vino la rayada con su consecuente pérdida de tiempo …………. por qué…. por qué el fichero era .mp3 ???

Porque es que, pocas veces (por no decir ninguna) hemos visto un solve-it de marcan o imobilis con ficheros de audio que no fueran .ogg …

Total, que tras unas cuantas horas de sueño perdidas buscando fantasmas e investigando sobre audio .mp3… tiramos la toalla…

Tras dormir unas cuantas horas a alguien se le ocurrió buscar en google:

punched code

Y aquí vimos la luz…

Y siguiendo un poco la pista de esta codificación, vemos que se trata de código baudot.

DIY Calculator :: Paper Tapes and Punched Cards

Como vemos … cuadra a la perfección con esta última captura (aunque haya que espejar la imagen en el eje horizontal)

La pequeña peculiaridad que tenía es que sacaba caracteres especiales con lo que al decodificarlo obteníamos:

B FIGS R LTRS U D FIGS P LTRS T SP B FIGS E E LTRS P FIGS T LTRS SP Y FIGS P LTRS U R SP B L FIGS P P LTRS P FIGS T

Llegados a este punto simplemente había que buscar qué significaban esos caracteres especiales:

Asi que como podemos ver ‘FIGS’ es para cambiar de letras a números, ‘LTRS’ es para volver a letras y ‘SP’ es sencillamente un espacio en cualquier caso. Nos quedaría:

B4UD0T B33P5 Y0UR BL00P5

Solve-It GE15 : Nivel 1 “Larga distancia”

Bueno, pues vamos con los Hack-Its y Solve-Its de esta 15ª edición de la Gipuzkoa Encounter, que lamentablemente aún sigue siendo online … :/

El primer solve-it era relativamente sencillo. Se nos presentaba un vídeo partido en 2 trozos y en cada uno de ellos había una captura de alguna zona google maps.

No tengo más capturas (ni el vídeo en sí) de todas las ciudades que salían, pero sí que hicimos una lista de las parejas de ciudades que iban saliendo.

Bueno, lo primero que salta a la vista es que absolutamente todas las ciudades son de EEUU.

La primera idea que nos pasó por la cabeza fue que habría que trazar los puntos de union entre las ciudades y saldrían algunas letras o semejante, pero no tenía pinta:

Igual no se aprecia mucho pero las trayectorias se solapaban y no quedaba nada definido de forma clara.

Tras varias vueltas jugando con los datos de las distancias y demás nos fijamos que en alguna de las capturas aparecían las carreteras interestatales de forma deliverada.

Por ejemplo, (no tengo la captura en concreto) pero había alguna ciudad que aparecía muy al borde de la imagen y salía más centrado el número de la interestatal en sí.

Pensamos que podría haber algo por ahí aunque el hecho de que hubiera rutas en la que se solapaban algunas interestatales o había rutas alternativas asi que no nos dio mucha esperanza …

Esta por ejemplo.

Aun así, probamos a intentar formar algo con las 4 primeras interestatales, asociando la letra en ascii:

Así que nada, esto fue lo único que nos hizo falta para deducir que ahí había algo con el tema de las Interestatales.

¿Qué hicimos con las que se solapaban y teníamos en duda? Pues un poco a ojo … ajustar a lo que nos interesaba a nosotros que tuviera sentido:

Hack-It EE28 : Nivel 1 “Takeoff!”

hackit_01

Vamos con el hackit sencillo de esta euskal. (Aunque igual algo extenso de explicar pero bueno… xD)

A éste le dediqué algo de tiempo para desintoxicarme del solveit 3, que nos tenía bastante cansados ya … pero no lo llegué a terminar por un fallo tonto que tuve… tonto pero suficiente para que me mandase el resultado a pique xD.

El enunciado, deja bastante claro, para el que conozca el evento de hackit, que algo habrá en el código fuente de la web que habrá que reversear.

Editando el código fuente nos encontramos con una línea que modifica el css del box de la contaseña y que tiene esta pinta:

(document).ready(function(){$(“#password”).keyup(function(o){for(var r = $(“#password”).val(), s = [],n = r.length,a = [35, 420, 53, 108, 275, 139, 690, 2417, 74, 888, 1002],f = a.length, t = 0; t < n; t++)s.push(r.charCodeAt(t));for (t = 0; t < 4242; t++) s[t % n] = 255 & ( a[t % f] % 10 == 0 ? s[t % n] + a[t % f] / 10 | 0 : a[t % f] % 10 == 1 ? s[t % n] – a[t % f] / 10 | 0 : a[t % f] % 10 == 2 ? s[t % n] ^ a[t % f] / 10 | 0 : a[t % f] % 10 == 3 ? s[t % n] + s[(t + a[t % f] / 10 | 0) % n] : a[t % f] % 10 == 4 ? s[t % n] ^ s[(t + a[t % f] / 10 | 0) % n] : a[t % f] % 10 == 5 ? -s[t % n] : a[t % f] % 10 == 6 ? s[t % n] + (s[(t + 3) % n] ^ a[t % f] / 10) : a[t % f] % 10 == 7 ? s[t % n] – (s[(t – 4) % n] | a[t % f] / 10) : a[t % f] % 10 == 8 ? s[t % n] ^ s[(t + 5) % n] & a[t % f] / 10 : s[t % n] ^ s[(t + 6) % n] * a[t % f] / 10); $(“#password”).css({ “background-color”: JSON.stringify(s) == JSON.stringify([32, 231, 18, 96, 116, 170, 21, 121, 83, 39, 25, 13, 64, 42, 127, 240, 39, 25, 173, 119, 201, 175, 205, 247]) ? “#8f8” : “#f88”})})});

Parecen un mogollón de operaciones con arrays, vamos a pasarle un beautifier para que quede algo más legible … como siempre también …

hackit_01_02

A ver, siendo sinceros, no es que deje muy limpio el formato que nos tiene puesto marcan pero bueno, vamos a dividir a mano lo que parece una cadena de ‘if’ infinitos …

hackit_01_03

Bueno, podría ser peor …

Si empezamos a analizar el código, como vemos, lo que hace es:

hackit_01_04

Linea 2: Cada vez que se hace “keyup” en el campo de password ejecuta la funcion ‘o’, que como vemos consiste en:

Linea 3: coger el valor de la password, es decir, la password que nos interesa, la del nivel, y asociarla a una variable ‘r’;

Linea 4: crea además un array ‘s’ vacío.

Linea 5: crea otra variable llamada ‘n’ en el cual metemos el valor de la longitud del array ‘r’, es decir, la longitud de la password del nivel (‘r’ lo hemos igualado antes a la password, recordemos)

Linea 6: crea un array llamado ‘a’ con los valores que se ven en la captura: 35, 420, 53, 108, 275, etc…

Linea 7: crea una variable llamada ‘f’ donde metemos el valor de la longitud del array ‘a’; que en este caso será 11, así que f = 11. Por otro lado, en esta misma línea inicia una variable t=0, que es la que va a usar para el bucle ‘for’, puesto que luego vemos que la condicion para seguir ejecutando el bucle for es que t < n y que cada iteración sume 1 a t (es lo que significa el t++).

Linea 8: Este es el contenido del bucle for en sí. Lo que vemos que hace cada iteración es añadir al array ‘s’ (el método push() en JavaScript añade un elemento al final del array) el valor en ascii (un valor de 0 a 255) del carácter en la posición t del array r, que es la contraseña. Es decir, lo que hace es calcular todos los valores en ascii de la password del nivel y meterlos en el array s como valores numéricos.

La conclusión de esto es que en este punto, nada más acabar el bucle ‘for’ tenemos en el array s nuestra contraseña codificada en ascii.

Lo que no sabemos es cuántos valores son (es decir, no sabemos el tamaño del array ‘s’) ni por supuesto qué valores son.

Si seguimos mirando el código nos encontramos con otro bucle for … este un poco más ‘potente’ ya … :

hackit_01_05

Linea 10: En el que vemos que hace 4242 iteraciones…

… con varios if concatenados.

Si nos fijamos bien, dentro de este for en realidad, solamente hay UNA operación que es la de la linea  11:

s[t % n] = 255 & ( los_if_que_siguen_que_son_un_churro_de_la_muerte );

Empecemos por el principio… tal y como vemos esto, lo que tenemos aquí es que el caracter que está en la posición ‘t % n’ de nuestro array, que contiene la password ‘s’, lo igualamos a ‘255 & ( algo )’; esto significa que hacemos un and lógico/bit a bit (&) de los valores de ‘algo’ con 255.

¿Y por qué?

Como sabréis 255 en binario es igual a ‘1111 1111’ así que marcan hace esto porque no quiere que, tras hacer las operaciones que hay dentro del paréntesis (es decir, las operaciones tochas que he definido antes como ‘algo’), NINGÚN valor de los que resulten sobrepase 255 en decimal; a esto se le suele llamar hacer una máscara de bits. Por ejemplo, supongamos que la operación ‘algo’ que tiene que hacer es la que hay en la de la linea 22 del programa (‘-s[t % n]’). Esta operación en concreto, lo que hace es calcular el valor en negativo de lo que hubiera en la posición del array s[t % n]; hasta ahí sencillo … Ahora bien, hacer el valor negativo de un número en informática recordemos que consiste en hacer el complemento a 2 (en binario) de ese número. Eso supone que si por ejemplo tenemos un valor en decimal de 120, en binario este valor se representaría como ‘0111 1000’, su valor negativo ‘-s[t % n]’ sería en decimal = -120, pero este valor negativo representado en binario sería ‘1111 1111 1111 1111 1111 1111 1000 1000’ (este valor es su complemento a 2 operando en 64 bits, que es como *creo* que javascript funciona por defecto). Si ahora este valor binario lo representase como entero sin signo (podéis probar usando la calculadora de windows mismamente) su valor sería de: 4294967176. Es por eso por lo que si a este valor tan tocho le hacemos una máscara ‘& 255’ nos estaremos quedando con los últimos 8 bits (bits de la derecha/menos peso) que serían ‘1000 1000’ es decir, el equivalente a 136 en formato decimal.

Y no hemos acabado, por supuesto …

¿Qué es ‘t % n’? (o mejor dicho, el operando ‘%’)

Tanto en C, como en C++ como en JavaScript como en otros muchos lenguajes, el operando % representa el módulo de una división. ¿Y qué es el módulo de una división? pues tan sencillo como el resto de esa división. Por ejemplo, ahora veremos que la primera iteración que vamos a hacer en ese for va a ser para t=4241 y veremos tambíen que el valor de n=24 (y que 24 es la longitud de la password). Hacer t % n consiste en hacer la división t/n y quedarnos, no con el resultado, sino con el resto de la división, es decir:

4241 / 24 = 176.70833333.. => 176.708333 – 176 = 0.708333 => 0.708333 * 24 = 17

Con lo que la operación: 4241 % 24 = 17

Hay otra serie de operaciones dentro de esos if en las que entraremos luego.

Y por cierto no lo he dicho, pero en C++, C#, JavaScript las líneas:

a > b ? a = 0 : b = 1;

Son exactamente lo mismo que:

if (a>b)
   a = 0;
else
   b = 1;

marcan se aprovecha de esto para poner un chorreo guapo en una sola línea concatenando ifs a lo salvaje…

Antes de entrar con esos if (que son lo más complejo del hackit) vamos a continuar fuera del mismo, con lo que viene tras el bucle for:

hackit_01_06

Aquí vemos lo que comentaba al principio del color del box de la contraseña en .css.

Cambia el color del css en base a si la password (el array ‘s’) resultante tras el bucle ‘for’  es igual a [32, 231, 18, 96, …., 247]. En concreto pone verde (#8f8) el fondo si es igual y lo pone rojo (#f88) si es diferente:

hackit_01_07

Llegados a este punto sabemos que justo antes de hacer esa comprobación, el valor de s ha de ser exactamente el siguiente:

s = [32, 231, 18, 96, 116, 170, 21, 121, 83, 39, 25, 13, 64, 42, 127, 240, 39, 25, 173, 119, 201, 175, 205, 247];

(Los JSON.stringify que se ven en el código, en este caso son triviales: se aplican en ambos lados de la igualdad así que podemos ‘pasar’ de ellos).

Llegados a este punto ya sabemos que lo que tenemos que hacer es “ejecutar el código al revés”, es decir, partiendo de que ‘s’ sea igual a: s = [32, 231, 18, 96, 116, 170, 21, 121, 83, 39, 25, 13, 64, 42, 127, 240, 39, 25, 173, 119, 201, 175, 205, 247]; Tenemos que conseguir saber qué valores tiene ‘s’ justo antes de que el bucle for tocho nos lo modifique; es decir, que podemos empezar programando lo siguiente:

hackit_01_08

Nos quitamos de en medio ese bucle for inicial que genera ‘s’ a partir de la password del nivel, y creamos el array ‘s’ con los valores que tiene que tener al final del bucle for tocho. Además sabremos que la password ha tener la longitud de esa misma ‘s’ generada ya que el bucle for tocho, no le añade elementos al array (no existe ningún .push() dentro del for tocho).

Vale, ahora lo que hay que pensar es cómo se ha de deshacer todo el cristo del bucle for.

Para empezar, el bucle ‘for’ original se recorre desde t=0 hasta t=4241 así que esta parte es fácil, consiste en darle la vuelta al bucle => tendrá que ir desde t=4241 hasta t=0:

hackit_01_09

Hasta aquí la parte fácil. Vamos ahora dentro del bucle ‘for’:

hackit_01_05

Linea 11: Esta ya la hemos visto antes. Hemos dicho que hace una máscara de 255 (1111 1111) con lo que hay detrás, que es el resto de ifs. Vamos con el ‘resto de ifs’.

Linea 12: Supongamos que se cumple la condición que indica de que ‘a[t % f] % 10 == 0’. Por ejemplo, para t=12; f = 11 (siempre, porque f = longitud de a, que no varía y vale 11). Así que a[12 % 11] = a[1] = 420, y ahora 420 % 10 = 0 así que al cumplirse tenemos que se ejecuta la linea 13.

Linea 13: lo que tenemos aquí es ‘s[t % n] + a[t % f] / 10 | 0’. Es decir, que la ejecución de la iteración para t=12 sería: s[t % n] = 255 & ( s[t%n] + a[t % f] /10 | 0 );

Si vamos sustituyendo tenemos: s[12%24] = 255  & ( s[12%24] + a[12%11] / 10 | 0 );

Es decir: s[12] = 255 & ( s[12] + a[1] / 10 | 0);

Y sustituyendo por valores numericos: s[12]new = 255 & ( s[12]old + 420 / 10 | 0 );

He puesto s[12]new y s[12]old porque realmente, los valores de ‘s’ van a ir oscilando según la iteración en la que estemos y no sé exactamente el valor numérico que tendrá cuando estemos en esta iteración que he puesto a bulto: iteración t=12 … Lo que sí sé es que lo que hay dentro del igual es un valor que es el anterior (old) al que va a haber (new), porque se sobreescribe; por eso les he puesto la etiqueta de ‘old’ y ‘new’.

Por otro lado entran en juego aquí

Ahora hay que tener en cuenta que lo que me interesa saber no es el valor ‘new’ (ya que este valor ‘new’ sería el que vale para cuando ejecutamos el programa como está originalmente) sino que lo que necesitamos es el valor ‘old’ porque recordemos, que estamos reverseando el bucle ‘for’! Con lo que hay que despejar de esa ecuación el valor que nos interesa, es decir: s[12]old

Puede que se nos plantee un problema ahora y es el operando ‘|’ que vemos.

Este operando es un ‘or lógico’ (or a nivel de bit). Y claro, aquí tenemos el planteamiento de… qué tiene prioridad? Sabemos de sobra que las divisiones/multiplicaciones tienen prioridad sobre sumas/restas, pero ¿y las operaciones booleanas a nivel de bit ??

Para saber qué tiene preferencia a la hora de operar .. pues recurrí a google, como era de esperar … y según esta tabla:

hackit_01_10

lo más prioritario serían las multiplicaciones y divisiones, luego vendrían las sumas y finalmente las operaciones a nivel de bit. Con lo que para despejar s[12]old de esta ecuación:

s[12]new = (  ( s[12]old – (420 / 10) ) | 0  );

‘| 0’ es exactamente igual que hacer nada … así que directamente lo vamos a quitar porque no hace más que molestar:

s[12]new = (  ( s[12]old – (420 / 10) )  );

s[12]new + 420 / 10 = s[12]old;

s[12]old = s[12]new + 420 / 10;

O lo que es lo mismo en plan genérico para esta linea 13:

s[t % n] – a[t % f] / 10

(le hemos cambiado el signo únicamente. Si hacemos con las siguientes líneas que hacen alguna operación la misma jugada …:

Linea 15 : s[t % n] – a[t % f] / 10 | 0 :  —>   s[t % n] + a[t % f] / 10 :

En la linea 17 no es una resta lo que tenemos, sino una operación tipo ‘^’. Esto es un XOR a nivel de bit. La inversa de una operación XOR es exactamente la misma operación XOR, con lo que:

Linea 17 : s[t % n] ^ a[t % f] / 10 | 0 : —>   s[t % n] ^ a[t % f] / 10 :

La línea 19 puede ser un poco confusa porque hay operaciones de sumas DENTRO del índice s, sobre el que estamos trabajando. Aquí NO hay que hacer ninguna modificación. El índice al que se refiera dentro de s tiene que ser el mismo según la variable t, n y f. Con lo que:

Linea 19 : s[t % n] + s[(t + a[t % f] / 10 | 0) % n] :  —>  s[t % n] – s[(t + a[t % f] / 10 | 0) % n] :

Linea 21: s[t % n] ^ s[(t + a[t % f] / 10 | 0) % n] :  —> s[t % n] ^ s[(t + a[t % f] / 10 | 0) % n] :

Y ahora vino mi cagada… que tarde o temprano habría descubierto … si no hubiera dedicado media party al Solve-It 3 ….. :/

Linea 22 : a[t % f] % 10 == 5 ? -s[t % n] :

-s[t % n] tiene que permanecer tal cual; NO ha de cambiarse porque si se cambia tenemos que:

s[t % n] = s[t % n];

Es decir, no vamos a hacer absolutamente ninguna operacion sobre el valor, y lo que hay que hacer es, como he explicado antes, el complemento a 2 del valor s[t % n] y luego se sustituye por sí mismo…

Típico de examen de matemáticas: “me han suspendido por un signo!” … xD

En cuanto al resto, seguimos con la misma tónica:

s[t % n] + (s[(t + 3) % n] ^ a[t % f] / 10) : –> s[t % n] – (s[(t + 3) % n] ^ a[t % f] / 10) : 

s[t % n] – (s[(t – 4) % n] | a[t % f] / 10) : –> s[t % n] + (s[(t – 4) % n] | a[t % f] / 10) :

s[t % n] ^ s[(t + 5) % n] & a[t % f] / 10 : –> s[t % n] ^ s[(t + 5) % n] & a[t % f] / 10 :

s[t % n] ^ s[(t + 6) % n] * a[t % f] / 10); –> s[t % n] ^ s[(t + 6) % n] * a[t % f] / 10);

De esta forma el programa que nos queda modificado (reverseado) es:

hackit_01_11

Si mostramos el valor del array ‘s’ con un console.log(s), tenemos que es el siguiente:

hackit_01_12

Y si esto lo pasamos a un string de la siguiente forma:

hackit_01_13

Tenemos finalmente la solución del level:

hackit_01_14

Mung1nG4rRay54fUn&Pr0f1t

 

Solve-It EE28 : Nivel 5 “Minutos musicales”

Y finalmente:

SolveIt_05

Este es el que, para mí, fue de los más sencillos del solve it (e igual por eso también fue el que más me gustó xD).

Se trata de un archivo de audio en el que suena Nyancat y cuya forma de onda tiene esta pinta:

Captura de pantalla 2020-07-28 a las 13.14.17

Nada más darle al play no suena nada excesivamente extraño pero sin embargo, como se puede ver en la captura anterior, en la forma de onda se pueden apreciar cosas raras …

Por un lado parece que tenemos a partir del centro de la pista de sonido, una ondas senoidales casi perfectas con mucho ruido alrededor. Sin ir mas lejos, la parte final de la pista de audio tiene una onda senoidal casi impoluta:

Captura de pantalla 2020-07-28 a las 13.18.56

Viendo esto, lo que parece es que han sumado una señal senoidal de muy baja frecuencia y bastante potente a la pista de audio.

De hecho, si vamos al inicio de la pista de sonido, vemos algo parecido pero bastante más claramente; hay una onda senoidal prácticamente perfecta:

Captura de pantalla 2020-07-28 a las 13.21.52

Se puede pensar que igual se nos quiere ocultar algo en la pista original de audio enmascarándolo con estas ondas de baja frecuencia (puede que morse subiendo y bajando el volumen de la pista original o asi…?)

Vamos a intentar quitar las bajas frecuencias de en medio. Para ello, vamos a buscar la frecuencia aproximada de las mismas:

Captura de pantalla 2020-07-28 a las 13.24.48

Un ciclo de esa onda dura 0.05 segundos => la frecuencia es la inversa: 1 / 0.05 = 20 Hz

Pasemos un filtro paso alto, es decir, eliminamos así todas las ondas por debajo de las frecuencias de 30 Hz (damos un poquito de margen, por eso 30Hz y no 20)

Captura de pantalla 2020-07-28 a las 13.27.55

Bueno, esto tiene más pinta de pista de audio “normal” aunque el problema que se ve es que… principalmente no hay nada que llame en especial la atención. No parece que haya datos  adicionales… la anchura (volumen) es más o menos constante … al escucharla suena normal …

Vamos a deshacer el filtro y ahora vamos a hacer lo contrario pasando un filtro paso bajo en lugar de paso alto a ver qué vemos en las bajas frecuencias… (el filtro tambien de 30Hz)

Captura de pantalla 2020-07-28 a las 13.30.48.png

Bueno, aquí sí que canta mucho más que hay algo de información … Parece que la anchura de las ondas divide perfectamente en varios tramos a la pista, en concreto en 18 tramos. => 18 letras?

Visto esto, lo único que parece que puede diferenciar a cada una de los tramos es su frecuencia de la onda de dicho tramo, así que vamos a ver qué frecuencia tiene cada tramo:

Captura de pantalla 2020-07-28 a las 14.43.47

Para medir la frecuencia hacemos parecido a como hemos hecho antes: tomamos desde un punto de la onda hasta el siguiente mismo punto y miramos el tiempo que hay entre ambos:

El primer tramo es el que he puesto al principio, que era de 0.05 s => 20 Hz

Captura de pantalla 2020-07-28 a las 14.47.25

Siguiente es de 0.055s => 18.2 Hz que vamos a redondear por defecto a 18 Hz

Siguiente es de 0.067s => 14,9 Hz redondeado a 15 Hz

Y así vamos haciendo todos los tramos (pongo captura de alguno más de ellos:

20 Hz

18 Hz
15 Hz
12 Hz
15 Hz
12 Hz
15 Hz
19 Hz
21 Hz
2 Hz
6 Hz
18 Hz
5 Hz
17 Hz
6 Hz
12 Hz
1 Hz
7 Hz

Si asociamos a cada uno de estos valores, una letra del abecedario (o sea, como en el solveit 3, pero sin hacer cabriolas raras) obtenemos la solución directamente:

Captura de pantalla 2020-07-28 a las 15.03.16

 

trololosubfreqflag

 

 

 

 

 

Solve-It EE28 : Nivel 4 “Grand piano”

Vamos llegando a los últimos solveit del año; este tiene poquito desarrollo:

SolveIt_04

VIDEO

Bueno, este nivel, más que difícil fue un poco tedioso.

En el vídeo que nos muestra marcan para este solve it se ve un piano tocando una pieza pero no suena nada. La solución salta a la vista que tendría que venir por intentar ver qué pieza es la que está tocando …

El problema de este solveit como digo, es que reproducir todas y cada una de las pulsaciones de las teclas con los tiempos adecuados iba a ser un auténtico coñazo y más para alguien como la mayoría de nosotros que no sabe de música…

…bueno, y digo la mayoría porque por suerte, uno del grupo sí que sabe, así que fue él el que se encagó de transcribir las notas en un editor midi.

No lo había terminado y cuando iba unos 20 segundos, nos pasó el archivo de sonido de lo que había generando hasta el momento.

Pese a no estar completa la pieza, otro del grupo distinguió rápidamente de qué música se trataba. El siguiente enlace es del archivo de sonido que generamos nosotros en midi:

https://bit.ly/3f1CxJi

 

 

Se trata de un tema de:

super mario world

Solve-It EE28 : Nivel 3 “Un nivel diferente”

Y aquí llega el muro con el que nos topamos muchos de los asistentes xD

SolveIt_03

Con diferencia este ha sido el nivel al que más tiempo dedicamos… creo que no fuimos el unico grupo de hecho …

Analizándo la serie de números rápidamente se ve que son 28 números que van de 1 a 26 así que enseguida se te viene a la mente que pueda ser una sustitución simple del alfabeto, con lo que al asociar números a letras debería de salir algo:

cggimatgmsvwkdaidpozhrxpdwil

Evidentemente no podía ser tan fácil …

Hacemos después las 25 combinaciones de código césar a ver si sale algo más legible:

bffhlzsflruvjczhconygqwocvhk
aeegkyrekqtuibygbnmxfpvnbugj
zddfjxqdjpsthaxfamlweoumatfi
ycceiwpciorsgzwezlkvdntlzseh
xbbdhvobhnqrfyvdykjucmskyrdg
waacgunagmpqexucxjitblrjxqcf
vzzbftmzflopdwtbwihsakqiwpbe
uyyaeslyeknocvsavhgrzjphvoad
txxzdrkxdjmnburzugfqyiogunzc
swwycqjwcilmatqytfepxhnftmyb
rvvxbpivbhklzspxsedowgmeslxa
quuwaohuagjkyrowrdcnvfldrkwz
pttvzngtzfijxqnvqcbmuekcqjvy
ossuymfsyehiwpmupbaltdjbpiux
nrrtxlerxdghvoltoazksciaohtw
mqqswkdqwcfgunksnzyjrbhzngsv
lpprvjcpvbeftmjrmyxiqagymfru
kooquibouadesliqlxwhpzfxleqt
jnnpthantzcdrkhpkwvgoyewkdps
immosgzmsybcqjgojvufnxdvjcor
hllnrfylrxabpifniutemwcuibnq
gkkmqexkqwzaohemhtsdlvbthamp
fjjlpdwjpvyzngdlgsrckuasgzlo
eiikocviouxymfckfrqbjtzrfykn
dhhjnbuhntwxlebjeqpaisyqexjm

Como se puede ver … no hay absolutamente nada con un mínimo de sentido…

A partir de aquí anduvimos mirando prácticamente todos los códigos de cifrado simple que pudimos encontrar por internet intentándolos asociar a números del 1 al 26.

De todos los que vimos, tras bastantes horas, hubo un par en concreto que nos llamó especialmente la atención porque podían tener algo de sentido para lo que teníamos. Se trataba de:

Numbered Key y Rag Baby

https://www.cryptogram.org/downloads/aca.info/ciphers/NumberedKey.pdf

https://www.cryptogram.org/downloads/aca.info/ciphers/Ragbaby.pdf

La primera, básicamente, lo que propone es asociar números a letras individuales, pero no tal y como hemos hecho al principio (A=1, B=2, … Z=26) sino añadiendo una clave al inicio y luego completando el abecedario (extendiendo la clave) con las letras que no estuvieran en esta clave; por ejemplo:

Clave: euskalencounter

Clave extendida: euskalencounterbdfghijmpqvwxyz

Ahora asociamos cada letra a un numero:

EUSKALENCO  U  N  T  E  R  B  D  F  G  H  I  J  M  P  Q  V  W  X  Y  Z
12345678910 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

Aunque haya números asociados a letras que ya estaban previamente asociadas a un número, es irrelevante para este cifrado (p.ej. el 1 y el 7 representarían ambos una E).

Este cifrado tiene un problema para nuestro caso en cuestión … y es que requiere de una clave de la cual no sabemos nada porque no se nos dice nada de claves en ningún sitio.

Probamos no obstante varias opciones de claves a ver si había suerte:

Captura de pantalla 2020-07-28 a las 11.21.21.png

Pero no, no la hubo…

Si os fijáis, llegamos hasta a utilizar la password de “un nivel diferente” (o sea, la password del solve it 2).

Por aquí no parecía haber salida …

Aun así, la noche del sábado antes de irme a dormir dejé la siguiente iteración funcionando mientras dormíamos … por ver si sonaba la flauta:

Captura de pantalla 2020-07-28 a las 11.36.16

Lo que hace ahí es una permutación random de la variable abc (la variable ‘abc’ si habéis visto arriba es un string con el abecedario en orden ‘abcd….xyz’),

[NOTA: y aquí os preguntaréis …”¿por qué una permutación random y no todas una a una?” aunque todas son (26!, es decir  4.032914611266057e+26) y os diré… “pues porque intenté hacer las permutaciones de todo el abecedario y el pc me sacó el dedo” así de simple, así que era la solución más rápida xD],

luego lo que hace es usar la clave que nos dan en el enunciado del solveit (que es la tira de números del level (3, 1, 7, 9 …, 4, 12) para formar la frase en base a esa key creada y finalmente …. (ojo que aquí se viene la inventadita …) si por algún casual en la cadena que nos sale como resultado está la palabra “coded” o “troll”, que me la muestre por pantalla. ¿Y por qué “coded” o “troll”? A ver, que nos conocemos ya … imo … xDDD

Bueno, que sea un método de mierda, no lo voy a discutir, y más presuponiendo que en la contraseña va a haber una palabra que sea ‘troll’ y/o una que sea ‘coded’, pero bueno, lo dicho, por si sonaba la flauta …

A la mañana siguiente … habiamos obtenido un mogollonazo de frases … y ninguna con ningún sentido completo (pongo extracto de algunas de ellas):

Captura de pantalla 2020-07-28 a las 11.42.41

A ver, sinceramente, esto no tenía ninguna pinta de que fuera a funcionar pero bueno, era gratis probarlo, asi que … 😛

La otra opción de cifrado que nos detuvimos a mirar un poco fue Rag Baby. Pero aquí tuvimos un problema parecido al inicial (o eso pensamos) y es que no teníamos ninguna key sobre la que partir; y por eso nos centramos mucho más en la Numbered Key.

El cifrado Rag Baby, consiste en tener una clave, como en numbered key, pero en esta ocasión no se puede repetir ninguna letra:

Clave: abcdefghijklmnopqrstuvwxyz

Y para cifrar el mensaje, se parte de la letra que te interesa y se va corriendo a la derecha en orden numérico simple. Para entendernos, por ejemplo:

Mensaje a Cifrar: menudo lio montamos

menudo lio montamos
123456 234 345678910

La primera letra es una 'm', vas a la clave, buscas la 'm' y 
seleccionas la letra que este '1' posición a la derecha => n
La segunda es una 'e', buscas y es una g
etc..

Cuando saltas a la palabra siguiente, la asociación numérica 
no vuelve a empezar de 1, sino que empieza con 2 y así 
sucesivamente ..

Este cifrado lo acabamos desechandoal final porque el resultado cifrado que obtenemos son letras y lo que nosotros tenemos en el enunciado son números…

Fue un error por nuestra parte no dedicar más de 10 minutos a este sistema de cifrado ya que habríamos encontrado la forma de adaptarlo a lo que teníamos para obtener la solución, ya que como veréis, el fundamento del cifrado que usó imobilis es el mismo que el de este Rag Baby.

Como digo, este último cifrado puede que fuera lo más cerca que estuvimos de solucionar el problema. El cifrado que se usa es la codificación Delta.

Este consiste en tener un listado de letras, como la clave del cifrado anterior (solo que aquí además introdujo la ‘ñ’ para trolear un poco…), en un determinado orden (en este caso en orden alfabético), y en base a una lista de números (que es lo que nos da imobilis en el enunciado), ir seleccionando las letras de izquierda a derecha, pero, lógicamente, sin partir de la ‘a’ cada vez que vayas a escoger la siguiente letra; es decir, sería:

Tenemos lo siguiente:
a b c d e f g h i j k l m n ñ o p q r s t u v w x y z
3 1 7 9 7 4 9 16 13 15 1 26 20 8 7 18 13 24 19 16 22 4 23 23 11 9 4 12

Empezamos a descodificar:
Partimos desde la 'a':

Primero vemos un 3, lo que significa: 3 a la derecha desde la 'a' => d
Luego tenemos un 1 => 1 posición a la derecha desde la 'd' => e
7 => 7 posiciones a la derecha desde la 'e' => l
9 => 9 a la derecha desde la 'l' => t
7 => 7 a la derecha desde la 't' => a (después de la 'z' vuelve la 'a')
4 => 4 a la derecha desde la 'a' => e
9 => 9 a la der... => n
16 => c
13 => o
etc 
.... 


Y así, tenemos finalmente la flag del nivel:

deltaencodedwelcometosolveit

 

 

Solve-It EE28 : Nivel 2 “Handle with care”

Vamos con el segundo nivel, que realmente fue el que primero resolvimos.

SolveIt_02

Una imagen acompañaba a este enunciado:

level_2

Imobilis comentó al final de la competi que fue el nivel más “físico” que se le pudo ocurrir para esta edición tan raruna de la Euskal. Estuvo chulo.

Bueno, para empezar, nosotros estábamos sin tinta de impresora así que utilizamos un software de edición de imagen para recortar e ir montando el puzzle:

image_2020-07-27_21-30-08

Por otro lado, otro compi en casa se lo imprimió y se puso a montarlo:

photo_2020-07-27 20.55.48

Con estas 2 vertientes en marcha y haciendo uso de una comunicación y sincronización épica vía telegram a base de fotografías y capturas de la evolución de cada uno de las 2 versiones, solucionamos el puzzle:

image_2020-07-27_21-04-01

La contraseña está en la parte superior. El texto inferior de “Fulfilled and delivered by Systroll” fue lo que primero vimos y probamos como password pero no, fue troleadita de imo.

Captura de pantalla 2020-07-27 a las 21.35.42

Ahí se puede apreciar el mensaje más o menos… Echando mano un poco de imaginación y probando un par de passwords dabamos con la solución:

mult1p4rt m3ssage 1n phys1c4l f0rm4t

 

 

PD: Gracias por ese “Case_sensitive = False” imobilis xDDD