NDH Writeups

From YobiWiki
Jump to navigation Jump to search

2014 Nuit du Hack CTF by Hackerzvoice

RTL-SDR stuff

2014 Nuit du Hack CTF Quals by Hackerzvoice

It was a great moment of fun to participate to this year's CTF Quals organised by Hackerzvoice
Solving challenges involved all Pollypocket team members, here is only some polished results.

The greatest

The greatest was a steganography challenge:

We are sure that this e-mail contains hidden information, go get it !
Score 500
Link http://static.nuitduhack.com/mail.tar

Let's get this one:

wget http://static.nuitduhack.com/mail.tar
file mail.tar 
mail.tar: POSIX tar archive (GNU)

And a quick inspection through an hexadecimal editor didn't reveal anything suspicious or noticeable.
So let's open it:

tar tvf mail.tar 
-rw-r--r-- null/null    296008 2014-04-05 07:05 Mail
tar xvf mail.tar

And we get a file called Mail containing an email from BOOBA#rapfr.fr to theflag#nuitduhack.com

Hi dude!
Check out this pic. I used the cool tool I told you about last time, except that I played around with the code a bit.
Speaking of tools, Gregory Evans right?
Have fun trying to find the hidden data ;)
Peace out.

Together with an attachment (well, two attachments as the email was text+html)
The html version differed slightly ("this pic" => "this pick") but that didn't reveal to be of importance.
The other attachment:

Content-Type: image/gif; name=greg.gif
Content-Disposition: attachment; filename=greg.gif
Content-Transfer-Encoding: base64

Let's get it out of the mail using munpack from package mpack

munpack Mail
file greg.gif
greg.gif: GIF image data, version 89a, 500 x 645

greg.gif is... a GIF showing #1 world hacker :-)
Greg.gif

Here again, after inspection, nothing else than the GIF itself in the file.
Using gifsicle from the eponym package

gifsicle --xinfo greg.gif
* greg.gif 1 image
  logical screen 500x645
  global color table [256]
  background 65
  + image #0 500x645

