Jeppe Ernst

#NC3CTF2017[2]["writeup - sector? what sector?!"]

The (Danish) National Police Cyber Crime Center (NC3) has created a four part advent CTF challenge this year. In a CTF you compete against the clock ⏱ to be the first to solve a series of challenges/riddles that involve different aspects of programming & forensics.

This is a writeup explaining how I solved the third challenge in this years advent CTF, This time I only managed to get the 13th best time, but it was great fun and I learned a lot of new stuff!

We were presented with the following text and two links, the first link was to a binary file “three.dd”, the second link was to a manual explaining the architecture of the filesystem.

Den 7. august 2017 vandt professor Kiwistone prisen “Fejl00”, der hvert år gives til udvikleren af årets mest håbløst forfejlede stykke software. Professoren vandt prisen for filsystem “FragFS”. Filsystemet udmærker sig negativt ved et væld af manglende funktioner og voldsomt fragmenteret data. Dette forhindrede dog ikke gerningsmanden B. Tarp i at bruge det til at gemme koden til en krypteret harddisk. Find koden(flaget), der er gemt i filsystemet, ved at bruge manualen udfærdiget af Kiwistone.

Download filsystemet - md5sum: 757282428a5b4cb348248afafaae3d88 Download manualen - md5sum: 37c728752566c5793eb421abc9be4995

(It’s basically the story of “professor Kiwistone” who won the award for the year’s most hopelessly flawed piece of software. He wrote the filesystem “FragFS”, a file system that lacked even the most basic stuff and was incredibly fragmented. But this didn’t prevent the perpetrator “B. Tarp” form hiding the code for an encrypted drive in a FragFS filesystem. Our job is to find the code (the flag) hidden in the filesystem by using the manual Kiwistone wrote.)

The manual is reproduced here in full:

FragFS

Et frygteligt fragmenteret filsystem


Synopsis

FragFS er et filsystem udviklet alene med det formål at give andre hovedpine. Filsystemet understøtter kun >små filer og diskstørrelser. Alt andet kan og vil gå galt.

Beskrivelse

FragFS benytter en sektor størrelse på 4096 bytes og har følgende overordnede struktur:

Version beskrivelse

De første 512 bytes angiver hvilken version af filsystemet der anvendes.

FilID og Filsti/Filnavn tabel

Starter ved byteoffset 512 ved start fra offset 0.
Hver entry indeholder en MD5 checksum(FilID) skabt ud fra filsti+filnavn.

FilID og Offset tabel

Følger direkte efter den foregående tabel.

Filsystemets indhold

Starter ved sectoroffset 20/byteoffset 81920 fra start offset 0.
Slutter når filsystemet får lyst til at slutte.

BUGS

Bunkevis. Brug spray eller DEET.


Af Professor Kenneth Kiwistone

From this we can extract the following variables that are going to be useful: sectorSize = 4096 and dataStart = sectorSize * 20 (I actually misunderstood the whole sector/data part the first time round, but we’ll get to that later)

This was the first time that I’ve been working with filesystems, so I needed to read up a bit before I could get anywhere with this challenge. I found a pretty good primer on the subject that got me started down the right path.

The first thing that I needed was to figure out how the different tables in the filesystem were seperated. For this I used the command xxd three.dd | less this gave me the file contents in three columns

Line number Hex ASCII
00002cb0: 2032 3039 3000 ff36 3833 3036 3637 3132 2090..683066712
00002cc0: 3037 3764 3438 3139 3535 6632 6461 3539 077d481955f2da59

We know that the two filetables are in the sectors 0 through 19, everything from sector 20 and onward is the filedata.

sector overview no-border full-width

But we need to figure out how the tables are structured and where the first table [FileID and Filepath/Filename] stops and the second table [FileID and Offsets] starts. We start by inspecting the data from sector 0 (but we ignore the first 512 bytes, as they’re just the filesystem version info).

sector overview no-border w100

We know that the table starts with an MD5 hash of the Filepath + Filename, MD5 hashes are always 32 characters in length. Looking at the table above we can see that immediately after the first 32 chars, there is a 0x00 value, to the right of that value we can see the Filepath + Filename, let’s call it the “column” seperator. Next we’re hitting a 0x00 again but this time it’s followed by 2 0xFF values. Combined they give us 0x00 0xFF 0xFF this is a new set of seperators that mark the “rows” in the table. If we try to visualize it we get something that looks like this:

MD5 Filename + Filepath
31f84df100b0c302c05f39c6e42deeb2 filsystem/docs/stack_smashing.pdf
683066712077d481955f2da59222e9d6 filsystem/gits/gef/docs/commands/memory.md

Great we’ve got the first table down! One more to go! So we keep scrolling through the the xxd output until we hit something that looks fresh :tomato:

sector overview no-border w100

Line 6832 is where it’s at! The output suddenly changes and “Huzzah!” now we’ve found the second table! and we’re in luck, there’s a new seperator! 0x00 0xFF 0xFF 0x00 0xFF 0x00 so now we know where both tables start and stop!

The first starts at offset 512 and ends when we encounter a 0x00 0xFF 0xFF 0x00 0xFF 0x00. The second table then start immediately after that and ends at sector 20 or offset 81920. Now let’s take a closer look and see if we can figure out how the second table [FileID and Offsets] should be read:

sector overview no-border w100

This table is supposed to consist of the FileID (the MD5 from the first table) and a list of offsets specifying where the different parts of the file are stored. Here we find a new seperator 0x00 0xFF this is the “row” seperator for the second table. In the second table 0x00 is once again used as the “column” seperator. But the offsets are also seperated by a hex value 0x20 or simply a “ “ space char. If we visualize the second table we get:

MD5 Offsets
31f84df100b0c302c05f39c6e42deeb2 1002 1737 1560 1405 1272 1098 981 1597 1698 1943 1071 1386 590 1199 351 1176 1963 2104 1473 1557 1180 1659 1247 332 888 2093 1160 1771 1673 379 660 1697 804 1291 1023 2069 655 2131 437 1317 1076 1852 222 2166 1788 1871 847 329 1559 2193 328 2061 666 1024 1439 2075 489 766 1114 1381 2126 1613 1844 1621 986 1107 806 1564 884 1912 2182 980 1980 1638 1812 393 1712 1555 2059 706 733 875 1964 1685 1875 1786 1210 520 1989 1543 1683 1276 1064 299 1352 1566 1263 1243 1073 2090
683066712077d481955f2da59222e9d6 2036

Now we’ve got everything we need to “carve” :knife: the files out the “three.dd” file. So I wrote a python script that would generate the files on my own harddrive, by reading the two tables and joining them on the FileID, then assembling the files from the offsets. The script ran and everything was peachy :peach:

That is until I tried to open one of the files and it was total garbage 🗑. The pdf file on “stack smashing”? it was filled with random python code intermingled with binary data. Not good… Fortunately for me I knew that autosolver was also doing the challenge so I hit him up on <messenger app>, and it turns out that I (as I mentioned earlier) had misunderstood the part about the sector offsets. I thought that sector 0 would be placed at offset 81920, when infact sector 0 was at offset 0 😱. A GREAT BIG THANK YOU TO autosolver :clap:

Fixing that mistake, and running the script again gave me all the files… with the proper content this time :+1: quickly trawling through the files I found the flag in an image file.

⏱ Total time: 2 hours 23 minutes and 47 seconds

Almost forgot the script (⚠️ ugly code!):

TL;DR: It was a super fun challenge, I made a stupid mistake but I learned a lot. It was also my first time using Pythons bytearrays… they’re pretty pretty smart! And a big thank you to autosolver :+1: