c0rrupt
Last updated
Last updated
We found this file. Recover the flag. You can also find the file in /problems/c0rrupt_0_1fcad1344c25a122a00721e4af86de13.
Checking the file mystery
indicates nothing. However, viewing the head
of the mystery file shows it looks like a PNG image:
The PNG Specification tells that the PNG signature (first eight bytes of a PNG datastream) must be 137 80 78 71 13 10 26 10
(decimal) or 89 50 4E 47 0D 0A 1A 0A
(hex).
So lets replace the signature using a hex editor:
After the header come a series of chunks. Each chunk starts with 4 bytes for the length of the chunk, 4 bytes for the type, then the chunk content itself (with the length declared earlier) and 4 bytes of a checksum. See the "5.3 Chunk layout" section of this page for more information.
The first chunk is called IHDR
and has the length of 0xD
, so we know that the next 8 bytes are 00 00 00 0D 49 48 44 52
(hex):
Now the file is identified as a PNG file:
pngcheck
lists two more errors to solve:
We need to fix the CRC (checksum) error in chunk pHYs
and find a chunk with an invalid length.
The CRC error means that either the checksum (CRC value) is corrupted, or the data is. To solve this error in chunk pHYs
we can simply replace the CRC (expected) value with the computed value. The purpose of the CRC section is to check for corruption of the data. It essentially is a checksum of that chunk. While replacing the CRC will work, the more "correct" method is to correct the content of pHYs
in order to get the same CRC, thus fixing the corruption that occurred. The below table shows the layout of the pHYs
chunk:
Name | Length | Current Value |
Pixels per unit, X axis | 4 bytes (PNG unsigned integer) | aa 00 16 25 |
Pixels per unit, Y axis | 4 bytes (PNG unsigned integer) | 00 00 16 25 |
Unit specifier | 1 byte | 01 |
Since the pixels per unit differ in just one byte, and the 0xaa
for the X axis makes the value very large, it makes sense to place a zero instead. This fixes the checksum.
The invalid chunk length (too large)
error does not specify a chunk, so we must begin at the start and check each chunk, with the knowledge of the format of chunks and each field’s length: 4 bytes (length) - 4 bytes (chunk type) - lengthbytes (data) - 4 bytes (CRC).
The chunk after pHYs
has a size of 0xaaaaffa5
, which is very large, and a type of \xabDET
which doesn't exist. The closest chunk type is IDAT. Let's fix that by replaying the chunk name with 49 44 41 54
(hex).
To solve the large chunk length we need to calculate the chunk length and update its value. IDAT
chunks must be consecutive so lets find the next one. We find the next IDAT at offset 0x10008
. The first IDAT was at offset 0x57
. The difference is FFB1. We must subtract 4 bytes for the length field of the second IDAT, subtract 4 bytes for the CRC of the first IDAT, and subtract 4 bytes again for the chunktype of the first IDAT. Subtracting 12 in total, we get FFA5. Replace the length field with 00 00 FF A5
(hex). The original value was 0xAAAAFFA5
so we just needed to overwrite the AAAA
with 0000
.
Running pngcheck mystery.png
shows mystery.png (1642x1095, 24-bit RGB, non-interlaced, 96.3%).
which means there are no errors and we can open the image:
picoCTF{c0rrupt10n_1847995}