There is no much possibilities for stegano in GIF as the image is made of refs to the colormap so it could be:

  • position of pixels of a given color
  • duplicates or alike in the colormap (e.g. #cccccc and #cccbcc) or other tricks

So let's dump the colormap:

gifsicle --color-info greg.gif
* greg.gif 1 image
  logical screen 500x645
  global color table [256]
  |   0: #FFFFFF      64: #A3835C     128: #1E3E71     192: #769DD1
  |   1: #FCF5F6      65: #A37F81     129: #030915     193: #0F314D
  |   2: #F5E9E8      66: #A27C58     130: #546473     194: #5982BB
[...]
  |  61: #A48A64     125: #675847     189: #4B3A47     253: #000000
  |  62: #A3BCE1     126: #101627     190: #7CA2CD     254: #000000
  |  63: #A38C6B     127: #4C6169     191: #594837     255: #000000
  background 65
  + image #0 500x645

243 colors were used (it's #000000 from 244 to 255)
They are globally sorted from #FFFFFF to #000000 but there are quirks in the sorting: e.g. #126, #129, #191 and #193 in the partial dump above are not sorted properly.
Clearly that can be a way to hide info but the problem as often in steganography challenges is that it's hard to guess how info was stored without the original tool.
And indeed the mail was talking about a modified tool, remember?
Googling for "gif stegano colormap" one of the hits mentioned gifshuffle: a tool used to conceal messages which are stored in GIF images by “shuffling” the color map.
That sounds promising!
And source code is available: http://www.darkside.com.au/gifshuffle/gifshuffle.tar.gz
It compiles smoothly.
Its man page explains very well how it embeds information by first sorting the colormap then changing the order of some of the colors.
Exactly what we observed!
There is also an encryption mode but that would be hard to crack and when used the colormap looks completely randomly sorted, which is not what we observed, luckily!
There is also a basic compression option
But when we try on the gif:

./gifshuffle greg.gif
<output is binary garbage>
./gifshuffle -C greg.gif
                                 uttEioe)udi
sgahat	aam wttf?ltkt tc(w a't weuos nllopcdyiccefohtr*c'npi na iarinrrrmgY rtolra"dbedna0tywUpea)ph   ic.i@t)w   i  Rdlnos 
igoi atyd	tns s t  hb bs0.iianiubiksiata gOobroiaw ..occsasniDtmdder tdpcatr. nI*ti	inmuaoitdfK  voesd ab leany0. l,nnetuCi .aabsas th e  g
Eo)bvrncitrid
sa	n.  Msdree

Hmmm.
Remember the mail, the tool was modified by the sender...
We can use gifshuffle ourselves on a gif to add some data into it.
We can use greg.gif as it will first sort the table, erasing the old data, then embed ours.

./gifshuffle -m fooooooooooooooooooooooooooooooooooooooooooooooooooooo greg.gif greg2.gif
Message used approximately 27.25% of available space.
gifsicle --color-info greg2.gif 
* greg2.gif 1 image
  logical screen 500x645
  global color table [256]
  |   0: #000000      64: #3B608F     128: #7C9CC5     192: #95675B
  |   1: #010001      65: #3C4230     129: #7CA2CD     193: #9C9499
  |   2: #030915      66: #44555D     130: #7CA3D2     194: #968C94
[...]
  |  61: #372819     125: #7B654B     189: #DFC69D     253: #000000
  |  62: #372925     126: #7B9ECB     190: #E6D9D8     254: #000000
  |  63: #394A58     127: #7C7456     191: #CFD8E9     255: #000000
  background 214
  + image #0 500x645

See, sorted colormap except for #191, #194
But global sorting is from #000000 to #FFFFFF (then some #000000 for the unused colors)
That's the thing we need to modify too in the tool
gifshuffle/encode.c colourmap_encode() starts by sorting the colormap:

if (encrypting_colourmap ()) {
    ...
    qsort (ci_array, ncols, sizeof (CMAP_INFO), cmap_encrypt_cmp);
} else
    qsort (ci_array, ncols, sizeof (CMAP_INFO), cmap_cmp);

Sorting is based on the comparison function cmap_cmp() defined in the same file:

static int cmap_cmp ( const void *p1, const void *p2) {
    return (rgb_cmp (&((CMAP_INFO *) p1)->rgb, &((CMAP_INFO *) p2)->rgb));
}

Let's just swap its arguments to inverse its effect:

static int cmap_cmp ( const void *p1, const void *p2) {
    return (rgb_cmp (&((CMAP_INFO *) p2)->rgb, &((CMAP_INFO *) p1)->rgb));
}

Let's try it:

gifshuffle_inverted greg.gif
The flag for this wonderful Gregory D. Evans picture is : L0n9L1v3TheW0rldN00n3Hack3rGr3g0ryD.3van

Another One

The Another One was a crypto challenge:

This is a crypted image, you must extract the data.
Score 300
Link http://static.nuitduhack.com/crypted.bmp

Let's get this one:

wget http://static.nuitduhack.com/crypted.bmp
hd crypted.bmp |head 
00000000  16 3c 04 03 3d 66 9e 02  ad 35 5d d0 3d ea 22 1e  |.<..=f...5].=.".|
00000010  c2 6c 32 02 13 d4 51 cc  37 3b 04 a9 7a ab 24 44  |.l2...Q.7;..z.$D|
00000020  ed dd 39 17 4c 18 8e 20  f3 42 ab 86 c4 1c 4c a4  |..9.L.. .B....L.|
00000030  da dc e7 65 22 33 97 9c  f5 95 fd e1 34 cd a7 bb  |...e"3......4...|
00000040  fb 5e a1 b7 89 5c 5e 8d  a7 5a 0d df 03 00 fe 3b  |.^...\^..Z.....;|
*
00001ec0  35 2e 5c 08 66 50 4d ab  60 04 d5 db da 80 32 17  |5.\.fPM.`.....2.|
00001ed0  fb 5e a1 b7 89 5c 5e 8d  a7 5a 0d df 03 00 fe 3b  |.^...\^..Z.....;|
*
00003180  d4 76 9b 3c d0 aa a5 57  e2 11 a3 e6 9e ab c5 6d  |.v.<...W.......m|

A 128 bits sequence is repeating itself quite often:

fb 5e a1 b7 89 5c 5e 8d  a7 5a 0d df 03 00 fe 3b 

This is typical of the usage of a block cipher in ECB mode when plaintext is repeating, which is likely to happen on an encrypted BMP drawing (much less likely if it's an actual photography).
Let's XOR the file with that sequence and 0xFF to get 0xFF (white pixels?) (very dirty way... at CTF we want to code fast, not the program to be the most optimized...)

#!/usr/bin/env python
c=open("crypted.bmp", 'rb').read()
p=open("out.bmp",'wb')
k=[]
for i in range(len(c)):
  if not k:
    k=list("fb 5e a1 b7 89 5c 5e 8d  a7 5a 0d df 03 00 fe 3b".replace(" ","").decode('hex'))
  p.write(chr(ord(c[i]) ^ ord(k.pop(0)) ^ 0xFF))
p.close()

The result is a file with many zeroes but it's still not a valid BMP (BTW is it really a BMP? Can we trust the file extension??). The background color was not encoded with 0x00 apparently.
Neither with 0xFF, we tested it by XORing additionally with 0xFF.
Time to read some BMP file format description...
Guessing what would be the initial header content is quite hard.
I took another approach:
Dump the raw content in a PPM file by adding a simple header.
PPM encodes each pixel in 3 bytes
BMP can encode each pixel in 2,3 or 4 bytes
We'll see...
We've also to provide the image size... Let's try 1200x1200: (1200*1200*3=4320000, the filesize)
We also flip top and bottom as BMP encodes the image from bottom to top

(echo -e -n "P6\n1200\n1200\n255\n";cat out.bmp)|pnmflip -tb|pnmtopng > out.png


Ndhanotherone1.png

We see things!
Playing around with the image size, we find out a satisfying ratio:

(echo -e -n "P6\n1600\n900\n255\n";cat out.bmp)|pnmflip -tb|pnmtopng > out.png


Ndhanotherone2.png

And this is enough to get our flag!
Never never use EBC mode ;-)
The quality is enough but actually one can do better, e.g. in cases the image is not that clear.
By carefully choosing replacements for repeating or non-repeating ECB blocks we can obtain something like this:
Ndhanotherone3.png
See https://doegox.github.io/ElectronicColoringBook/ for more ECB coloring fun!