WPICTF 2018: Jay-Peg Writeup - LSB-Stego
By David Buchanan, 15th April 2018
Apparently I was the only person to solve this challenge, which genuinely surprised me - It really isn't that hard! But since I was the only solver, I guess I have to do a writeup now...
jay-peg - 400pts https://drive.google.com/file/d/1qIe4QkUBzXKmFeqEwIVodFp3h2pb-umd/view?usp=sharing Hint: Parity made by awg
Here's the image:
Note, this is a lossy version because the actual file is huge
An obvious reference to https://www.youtube.com/watch?v=QEzhxP-pdos
Well, I know what a jpeg is, and the first thing I noticed is that this isn't actually a jpeg:
1 2 | $ file hank.jpeg hank.jpeg: PNG image data, 1600 x 1197, 8-bit/color RGBA, non-interlaced |
I had a look at the different colour channels with stegsolve
, but nothing
really stood out - there was a lot of noise on all the channels. However, I noticed
that the LSB of the alpha channel was noisy too, whereas the higher order bits
were always set. Clearly, there's something going on with the LSBs here...
First, I converted the png to a raw RGBA bitmap, for easier processing with python:
1 | $ convert hank.jpeg raw.rgba |
Then, with the hint in mind, I wrote this simple python script to calculate the parity bit of the LSBs for each pixel, and write them to a file:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | data = open("raw.rgba", "rb").read() bitcount = 0 bits = 0 out = [] for i in range(0, len(data), 4): parity = data[i] ^ data[i+1] ^ data[i+2] ^ data[i+3] bits |= (parity&1) << bitcount bitcount += 1 if bitcount == 8: out.append(bits) bitcount = 0 bits = 0 f = open("output", "wb") f.write(bytes(out)) f.close() |
This resulted in a zip, file, which I extracted:
1 2 3 4 5 | $ file output output: Zip archive data, at least v2.0 to extract $ unzip output Archive: output inflating: mod.iqm |
This resulted in a file called mod.iqm
. After a bit of googling, I found
a tool for viewing IQM files: http://www.moddb.com/mods/r-reinhard/addons/iqebrowser-v110
This is what I saw:
And that was all!