ee33: Hackit Level 5

Ramandi (w0pr) explicó hasta donde habían llegado, con discusión incluida con Ontza 🙂
Es un webassembly de 2.6Mb (compilado a partir de un programa en Go). Al analizarlo han visto que lanza conexiones contra el server de hackit. Han analizado el protocolo viendo que se pueden hacer peticiones GET y POST. Las GET te devuelven un token que puedes usar luego para las POST. Al hacer un GET han visto también que el server establece conexiones contra tu propia máquina, vía UDP. Ahí se han quedado. Si todo va bien, espero que junto con Ontza podamos hostear una versión jugable en ikasten.io.

http://ikasten.io/images/ee33_level.wasm


HackIt 5: All you need is love. NO Resuelto.

ee33: Hackit Level 4

Interesante prueba. Más sencilla de lo que pensábamos originalmente. Con bastantes troleos, eso sí.


HackIt Level 4: Noise? Resuelto por 1 equipo

http://ikasten.io/images/ee33_level.opus

Fichero transmitido por modem. Baudios: 1200

$ minimodem –rx –file level.wav 1200 > extracted

$ file extracted
extracted: GIF image data, version 89a, 400 x 200

Primero troleo:


Dentro del gif vemos que hay un par de .ogg

$ strings extracted

Vamos con Cursor+Claude Sonnet 4 en modo agente:

$ strings extracted | grep -i ogg

// buscar OGG file signatures:
$ hexdump -C extracted | grep -i «4f676753»

// obtener offsets
$ grep -abbo «OggS» extracted

39513:OggS
48094:OggS
56231:OggS
64935:OggS
73658:OggS
80921:OggS
89402:OggS
98112:OggS
106822:OggS
115533:OggS
124243:OggS
132529:OggS
141010:OggS
149738:OggS
157693:OggS

Comprobamos primero tamaño de extracted:
$ wc -c extracted
162245 extracted

Y procedemos a extraer los OGG files en las posiciones 2981 y 6451.

$ dd if=extracted of=embedded_file1.ogg bs=1 skip=2981 count=$((6451-2981))

$ dd if=extracted of=embedded_file2.ogg bs=1 skip=6451

$ file embedded_file1.ogg embedded_file2.ogg
embedded_file1.ogg: Ogg data, Opus audio, version 0.1, mono, 48000 Hz (Input Sample Rate)
embedded_file2.ogg: Ogg data, Opus audio, version 0.1, mono, 48000 Hz (Input Sample Rate)
hackit2025/hackit4

Repetimos el proceso con el primer ogg, pero esta vez a 300 baudios:

$ minimodem –rx –file embedded_file1.ogg 300 > file1
### CARRIER 300 @ 1250.0 Hz ###
### NOCARRIER ndata=21 confidence=2.343 ampl=0.984 bps=300.00 (rate perfect) ###

Veamos qué hemos sacado en claro:

$ file file1
file1: ASCII text

$ cat file1
youtu.be/dQw4w9WgXcQ
Adivinad a dónde nos lleva el vídeo…

No se podía saber 🙂

Entender lo que había en el segundo ogg fue más sencillo… al menos para los viejos del lugar como el que escribe estas líneas:

Un bonito dump de una cinta de Spectrum. La convertimos a wav y de wav a tape:

$ ffmpeg -i embedded_file2.ogg spectrum_tape.wav

$ python3 -c «import tzxtools; print(dir(tzxtools))»

$ tzxwav -o spectrum_tape.tzx spectrum_tape.wav

$ pip show tzxtools
Name: tzxtools
Version: 1.9.4
Summary: A tool collection for processing tzx files
Home-page: https://codeberg.org/shred/tzxtools
Author: Richard Körber
Author-email: dev@shredzone.de
License: GPLv3+
Location: /opt/hackit2025/hackit4/venv/lib/python3.11/site-packages
Requires: numpy, pypng, sounddevice
Required-by:

Sólo nos queda lanzar un emulador de Spectrum para macOS (o cualquier otro para otro sistema operativo):

$ open -a Fuse.app ../spectrum_tape.tzx

