Sunday, July 25, 2010

Write-up on RootBSD's forensics challenge

Saturday, RootBSD (@r00tbsd #hackbbs) organized a small forensics challenge (french). About 30 people played the challenge, and we had fun. Fellow Nibbles member sh4ka quickly took the first place in just 2 hours and therefore won a shirt of his choice at I played with two friends - 0vercl0k and thaw - and we took second place a few minutes after sh4ka. Below is my write-up for all the flags, but other players have also posted their write-ups: m_101 and tryks.


We were given an 17MB archive of a linux home directory, and instructed to find 10 flags, in the form of md5 hashes. The global level of the challenge was easy and so very interesting for people who want to try forensics.

First, extract the archive:
$ tar zxf forensics_challenge.tar.gz
$ cd forensics_challenge

Flag 1: Private/.facile

Flags are md5 hashes? Use grep and a small regular expression to find such flags:
$ grep -EHiorn '[0-9a-f]{32}' .
This is our first flag: 8cd4525b78f0488581316bba7734e758.

Flag 2: Private/priv.txt

File Private/priv.txt is suspicious:
$ cat private/priv.txt
Sh mshn lza 55ml6j0m75j563099l3k332m5j64l690
We quickly recognize a Caesar cipher. Let's see what we have with all different keys:
>>> import string
>>> def cesar(s,k):
...   o = ''
...   for c in s:
...     if c in string.letters:
...       r = ord('A') if c in string.uppercase else ord('a')
...       o += chr(r+(ord(c)-r-k)%26)
...     else: # don't touch other chars (numbers, punctuation..)
...       o += c
...   return o
>>> s='Sh mshn lza 55ml6j0m75j563099l3k332m5j64l690'
>>> for k in range(26):
...  print "%i: %s" % (k, cesar(s,k))
'7: La flag est 55fe6c0f75c563099e3d332f5c64e690'
The key was 7 and the flag is 55fe6c0f75c563099e3d332f5c64e690.

Flag 3: Musics/miel-vie.mp3

Thanks to id3 tool (package of the same name), we see the ID3 tags:
$ id3 -l miel-vie.mp3
Title  : miel-vie                        Artist: ???
Album  : VW4gZGUgcGx1cyAzMzA2ZWMwOTdmYz  Year:     , Genre: Unknown (255)
Comment: gzMDgxNzE4MTUxNmVhMjhkZWQzOA==
Looks like base64:
$ echo -n 'VW4gZGUgcGx1cyAzMzA2ZWMwOTdmYzgzMDgxNzE4MTUxNmVhMjhkZWQzOA==' |base64 -d
Un de plus 3306ec097fc830817181516ea28ded38
It says: one more flag 3306ec097fc830817181516ea28ded38.

As a proof there is no other flag in the file, we use Google to find the original mp3 and binary diff it with hexdump+diff:
$ wget -q ""
$ diff -u <(hexdump -C miel-vie.mp3) <(hexdump -C miel-vie.mp3.1)
--- /dev/fd/63  2010-07-24 22:49:53.781841807 +0200
+++ /dev/fd/62  2010-07-24 22:49:53.799234778 +0200
@@ -170399,13 +170399,5 @@
 0029dcd0  0000000001a40000 0000000034800000  |............4...|
 0029dce0  0000000000000000 0000000000000000  |................|
-0029ddd0  0000000000000000 0000000000005441  |..............TA|
-0029dde0  476d69656c2d7669 6500000000000000  |Gmiel-vie.......|
-0029ddf0  0000000000000000 000000000000003f  |...............?|
-0029de00  3f3f000000000000 0000000000000000  |??..............|
-0029de10  0000000000000000 0000000000565734  |.............VW4|
-0029de20  675a475567634778 316379417a4d7a41  |gZGUgcGx1cyAzMzA|
-0029de30  325a574d774f5464 6d597a0000000067  |2ZWMwOTdmYz....g|
-0029de40  7a4d4467784e7a45 344d5455784e6d56  |zMDgxNzE4MTUxNmV|
-0029de50  684d6a686b5a5751 7a4f413d3dff      |hMjhkZWQzOA==.|
+0029ddd0  0000000000000000 000000000000      |..............|
Note the shell trick of double <(cmd) to give files in two input descriptors.

We are now sure there is no other flag than the base64 one in the ID3 tags.

Flag 4: Images/fractale5.jpg

The picture has an EXIF comment, that we can see with jhead as I already showed:
$ jhead fractale5.jpg
File name    : fractale5.jpg
File size    : 407821 bytes
File date    : 2010:07:14 23:15:38
Resolution   : 664 x 498
Comment      : 1dcd64e16d97507052d67a6d0557ee8d
Or simply with exiv2:
$ exiv2 -pc fractale5.jpg
The flag is in the EXIF comment field: 1dcd64e16d97507052d67a6d0557ee8d.

Flag 5: Images/jpg_NDH080408ak.jpg

The picture has a thumbnail, that we can extract with:
$ exiv2 -et jpg_NDH080408ak.jpg
The thumbnail is a picture showing the flag: f2c7ec9225e9158deb7ca7aad0f3504b.

Now, just like with the mp3 file, to be sure there is no other flag hidden in the other pictures, we search the pictures on Google images, find the originals and compare:
$ md5sum *
fa033b0f3f0bb536770bbd5580575aac  fractale.1.jpg
fa033b0f3f0bb536770bbd5580575aac  fractale.jpg
9798b0bd4733cdceafe41c60549340ee  fractale1.1.jpg
9798b0bd4733cdceafe41c60549340ee  fractale1.jpg
e3b2fcef09ce3f2b00b207a259d0e9d9  fractale10.1.jpg
e3b2fcef09ce3f2b00b207a259d0e9d9  fractale10.jpg
0fc57bbea15fe0248998e3a8f8de7567  fractale11.1.jpg
0fc57bbea15fe0248998e3a8f8de7567  fractale11.jpg
ed8a7bf5c9b2646a92faaeea39b5a78b  fractale2.1.png
ed8a7bf5c9b2646a92faaeea39b5a78b  fractale2.png
7bb953cd11f88f7f82a17f837a69fb1d  fractale3.1.jpg
7bb953cd11f88f7f82a17f837a69fb1d  fractale3.jpg
e9795f353f24ebef3d568d9025feba22  fractale4.1.jpg
e9795f353f24ebef3d568d9025feba22  fractale4.jpg
9b0cda35bec3154571d26975bc7c309c  fractale5.1.jpg <= different
d1dd0deefe82780a610bea6f83da8b8b  fractale5.jpg
50d72c32b8b9bdc43c72ebdd1b6c2f49  fractale6.1.jpg
50d72c32b8b9bdc43c72ebdd1b6c2f49  fractale6.jpg
7be72e674c0a62d21247eb000d8df597  fractale7.1.jpg
7be72e674c0a62d21247eb000d8df597  fractale7.jpg
6c3217235c4f91ed6c8a763d7ddb8063  fractale8.1.jpg
6c3217235c4f91ed6c8a763d7ddb8063  fractale8.jpg
9dfc8a27e6aeca6c684f3bc9324bb91d  fractale9.1.jpg
9dfc8a27e6aeca6c684f3bc9324bb91d  fractale9.jpg
020d7508ed6466a41c58e38aada2cf1d  jpg_NDH080408ak.1.jpg <= different
8e08485bd52163e682f9e7cc88de92c2  jpg_NDH080408ak.jpg
We can see that the only different sums are for the file where we already extracted the flag. So no more flag here!

Flag 6: Documents/World_of_Fractal.pdf

Again, we use Google to find the original PDF files and compare their hash to find where is the flag:
$ md5sum *
3dc8480a8762d1eb2af09482468b0298  03-icar-fractal.pdf
3dc8480a8762d1eb2af09482468b0298  03-icar-fractal.pdf.1
07528724e9c0aea37656e0c794ce30d7  Fractal.pdf
07528724e9c0aea37656e0c794ce30d7  Fractal.pdf.1
bdbf94bb16895468409f68ecf9401e02  World_of_Fractal.pdf => flag must be here!
6263b0228a08fe3de7677ad2a5cba621  World_of_Fractal.pdf.1 
8dcdaea419993e2fdb7f736d539d94da  fractales.pdf
8dcdaea419993e2fdb7f736d539d94da  fractales.pdf.1
3801073a72e037ee60b532cb8a1254dc  fractals2.pdf
3801073a72e037ee60b532cb8a1254dc  fractals2.pdf.1

Now just binary diff the two files:
$ diff -u <(hexdump -C World_of_Fractal.pdf) <(hexdump -C World_of_Fractal.pdf.1)
--- /dev/fd/63  2010-07-24 22:16:58.178382800 +0200
+++ /dev/fd/62  2010-07-24 22:16:58.165298097 +0200
@@ -77407,9 +77407,9 @@
 0012ee00  6f626a0d3c3c200d 2f50726f64756365  |obj.<< ./Produce|
 0012ee10  7220284163726f62 6174204469737469  |r (Acrobat Disti|
 0012ee20  6c6c657220352e30 205c2857696e646f  |ller 5.0 \(Windo|
-0012ee30  77735c29290d2f41 7574686f72202866  |ws\))./Author (f|
-0012ee40  3138303938343465 6161316562653035  |1809844eaa1ebe05|
-0012ee50  3062643439373361 3435366231353029  |0bd4973a456b150)|
+0012ee30  77735c29290d2f41 7574686f7220286d  |ws\))./Author (m|
+0012ee40  6f6f636869290d2f 43726561746f7220  |oochi)./Creator |
+0012ee50  284163726f626174 205044464d616b65  |(Acrobat PDFMake|
 0012ee60  7220352e3020666f 7220576f7264290d  |r 5.0 for Word).|
 0012ee70  2f4d6f6444617465 2028443a32303032  |/ModDate (D:2002|
 0012ee80  3034303931373336 32332b3038273030  |0409173623+08'00|
We have our flag: f1809844eaa1ebe050bd4973a456b150, and thanks to Google we also know that there is no other flag in the PDF files.

Flag 7: FS.dd, foremost

File does not return anything interesting on this file:
$ file FS.dd
FS.dd: data
RootBSD said it's because the ext2 header has been voluntarily corrupted. sh4ka just told me one can restore this header simply with: mke2fs -S FS.dd, to write superblock and group descriptors only (see man mke2fs).

But this does not stop us. We grab our favourite file carving tool foremost and run it over FS.dd to find files in it:
$ foremost FS.dd
Processing: FS.dd
$ ls -R output/
audit.txt  jpg

Success! Open the picture and see the flag: a84774bcf9e00b394d75e4367472e58e.

Flag 8: FS.dd, hexdump

Maybe there are other flags in this filesystem image. It is a big file, but has many zeroes. Thanks to the great hexdump utility which does not print repeating lines (instead it prints a star *), we can easily view its content in hex:
$ hexdump -C FS.dd
00700400  623056494d20372e 3200000000100000  |b0VIM 7.2.......|
00700410  0000000000000000 7e0a0000726f6f74  |........~...root|
00700420  0000000000000000 0000000000000000  |................|
00700440  000000006b657669 6e2d6c6170746f70  |....kevin-laptop|
00700450  0000000000000000 0000000000000000  |................|
00700460  0000000000000000 000000002f6d6e74  |............/mnt|
00700470  2f666c6167732e74 7874000000000000  |/flags.txt......|
00700480  0000000000000000 0000000000000000  |................|
007007e0  0000000000000000 0000000000000d55  |...............U|
007007f0  3332313023222120 1312550000000000  |3210#"! ..U.....|
00700800  0000000000000000 0000000000000000  |................|
00702400  4a6f6c69203a2032 3834333036323135  |Joli : 284306215|
00702410  3331323166656430 3535383631333630  |3121fed055861360|
00702420  323634356638310a 0000000000000000  |2645f81.........|
00702430  0000000000000000 0000000000000000  |................|
Here is our flag: 2843062153121fed0558613602645f81.

Flag 9: .mozilla/firefox profile, master password

In the hidden directory .mozilla we have a full profile of a user. Interesting URLs can be found in the places.sqlite database. To explore this SQLite version 3 database files, we will use its command-line interface sqlite3:
$ sqlite3 places.sqlite
SQLite version 3.5.9
Enter ".help" for instructions
sqlite> .tables
moz_anno_attributes  moz_favicons         moz_keywords
moz_annos            moz_historyvisits    moz_places
moz_bookmarks        moz_inputhistory
moz_bookmarks_roots  moz_items_annos
sqlite> .dump moz_places
INSERT INTO "moz_places" VALUES(95,'','','moc.det00r.www.',1,0,0,NULL,100,1279220319364367);
INSERT INTO "moz_places" VALUES(96,'','r00ted [r00ted]','moc.det00r.www.',1,0,0,10,100,1279220314450621);
INSERT INTO "moz_places" VALUES(97,'','flags.txt','moc.det00r.www.',1,0,1,11,2000,1279220457708086);
The last URL with flags.txt file seems interesting but it requires a username and a password (HTTP authentication).

No need to brute-force RootBSD's website, maybe the user has saved his username and password in his Firefox profile. Indeed Firefox (and Thunderbird, Sunbird...) has a signons.sqlite file (an SQLite version 3 database) containing all saved usernames and passwords with their corresponding base URL.

$ sqlite3 signons.sqlite
SQLite version 3.5.9
Enter ".help" for instructions
sqlite> .tables
moz_disabledHosts  moz_logins
sqlite> .dump moz_logins
CREATE TABLE moz_logins (id                 INTEGER PRIMARY KEY,hostname           TEXT NOT NULL,httpRealm          TEXT,formSubmitURL      TEXT,usernameField      TEXT NOT NULL,passwordField      TEXT NOT NULL,encryptedUsername  TEXT NOT NULL,encryptedPassword  TEXT NOT NULL,guid               TEXT,encType            INTEGER);
INSERT INTO "moz_logins" VALUES(1,'','Accès réservé aux amis',NULL,'','','MDIEEPgAAAAAAAAAAAAAAAAAAAEwFAYIKoZIhvcNAwcECG+PJbf7p3NqBAgelTlhXE0NMA==','MDoEEPgAAAAAAAAAAAAAAAAAAAEwFAYIKoZIhvcNAwcECFNhViAtgtLuBBBr2d66d+brfnCfVBwv7qw7','{6b6d81fa-34bd-4475-b51e-4a65ab075cdd}',1);
Sadly but as a very good practice, the user has protected its credentials with a master password. Hopefully, nagareshwar (@tnagareshwar) from (@securityxploded) has built an ultimate tool to recover lost Firefox master passwords, called FireMaster.

We will start with a small brute-force:
C:\>Firemaster.exe -b -m 1 -l 5 -c "abcdefghijklmnopqrstuvwxyz" 9tv5bckt.default
 * Congratulations !!! Your Master Password is Recovered Successfully
 Your Firefox Master password is : hack
Great! The master password is hack, we can now see the username & passwords thanks to another utility by the same author: FirePassword.

C:\>FirePassword.exe -m hack 9tv5bckt.default
 unknown     : kevin
 unknown     : hKza62qCSTgq
Great! We can how access the protected URL with username kevin and password hKza62qCSTgq and see:
Et encore un de plus : 4f88ae808c5cb93084bb4117b0452ca7
It says: and again one more 4f88ae808c5cb93084bb4117b0452ca7.

Flag 10: Download/trame.pcap, password-protected flags.rar

We open the capture in Wireshark, see an HTTP GET request to /downloads/flags.rar, and the response containing the file. As previously explained, we use right-click/export selected packet bytes to save the flags.rar.

We can see that the rar file contains a flags.jpg file, but the archive is password-protected: we first have to crack the password.

If you don't already have an archive password cracker/recovery, use rarcrack. It is slow, does not support advanced attack such as dictionary attacks, but it is free and it works:
$ rarcrack --type rar flags.rar
RarCrack! 0.2 by David Zoltan Kedves (

INFO: the specified archive type: rar
INFO: cracking flags.rar, status file: flags.rar.xml
GOOD: password cracked: 'biere'
By the way, if you know any good & free archive cracker, please let me know!

We extract the flags.jpg from the archive using password biere - beer in french - and see the flag on the picture: 203ec6cfbff8288c0ebeec8ea1e70144.


It was simple forensics, yet interesting tools have been showed - especially FireMaster & FirePassword. Also, the Google trick to diff the original file and the challenge one proved to be damn powerful! I think next time totally new files have to be created, or at least original files have to be a lot modified so that diff'ing will not help much.

We had fun during this small forensics challenge, and I hope there'll be others. Thank you RootBSD!


  1. Nice write up. I hope you had a nice evening !!

  2. Nice write-up.

    I put a link on my blog spot : m_101's write-up

  3. How did you recognize that this is a ceasar chipher at flag #2?

  4. The text is properly formatted, you try a substition cipher, bingo it's cesar.