Title: brainfun
Competition: CSAW quals 2016
Category: Forensics
Points: 150
Description: Scrambled Fun for Everyone! Author: fang0654 <brainfun.png>
- There's nothing hidden in the file other than the pixel data.
- The image is 512x512, but can be scaled down 32x32 to match the blocks to pixels.
- The RGB values are all multiples of 0x10. An example pixel could be
(0x40, 0xf0, 0x20)
. - There is also transparency.
- There aren't that many different alpha values. Many occur around the same number of times (28-30).
- The alpha values are in the printable ASCII range.
- The values that occur around the same number of times are lowercase letters,
and the others are
+
,-
,.
, and a single newline. - The name of the challenge is brainfun, which sounds kind of like brainfuck, which is an esoteric programming language which uses those symbols.
- The challenge description says that it's scrambled.
- Pige0n noticed that the letters can be rearranged to spell "my rainbow", which suggests that there is a definite order to the pixels.
- There are probably sections of lowercase letters and sections of brainfuck symbols.
- Brainfuck symbols had red values around the middle, and lowercase letters had low and high values.
- Sort the pixel values by RGB value, using the key
red<<8 + green<<4 + blue
. Edit (thanks BookGin):- It should be
red<<16 + green<<8 + blue
to sort by full values, but I abused the fact that all the RGB values take the format of0xN0
, so a pixel(0x10, 0x20, 0x30)
will get converted to0x1230
this way. - I probably should have used
struct.pack("hhh", red, green, blue)
- It should be
- It turns out that they spell "owmybrain", but whatever.
- Running that as brainfuck spits out the flag:
flag{w3_r_th3_h0llow_m3n}
- Here's a one-liner (it's not very efficient):
python3 -c '__import__("pybrainfuck").BrainFck().run("".join([chr(p[3]) for p in sorted([list(__import__("PIL", globals(), locals(), ["Image"]).Image.open("brainfun.png").getdata())[r*512 + c] for r in range(0, 512, 16) for c in range(0, 512, 16)], key=lambda p: (p[0]<<8) + (p[1]<<4) + p[2])]))'
You could also have just done
pixels.sort()
, which uses Python's builtin tuple comparison to fist compare red, then green, etc. That's what I did for this challenge