(accesible desde aquí https://fuse-for-macosx.sourceforge.io/)

Y por fin, llegamos al final del level.

ee33: Hackit Level 3


HackIt Nivel 3 – Steamin’ Weenie’ indeed

Podéis descargar la imagen del level aquí:
http://ikasten.io/images/ee33_level.webp

Gracias a @abeaumont the w0pr por el writeup que publicó en el Discord de la party:

Os cuento brevemente el nivel 3 de hackit. Tenemos una imagen WebP. En la imagen se ve que está sacada de una https://gamewallpapers.com/ donde está en formato JPEG o PNG y convertida a WebP. La imagen tiene diferentes chunks RIFF. Uno de estos chunks es XMP, que son metadatos en formato XML. Mirando estos metadatos y comparándolos con el JPEG original vemos que se han añadido localizaciones. Cogiendo las iniciales de las localizaciones y probando diferentes combinaciones obtenemos «HALSPEAKS» que es la primera pista (referencia a IBM). Otro de los chunks que nos encontramos es un chunk desconocido al final del fichero, en formato RIFF, tal como permite la especificación, con FourCC LCHK, en referencia a LeChuck. Es un bloque de 40 bytes de datos codificados en EBCDIC (de ahí la referencia a IBM) que nos da la siguiente pista: «I conceal using 74 steganography methods». Vamos ahora con el chunk de metadatos Exif: mirando el chunk podemos ver que hay un thumbnail. Lo extraemos y vemos que está en formato JPEG y también tiene a su vez metadatos Exif, incluyendo otro thumbnail JPEG, del mismo tamaño que el anterior. jsteg (74 en ASCII es J, de la segunda pista) sin contraseña sobre este segundo thumbnail nos recupera unos datos, que usamos como clave para recuperar datos del primer thumbnail con la herramienta imgconceal (referencia a conceal de la segunda pista). Estos datos están codificados en base58 y consisten en una imagen PNG con un código Data Matrix. Al escanear la contraseña del nivel.

ee33: Hackit Level 2. It’s show time!

La locura del Level2 nos llegó a amargar. Aunque cuando la resolvimos nos llevamos una alegría del copón, todo hay que decirlo. Empezamos sin pistas y con una mala espina considerable al ver tantas URLs de YouTube a vídeos con frases de Arnold Schwarzenegger…con timestamps a frases concretas. No teníamos nada claro qué demonios había que hacer. La primera (mala) idea fue ir apuntando la palabra que oíamos en ese segundo exacto. Vimos que las URLs se reducían a 4 vídeos…pero con 189 timestamps.

Podéis ver lo que luchamos aquí:

https://docs.google.com/spreadsheets/d/1FcJSehUeCfPu7-DF-bVn1zpOntTm2PFkTCGMuhhx3dA/edit?usp=sharing

Como en todos los niveles, en este también tuvimos ayuda de la IA: en concreto Gemini Flash Pro 2.5 tiene soporte de transcripción de audios, con timestamps incluidos. Hace poco publiqué una extensión que hace uso de esta funcionalidad:

https://x.com/juanan/status/1947976791211282737

… pero bueno, perdonadme, me estoy desviando.

Aquí tengo que descubrirme ante el excelente trabajo de Andrea, Servida, Paul, Owen y Urtzi. Esta generación tiene un nivel técnico excelente. Hats off 🎩Consiguieron transcribir TODO lo que se dice en los timestamps de cada vídeo. La pista que publicó Ontza nos hizo ir al detalle.

Y aquí, en este fichero de texto, hay muuuuuchas horas de curro de Servida:

https://gist.github.com/juananpe/26c3a41b5d6b9b97e16cc94be6c1acf6#file-frasesvideosarnold-txt

OK. Pero… ¿y ahora qué? Pues ahora estuvimos horas intentando descifrar qué demonios querían decir esas frases. Os ahorraré nuestras locuras, pero llegamos a interpretar esas palabras cogidas de frases de Arnold en segundos exactos de distintos vídeos como declaración de variables, llamadas a funciones… Sí, una locura… Se la explicamos a Ontza e Immobilis que pasaban por los puestos de los jugadores cada X tiempo y literalmente se rieron a carcajada limpia de nuestras locuras. En ese momento no me sentó muy bien, la verdad 🤡pero tras finalizar el level… hasta yo mismo me reía de nuestro intento de interpretar como código esas frases…. Pero no porque no se pudiera, no, sino porque… YA EXISTïA UN FCKNG intérprete para ello. Exacto, lo que oyes, hay un maldito lenguaje de programación esotérico que permite programar en ArnoldC (lenguaje que interpreta frases de Arnold como si fueran programas, con su propio parser de ArnoldC a bytecode Java, que luego podemos ejecutar)

Ejemplo de «Hello world» en ArnoldC:

IT'S SHOWTIME
TALK TO THE HAND "hello world"
YOU HAVE BEEN TERMINATED

Hay gente para todo, amigos.

Hack It 2: To be or not to be (resuelto por 12 equipos).

La PISTA se publicó cuando llevábamos bastante tiempo de HackIt sin que ningún equipo consiguiera superarla: «Arnold es sabio, es importante escuchar lo que dice.»

Os podéis imaginar nuestra cara de panolis cuando nos enteramos de esto 🤡

En fin… Pero esto no acababa aquí, claro. Tuvimos que pasar por otro proceso de convertir las frases que habíamos transcrito a código ArnoldC válido:

https://gist.github.com/juananpe/26c3a41b5d6b9b97e16cc94be6c1acf6#file-instructions-arnoldc

Tras ello, para entenderlo, usando la especificación del lenguaje (decir «especificación» es ser muy generoso con esta 💩de documentación)

https://github.com/lhartikk/ArnoldC/wiki/ArnoldC

como base, decidimos convertir el código ArnoldC a Python.

Aquí, como curiosidad: Gemini Flash Pro 2.5 + Cursor en modo agente encontró que teníamos clonado el repo de Arnold, donde tienen el parser implementado en Scala:

https://github.com/lhartikk/ArnoldC/blob/master/src/main/scala/org/arnoldc/ArnoldParser.scala

Así que decidió por su cuenta que pasaba de la especificación y que iba a usar el parser como base para entender cómo traducir el programa a Python 🤯

Y lo hizo (alguna vuelta tuvimos que darle, pero básicamente lo hizo casi perfecto):

https://gist.github.com/juananpe/26c3a41b5d6b9b97e16cc94be6c1acf6#file-arnold-py

¡Y llegó la hora de la verdad!

Oh shit… no puede ser… 42? seriously?  Pero… no llevaba ayer el sr. Ontza una camiseta bien chula con ese 42 estampado?

Y sí, para los viejos del lugar:

What is the Answer to the Ultimate Question of Life, the Universe, and Everything?

42

«The Hitchhiker’s Guide to the Galaxy» (Douglas Adams)

Addendum

Me gustó el script sed de transformación de URLs+timestamp a frases de Arnold: Muy old school: rápido, efectivo, sencillo.

Me gustó también la limpieza del script decodificado en pseudo código que se curró Jon de Navarparty. Kudos to Jon, Mattin, tatai and all the Navarparty crew.

Hay intérpretes online para arnoldC.

ee33: Hackit Level 1

Los HackIt de hoy en día ya no tienen nada que ver con lo que eran antes. No porque hayan cambiado las normas o los niveles, sino por la tan alabada/odiada IA.

HackIt1: Easy and simple to understand. Resuelto por 76 equipos.

Un ejemplo: hacer reversing del level 1 ha sido tan fácil como pasárselo a Claude. 2-3 minutos.

¿Es esto algo malo o bueno? La respuesta, como siempre, sería: depende. Personalmente me encanta poder profundizar en las soluciones. Hacerle preguntas al LLM sobre trozos que no entiendo. Intentar leer y comprender en detalle las respuestas que nos da. Por ejemplo:

«Explain me the original source code and why is it reversible»

También me gusta poder ir rápidamente a los levels que una IA no puede resolver directamente. O pedirle ayuda para empezar: pedirle que te dé ideas de cómo avanzar, pruebas de concepto, ayudas gráficas… Evitar la pereza, el miedo a la hoja en blanco. Creo que la IA ha hecho mucho más agradable el participar en el HackIt.

Aunque es cierto que a veces, siento que mis conocimientos se van oxidando, olvidando, por falta de práctica. ¿Delego demasiado en la IA? Es probable, rápidamente te acostumbras a «pasarle el marrón» a un LLM. Máxime cuando los usas en modo agente, con Cursor, Claude Code o Gemini CLI. Pero me estoy desviando del tema que nos había traído hasta aquí. Vayamos a por el level 2.

Related Source code:

https://gist.github.com/juananpe/26c3a41b5d6b9b97e16cc94be6c1acf6#file-level1-js