Try and get the flag hidden in this PNG file: pngcrc.png
Opening the downloaded file, you see a fully white image.
You might want to check the MD5 hash for the file:
avalz@zenh~$ md5sum pngcrc.png
3e6bc1b4c62588810efd5ab7e40541d6 pngcrc.png
So far, so good.
Now you might want to check the file format:
avalz@zenh~$ file pngcrc.png
pngcrc.png: PNG image data, 200 x 150, 1-bit colormap, non-interlaced
This output is quite easy to break down:
Interlacing is a technique used to transfer images progressively on a slow network, starting with a low resolution image and working up to a full resolution.
If you are 1337, you can check the 8-bit signature of the file that should
be 89 50 4E 47 0D 0A 1A 0A
:
89
: detects transmissions that support 7-bit data instead of 8-bit data (backward compatibility),50 4E 47
: PNG in ASCII,0D 0A
: a DOS-style line ending (CR+LF),1A
: EOF char,0A
: a Unix-style line ending (LF).Now you know it’s a PNG file! (Or you could’ve just read the title, but you were right not to trust me! *grin*)
Please note that, according to specification, integers in PNG files must be in network byte order, i.e. big endian! Always check endianess.
From Wikipedia:
Portable Network Graphics (PNG /ˈpɪŋ/) is a raster graphics file format that supports lossless data compression.
…cool, I guess?
But here’s the real deal: after the 8-byte header section, PNG files are split in chunks of variable size.
Chunks are divided in critical and ancillary.
Critical chunk are:
type | HEX | DEC |
---|---|---|
width | 00 00 00 C8 |
200 |
height | 00 00 00 96 |
150 |
bit depth | 01 |
1 |
color type | 03 |
3 |
compression method | 00 |
0 |
filter method | 00 |
0 |
interlace method | 00 |
0 |
Ancillary chunks may also appear in the image, as the sRGB chunk to indicate the standard sRBG color space being used or tIME chunk to indicate the time of the last edit on the image.
Each chunk is divided in 4 parts:
Let’s dive into the PLTE chunk!
In a standard Bitmap image, each pixel is represented by a group of 3 bytes, representing its RGB value.
If colors are repeated in the image, the RGB value must be repeated too. A simple compression method for images is storing repeated colors in a palette and have each pixel reference a position in the palette instead of an RGB value.
As I told you above, the palette in a PNG file is located a chunk with type PLTE.
In this challenge, you have a 1-bit palette, which means you can use two colors in the image.
The palette chunk is located from 0x005D to 0x006E:
00 00 00 06 50 4C 54 45 FF FF FF FF FF FF 55 7C F5 6C
This is the chunk breakdown:
Field | HEX | Value |
---|---|---|
Length | 00 00 00 06 |
6 (i.e. 2 colors) |
Chunk Type | 50 4C 54 45 |
“PLTE” |
Data | FF FF FF FF FF FF |
[ White, White ] |
CRC | 55 7C F5 6C |
(the CRC32 value) |
As we can see, we have 2 colors, but both are white! WTF??
The palette has two identical colors. This should raise suspicion, since palette are used to avoid data duplication. NOTE: suspicion should come as a variant of “what if pixels referenced position 0 and position 1 forming a pattern, but since they both render as white I can’t see the pattern?”.
If so, you can change one of the colors with another distinct color (like 00 00 00
, a.k.a. black) and have the
PNG render as different colors (as originally intended).
You can use any Hex editor to do this, but if you don’t know what to choose, you can try hexcurse (just apt install it). The chunk should now look like this:
00 00 00 06 50 4C 54 45 FF FF FF 00 00 00 55 7C F5 6C
Nice! Now just open the image and you should… what? An error? What does it say?
Fatal error reading PNG image file: PLTE: CRC error
Oh right! Chunks are CRCed… that’s fine, we just have to calculate the CRC32 for the block!
Remember you have to calculate it on both the Chunk Type and Data.
You can just create a temporary file and use the crc32
Linux utility to calculate the CRC32 (or calculate it online):
avalz@zenh~$ dd bs=1 skip=97 count=10 if=pngcrc.png of=plte_type_and_data
10+0 records in
10+0 records out
10 bytes copied, 0,000142621 s, 70,1 kB/s
avalz@zenh~$ crc32 plte_type_and_data
55c2d37e
The resulting file plte_type_and_data should contain:
50 4C 54 45 FF FF FF 00 00 00
(4 bytes for “PLTE”, 3 bytes for White, and 3 bytes for Black).
CRC32(50 4C 54 45 FF FF FF 00 00 00
) = 55 C2 D3 7E
This will be the value we have to substitute in the CRC32 field of the chunk.
The resulting PLTE chunk should look like this:
00 00 00 06 50 4C 54 45 FF FF FF 00 00 00 55 C2 D3 7E
This is the resulting file: pngcrc_solved.png
Flag: RockOn_\m/