]> git.somenet.org - pub/jan/ctf-seminar.git/blob - writeups/fkehrer/tasteless19.md
added tasteless19
[pub/jan/ctf-seminar.git] / writeups / fkehrer / tasteless19.md
1 # Tasteless CTF 2019
2
3 I, together with another colleague, spent the whole CTF biting down on one challenge, which, in the end, was solved by other people :sweat_smile:
4
5 ## RGB
6
7 This is one stegano challenge with three flags. We are given a pcapng file, in which there is only a single HTTP connection, in which the requested server returns a png.
8
9 ![](tasteless19/pca.png)
10
11 If we then dump this png from the trafic, we can open and analyze. My first idea was to check the lower bits of the different color channels, which turned out to be a great plan:
12
13 ![2616, Category: Standards Track](tasteless19/red.png)
14 ![2083, Category: Informational](tasteless19/green.png)
15 ![1951, Category: Informational](tasteless19/blue.png)
16 ![Nobody expected this](tasteless19/danish_inhibition.png)
17 _Obviously, even though it was easy to guess that there were pictures hidden in the LSBs, nobody could have expected the original picture._
18
19 Putting these numbers and words into a privacy-respecting search engine of our choice, we could easily explore their deeper meanings: They are the RFCs for HTTP/1.1, PNG and DEFLATE. We took a PNG out of an HTTP stream, and PNGs use DEFLATE to compress their image data. It was all coming together.
20
21 Riding high on all the progress we had made in quite a short time, I was sure we were bound to discover a flag soon. Naturally, this is the point at which we got stuck massively and made no notable progress for the next six hours or so.
22
23 The problem is, we failed to see how this was new information. There was only an HTTP stream and a PNG image to look at anyway, and while one might or might not be familiar with the compression of PNGs, it's not obvious how this information helps in locating a flag.
24
25 Out of hints to persue, we threw every tool we could think of against the problem. Unfortunately, stegsolve showed no further irrularities, and zsteg only showed its usual ton of false positives with nothing useful in between, strings did not show anything that stegsolve or Wireshark could not have told us.
26
27 It was about 16: when we found the hidden pictures, and subsequently got stuck. The next relevant step forward happened at 2:31 in the morning, when @Hetti announced he'd probably found the first flag.
28
29 ### First flag
30
31 ![1000; t](tasteless19/first_flag.png)
32
33 Looking at the bottom of the picture you can see the HTTP transfer chunk marker "1000;", and an inconspicuous "t" behind it. This is the first letter of the first flag. About 1/4 into the stream, these letters start appearing, always behind the chunk markers. Together, they spell out `tctf{NoB0dy_3xPec7s_chUnK_ex7En5iOnz}`
34
35 Shortly afterwards, at 4: in the morning, @ideal swooped in with the second flag.
36
37 ### Second flag
38
39 Remember, a few sentences ago, when I said that stegsolve revealed no more interesting information? That's not exactly right, I just did not recognise it as such.
40
41 ![](tasteless19/second_flag.png)
42
43 As @ideal had noticed, those CRC values did not match the actual PNG chunks they were assigned to, but instead encoded the second flag, `tctf{Wh0_Do3s_n0t_l1k3_fL4gz_1n_cRc}`
44
45 ### Third flag
46
47 Now, we didn't actually find this flag during the CTF, but I want to mention it anyway, because I'm going somewhere with this.
48
49 DEFLATE uses blocks, and apparently, it's possible to leave a bit of data in between these blocks which will be ignored by inflate. This is where the last flag was. To extract it, quite a bit of work is needed. The author of the writeup we read rewrote zlib to do it.
50
51 ## The realisation I didn't have in time
52
53 You as the reader have probably already spotted the theme going on here, but when I was attempting this challenge, I tried many different things (such is the nature of stego), and it only clicked for me once I read of the second flag, at which point it was 4: in the morning, I was tired and had spent the last 12 hours poking at this challenge.
54
55 The theme that we could have spotted a lot earlier is that the HTTP stream, the PNG and the DEFLATE data all came in chunks/blocks, and you can easily hide data in places that don't directly carry data. In the HTTP chunks, the rest of the line after the marker was ignored, in PNG the CRC was never actually checked and in DEFLATE, you can put bytes there which will be skipped. The RFCs were probably supposed to hint at this fact, but I didn't put this together until way too late. I would suggest renaming the challenge to "Chunky RGB" :)