picoCTF 2019 - [Forensic] c0rrupted (250 points)

Written by Maltemo, member of team SinHack in collaboration with SaladeTomateOnion team.


Statement of the challenge

Description

We found this file. Recover the flag.

File

mystery

Hint

Try fixing the file header

Analyzing the file

When you have a challenge with a corrupted file, you can start with file command :

file mystery
    mystery: data

But most of the time, as the file is corrupted, you will obtain this answer : data.

The next step will be to open the file with an hexadecimal editor (here I use bless).

When you are on the file, search for known elements that give hints about the file type.

In this file, I found and IEND and multiple IDAT chunks name in the hexa values, so at this moment I already knew it was a corrupted PNG picture.

Fixing the corruption problems

Usual tips to uncorrupt a PNG

Correcting the PNG header

Lets start with the PNG header. I noticed that it was not correct !
A PNG image always starts with those 4 bytes:

Hexa Values Ascii Translation
89 50 4E 47 . P N G

And at the start of our file, we did have this :

Hexa Values Ascii Translation
89 65 4E 34 . E N 4

So I corrected it with bless hexa editor.

Correcting the IHDR chunk

The next chunk in a PNG after the header is the IHDR chunk, which defines the composition of the image.

Also, the creator of the challenge give you a hint with the two last letters.

In the file, we found this instead :

Hexa Values Ascii Translation
43 22 44 52 C " D R

So I correct it with bless.

Hexa Values Ascii Translation
49 48 44 52 I H D R

Correcting the IDAT chunk

The next chunks after the IHDR were alright until it ends with an unknown header name :

Hexa Values Ascii Translation
AB 44 45 54 . D E T

There is a hint with the D and T letters, which help us to deduce that it is a IDAT chunk.

So let’s change the name of the chunck

Hexa Values Ascii Translation
49 44 41 54 I D A T

Also, I saw the length anounced for this chunk was enormous : AA AA FF A5.

So I checked the lenght of the chunk by selecting the data chunk in bless.
You can find the length value of what you select in the right bottom corner:

Be careful to select only the data chunk and not the checksum (CRC) with it ! It will give you 4 bytes more than the right result.

We can read 0xffa5 bytes.
:smile: Nice, we just get the same values at the end of the wrong length.

We just have to set the first two bytes to zero which give us :
00 00 FF A5

After saving all those modifications, let’s check the integrity of our newly modified image with pngcheck :

pngcheck -v mystery_solved_v1.png
File: mystery_solved_v1.png (202940 bytes)
  File is CORRUPTED.  It seems to have suffered EOL conversion.
ERRORS DETECTED in mystery_solved_v1.png

Correcting again the PNG header to make it readable

After a little time of thinking, I finally found what was wrong.

The PNG header had End Of Line specific that wasn’t recognized on Linux.

The older PNG header was :
89 50 4E 47 0D 0A B0 AA

So I decided to change the PNG header again to correct this problem :

89 50 4E 47 0D 0A 1A 0A

From the wikipedia PNG format page, everything is explained. I copy pasted it here :

Values (hex) Purpose
89 Has the high bit set to detect transmission systems that do not support 8-bit data and to reduce the chance that a text file is mistakenly interpreted as a PNG, or vice versa.
50 4E 47 In ASCII, the letters PNG, allowing a person to identify the format easily if it is viewed in a text editor.
0D 0A A DOS-style line ending (CRLF) to detect DOS-Unix line ending conversion of the data.
1A A byte that stops display of the file under DOS when the command type has been used—the end-of-file character.
0A A Unix-style line ending (LF) to detect Unix-DOS line ending conversion.

After this change, I run again pngcheck :

pngcheck -v mystery_solved_v1.png 
File: mystery_solved_v1.png (202940 bytes)
  chunk IHDR at offset 0x0000c, length 13
    1642 x 1095 image, 24-bit RGB, non-interlaced
  chunk sRGB at offset 0x00025, length 1
    rendering intent = perceptual
  chunk gAMA at offset 0x00032, length 4: 0.45455
  chunk pHYs at offset 0x00042, length 9: 2852132389x5669 pixels/meter
  CRC error in chunk pHYs (computed 38d82c82, expected 495224f0)
ERRORS DETECTED in mystery_solved_v1.png

This error indicates that the checksum of pHYs chunk isn’t right, so let’s change it :smiley: !

pHYs CRC Chunk before rectifying : 49 52 24 F0
pHYs Chunk after rectifying : 38 D8 2C 82

Let’s save again, run the pngcheck :

pngcheck -v mystery_solved_v1.png
File: mystery_solved_v1.png (202940 bytes)
  chunk IHDR at offset 0x0000c, length 13
    1642 x 1095 image, 24-bit RGB, non-interlaced
  chunk sRGB at offset 0x00025, length 1
    rendering intent = perceptual
  chunk gAMA at offset 0x00032, length 4: 0.45455
  chunk pHYs at offset 0x00042, length 9: 2852132389x5669 pixels/meter
  chunk IDAT at offset 0x00057, length 65445
    zlib: deflated, 32K window, fast compression
  chunk IDAT at offset 0x10008, length 65524
  chunk IDAT at offset 0x20008, length 65524
  chunk IDAT at offset 0x30008, length 6304
  chunk IEND at offset 0x318b4, length 0
No errors detected in mystery_solved_v1.png (9 chunks, 96.3% compression).

And we got the final image :

TL;DR

The file was a PNG corrupted, chunk name were changed, the length and the checksum of the PLTE chunk was changed. To make it readable on linux, had to change the PNG header.

Flag

The flag is picoCTF{c0rrupt10n_1847995}


Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.