You arrive at the location through the coordinates that you got from the assassin, a luxurious yacht. A fat, bald man lies on a puma couch. He sips on a dry martini, smokes the biggest cigar you've ever seen and when he smiles, a golden tooth is revealed. You can’t help but smile back at him, although you think the place seems shady. "Welcome to my yacht, Johnson, finally you show us your face. Have you killed the AGENT now? Good! You’re here to collect your reward I presume? I’ll have my guy finalize the transaction but before you leave I need a small favour from you." It seems that he is mistaking you for the assassin but you don’t mind.
#### Challenge: Hide and seek (misc)
The man hands you a pendrive which you reluctantly connect to your laptop. He says he got it from a partner, and the partner claims that he hid valuable information in that PNG there. The problem is, it looks empty. See if you can find anything.
### After solving
I see you are a person of many qualities. I must say I am impressed. One last thing, I just have to ask, see you always struck me as a fan of sports, I don’t know why. What do you prefer? Basketball or Soccer?
#### Basketball ([10](#))
"Well then, if you are hungry for more missions, I got a thing in NYC for you. The person who wanted the AGENT dead, also owns this office complex, and needs a guy to guard a certain event that will take place there tomorrow. I'm sorry that I can’t reveal more information than that, but at least it is well paid, and perhaps you can watch a game of basketball on your way home, deal?."
#### Soccer? Do you mean football? ([11](#))
"Well then, if you are hungry for more missions, I got a thing in London for you. The person who wanted the AGENT dead, also owns this warehouse near Heathrow, and needs a guy to guard a certain event that will take place there tomorrow. I'm sorry that I can’t reveal more information than that, but at least it is well paid, and perhaps you can watch a game of football on your way home, deal?."
_Note: The image is supposed to look like half is missing._
## Recon
The attachment contains one file: `hideandseek.png`.
It is an image of 1000x1000 pixels with a size of 15KB.
## Solving
Upon opening the image we don't really see anything, depending on the image viewer we only get a black image. So first thing I thought of was regular stenography.
### Basic stenography
After playing with the image a bit and using tools like [`zsteg`](https://github.com/zed-0xff/zsteg) and `steghide`, I found it to not be your standard stenograpy.
So I started looking a the hex representation of the image (using `hexdump` or `hexyl`), and found some PNG data chunks. I didn't know anything about PNG files though.
### PNG specification
When reading through [the PNG specification](http://libpng.org/pub/png/spec/iso/index-object.html), I found that it was actually pretty huge. We (probably) don't need to know everything though, so let's skip to [the datastream specification](http://libpng.org/pub/png/spec/iso/index-object.html#4Concepts.Format). Here we find the following text:
> There are 18 chunk types defined in this International Standard. Chunk types are four-byte sequences chosen so that they correspond to readable labels when interpreted in the ISO 646.IRV:1991 character set. The first four are termed critical chunks, which shall be understood and correctly interpreted according to the provisions of this International Standard. These are:
>
> - [IHDR](http://libpng.org/pub/png/spec/iso/index-object.html#11IHDR): image header, which is the first chunk in a PNG datastream.
> - [PLTE](http://libpng.org/pub/png/spec/iso/index-object.html#11PLTE): palette table associated with indexed PNG images.
> - [IDAT](http://libpng.org/pub/png/spec/iso/index-object.html#11IDAT): image data chunks.
> - [IEND](http://libpng.org/pub/png/spec/iso/index-object.html#11IEND): image trailer, which is the last chunk in a PNG datastream.
>
> The remaining 14 chunk types are termed ancillary chunk types, which encoders may generate and decoders may interpret.
>
> - Transparency information: [tRNS](http://libpng.org/pub/png/spec/iso/index-object.html#11tRNS) (see 11.3.2: [Transparency information](http://libpng.org/pub/png/spec/iso/index-object.html#11transinfo)).
> - Colour space information: [cHRM](http://libpng.org/pub/png/spec/iso/index-object.html#11cHRM), [gAMA](http://libpng.org/pub/png/spec/iso/index-object.html#11gAMA), [iCCP](http://libpng.org/pub/png/spec/iso/index-object.html#11iCCP), [sBIT](http://libpng.org/pub/png/spec/iso/index-object.html#11sBIT), [sRGB](http://libpng.org/pub/png/spec/iso/index-object.html#11sRGB) (see 11.3.3: [Colour space information](http://libpng.org/pub/png/spec/iso/index-object.html#11addnlcolinfo)).
> - Time information: [tIME](http://libpng.org/pub/png/spec/iso/index-object.html#11tIME) (see 11.3.6: [Time stamp information](http://libpng.org/pub/png/spec/iso/index-object.html#11timestampinfo)).
When reading through the hex representation of the image, I could find the mandatory `IHDR`, `IDAT` and `IEND` chucks. However, I also found some `eDIH` chunks. When looking around on the internet I could not find anything about it, so it had to be something to do with the challenge.
Firstly, I had to find out how chunks actually work.
### Chunk specification
When looking at [the chunk layout documentation](http://libpng.org/pub/png/spec/iso/index-object.html#5Chunk-layout), it says a chunk consists of four field; `LENGTH`, `CHUNK TYPE`, `CHUNK DATA` and `CRC`.
So I grabbed one `eDIH` chunk and verified/decoded it.
```text
00 00 00 01 65 44 49 48 31 95 B3 B3 32
```
| Part | HEX | Decoded |
| ------ | ------------- | ------- |
| Length | `00 00 00 01` | `1` |
| Type | `65 44 49 48` | `eDIH` |
| Data | `31` | `1` |
| CRC | `95 B3 B3 32` | `....` |
Now we have to get all the `eDIH` chunks.
### eDIH chunks
The flag is probably stored in the data fields of the `eDIH` chunks, so I wrote a little script to get all these fields and decode them.
```py
import re
import base64
with open("hideandseek.png", 'rb') as file:
image_data = file.read()
occurrences = (location.end() for location in re.finditer(b"eDIH", image_data))
print("".join(chr(image_data[index]) for index in occurrences))
```
When running it, it returns the following:
```text
Q1RGe0RpZFlvdUtub3dQTkdpc1Byb25vdW5jZWRQSU5HP30=
```
This looks like some base64, so I decoded it using the following command: