I took part in the OverTheWire Advent Bonanza 2019. All in all, the CTF was very pleasant because the challenges were interesting to solve, there was quite some time available as well (I spent about two weeks on and off on it) and I also managed to solve a few challenges as well.
The following write-up is about the challenge from day 14: tiny runes.
Description
One of Santa's Little Helpers received an unusual Christmas wish, a copy of the yet to be released Deus Hex game. All they managed to find were fragments from the dialogue system. Can you decode the last one?
Given where the following files in an archive:
. ├── lines1.bin ├── lines1.png ├── lines1.txt ├── lines2.bin ├── lines2.png ├── lines2.txt ├── lines3.bin ├── lines3.png ├── lines3.txt └── lines4.bin
Goal: The goal is to decode lines4.bin into lines4.txt.
Analysis
The *.bin files all start with the following byte sequence:
00000000 54 69 4e 79 4d 65 54 61 00 00 00 10 00 00 00 02 |TiNyMeTa........|
This indicates some kind of magic (TiNyMeTa) but also a header with positions/length. The bin files contain an embedded PNG file starting from byte 89:
00000020 00 00 03 01 89 50 4e 47 0d 0a 1a 0a 00 00 00 0d |.....PNG........|
This embedded image is the same in all files:
Looking at the images (lines1.png, etc.), we can see that the image is used for rendering the text. What text to render is also part of the .bin file:
00000000 4c 69 4e 65 00 00 00 3c 05 01 03 0a 04 08 06 09 |LiNe...<........| 00000010 03 07 00 05 00 0a 01 0b 00 05 02 07 04 08 06 07 |................| 00000020 00 04 03 0b 07 0a 05 0b 05 09 05 09 05 09 04 08 |................| 00000030 02 05 05 09 05 09 05 09 04 08 02 05 05 09 05 09 |................| 00000040 05 09 06 07 4c 69 4e 65 00 00 00 54 05 01 03 0a |....LiNe...T....| 00000050 04 08 06 09 03 07 00 05 00 0a 01 0b 00 05 02 07 |................| 00000060 04 08 06 07 02 05 04 08 00 0a 00 09 01 0b 07 0a |................| 00000070 01 07 00 09 00 0a 04 08 05 07 01 0b 07 0a 04 08 |................| 00000080 00 06 03 07 07 03 03 07 04 08 03 0b 04 08 01 06 |................| 00000090 04 03 00 04 04 08 01 07 07 0a 00 05 05 09 06 07 |................|
Every line segment starts with 4c 69 4e 65 (LiNe), followed by the length of the line as a 4 byte value. Every plain text byte takes 2 bytes in the encoded line. The first byte maps to the column, the second one to the line in the embedded image (indices starting from 0).
This can be easily automated in Python.
Final exploit
MAP = """Q?0\H$Y,
R-L^KJ?k
s#_/m=f9
7d-NE4qr
Pi?V'&XA
n3I?O*;Z
wGpB8cSj
Fg:eby"v
%+?1 !M@
h{2xW.D}
tU|CTz6u
Io>a5l<'
""".split("\n")
with open("lines4.bin", "rb") as f:
lines = f.read().split(b"LiNe")[1:]
for line in lines:
line = line[4:] # skip the length
for column, row in zip(line[::2], line[1::2]):
print(MAP[row][column], end="")
print()
Executing the script prints the flag:
Jock: "Oh my God! JC! A flag!" JC Denton: "A flag! AOTW{wh4t_4_r0tt3n_fi13_f0rm4t}"