Monday, March 5, 2018

Pragyan CTF 2018 - Pictorial mess (300)




This was an annoying but very rewarding challenge in the end once the idea came together.
We start off with a file called files.zip which contains seven png's from 0-6.png:


Source files: https://github.com/vitapluvia/Pragyan-CTF-2018/tree/master/stego/pictoral-mess

Looking at these we have the following images filled with color:














First we could see if any of these images have hidden values in the RGB values, they seem like a good candidate for this. Opening them in stegsolve and cycling through the channel filters, we start to see letters appear:



This seems to spell out 'MakeMeTall', attempting to submit this as the flag failed though.  It was just a clue towards the next step.

After some procrastination, it was time to try what must have been the right path. Edit the PNG in a hex editor and change the height value.

For this we'll source the amazing corkami binary references - https://github.com/corkami/pics, in particular the PNG reference:


There are many great hex editors out there, feel free to use your favorite if you're following along.

We want to look for IHDR and then skip past the next 4 bytes for the width to get to the height.
For each image, this value is set to 0x0000017C.

To make the image taller, let's increase that height value to 0x0000047C.
After we save the new copy of this image, we'll notice a CRC error when checking it using pngcheck.

zlib warning:  different version (expected 1.2.5, using 1.2.11)

0.png  CRC error in chunk IHDR (computed b301c292, expected e139ed35)
ERROR: 0.png

If we run pngcheck again, we get no errors, and if we look at the image it seems to have some extra information on the bottom!


Now we can repeat this process for the other images and check out the collection we get back:



Now this looks a lot like the bottom strips may be bits which could decode to character values. There are 20 'bits' per image and 7 images total. If we stack these bits, we get the header of this writeup:


If we attempt to concatenate these rows of bits together, we don't get anything too useful at all.
If we go from top to bottom, left to right, we're able to find a message. Trying the first column we can see what it decodes to:

$ python
>>> chr(0b1110000)
'p'

This is the beginning of the expected flag format 'pctf{', looks good!

Let's throw this in a small python script to decode it all:

#!/usr/bin/env python
from pwn import unbits

b = [
  '11111101111110101111',
  '11111011111111111111',
  '10101011000101110011',
  '00001001110010000101',
  '00110000111100001011',
  '01011110110001101000',
  '01001011100001111001',
]

flag = ''

for x in range(0, 20):
  bits = [0]
  for y in range(0, 7):
    bits += b[y][x]
  flag += unbits(bits)

print flag

This results in:

pctf{B3yondth3s1ght}