Brandon T. Elliott
CTF Writeup: Space Heroes CTF - "Conspiracy Nut"
The CTF
Space Heroes CTF took place from April 21, 2023 to April 23, 2023 and was built by FITSEC @ Florida Tech.
The Challenge
This forensics challenge began with the following description and a file conspiracy_nut.tar.gz
to download and analyze:
Something about the description of this challenge captivated me and it was definitely the most difficult challenge that I managed to solve during Space Heroes CTF.
It forced me to learn quite a bit about doing forensics on memory dumps, so with that being said, this writeup will partially go over the rabbit holes I went down (the worthwhile ones at least), as well as how I solved the challenge during the CTF, and an additional way I found to solve the challenge after the fact.
The Memory Dump
After extracting the contents of conspiracy_nut.tar.gz
we are left with a single file conspiracy_nut.dump
which is the memory dump we will analyze.
Admittedly, before I ended up approaching the challenge in a more sensible way, I initially ran binwalk
on it with limited success, attempted to extract strings from it with strings
, and even attempted to extract things like .png .jpg .bmp .gif .pdf .txt
, etc. files from it manually using custom python scripts. Although I did garner a little bit of info from all of this, ultimately I wasted several hours only to realize that I needed to find the right tool for the job if I were going to have any amount of success with solving the challenge.
A little google-fu and struggling to install python dependencies later, and volatility
ended up being exactly the tool I needed.
Volatility
Specifically, I ended up using volatility3 which is an amazing tool for analyzing memory dumps.
While I wasn’t successful overall with my prior approaches to the challenge, I did however manage to see that there was a flag.jpg
file that was potentially downloaded during my analysis with strings
.
Therefore, a good starting point will be to find .jpg
files in the memory dump with something like the following:
vol -f conspiracy_nut.dump windows.filescan.FileScan | grep 'jpg'
After running this, we see that some Sample Pictures are included in the results, so with those removed:
┌──(kali㉿kali)-[~/conspiracy_nut]
└─$ vol -f conspiracy_nut.dump windows.filescan.FileScan | grep 'jpg' | grep -v 'Sample'
0x17eeb9ae0 \Users\tinfoil\AppData\Roaming\Microsoft\Windows\Themes\TranscodedWallpaper.jpg
0x17eec5670 \Users\tinfoil\Desktop\IMG_2930.jpgpg
0x17f0d42b0 \Users\tinfoil\Downloads\Patterson–Gimlin_film_frame_352.jpg
0x17fb704b0 \Users\tinfoil\AppData\Roaming\Microsoft\Windows\Themes\TranscodedWallpaper.jpg
0x17fc26ad0 \Users\tinfoil\Downloads\20230213_212116.jpg
0x17fd59070 \Users\tinfoil\AppData\Local\Mozilla\Firefox\Profiles\iosz5xuz.default-release\settings\main\quicksuggest\icon-160380814674521.jpg
This leaves us with some initial things to look at, although unfortunately we don’t see the aforementioned flag.jpg
.
We can extract specific files with a command similar to the following, specifying the address of the file from the left column:
vol -f conspiracy_nut.dump windows.dumpfiles.DumpFiles --physaddr 0x17fc26ad0
This, for example, would extract the photo \Users\tinfoil\Downloads\20230213_212116.jpg
(which by the way, ended up being this picture of two cats):
Interestingly, I used this same technique on \Users\tinfoil\Desktop\IMG_2930.jpgpg
and \Users\tinfoil\Downloads\Patterson–Gimlin_film_frame_352.jpg
as well but the data extracted didn’t appear to be valid images, but instead contained what looked like zone transfer information from the same IP I saw in my earlier analysis which flag.jpg
was downloaded from? Kind of strange…
Downloads
Using the same filescan technique as before, I turned my focus to discovering what else was in the tinfoil
user’s Downloads
folder:
┌──(kali㉿kali)-[~/conspiracy_nut]
└─$ vol -f conspiracy_nut.dump windows.filescan.FileScan | grep 'tinfoil' | grep 'Downloads'
0x17ece7cb0 \Users\tinfoil\Links\Downloads.lnk
0x17ef2a4d0 \Users\tinfoil\Downloads\220517-ufo-mjf-0953-5ad8c4.webp
0x17ef49d40 \Users\tinfoil\Downloads
0x17f0d42b0 \Users\tinfoil\Downloads\Patterson–Gimlin_film_frame_352.jpg
0x17f6596c0 \Users\tinfoil\Downloads\Firefox Installer.exe
0x17fada070 \Users\tinfoil\Downloads\virtio-win-guest-tools.exe
0x17fb17f20 \Users\tinfoil\Downloads
0x17fc26ad0 \Users\tinfoil\Downloads\20230213_212116.jpg
0x17fdc1840 \Users\tinfoil\Downloads\desktop.ini
The 220517-ufo-mjf-0953-5ad8c4.webp
file ultimately ended up being similar to the zone transfer thing as described before.
The other file which piqued my interest here was the Firefox Installer.exe
.
Clearly this meant that Firefox was used to download these images…
Firefox
A little bit of google-fu informed me that a user’s Firefox browsing history is stored in a places.sqlite
database.
Therefore, we will find this file and extract it from the memory dump:
┌──(kali㉿kali)-[~/conspiracy_nut]
└─$ vol -f conspiracy_nut.dump windows.filescan.FileScan | grep 'places.sqlite'
0x17f01f650 \Users\tinfoil\AppData\Roaming\Mozilla\Firefox\Profiles\iosz5xuz.default-release\places.sqlite-wal
0x17f2c7ca0 \Users\tinfoil\AppData\Roaming\Mozilla\Firefox\Profiles\iosz5xuz.default-release\places.sqlite-wal
0x17fc5ac10 \Users\tinfoil\AppData\Roaming\Mozilla\Firefox\Profiles\iosz5xuz.default-release\places.sqlite-wal
0x17fc91d00 \Users\tinfoil\AppData\Roaming\Mozilla\Firefox\Profiles\iosz5xuz.default-release\places.sqlite
0x17fc95120 \Users\tinfoil\AppData\Roaming\Mozilla\Firefox\Profiles\iosz5xuz.default-release\places.sqlite-wal
0x17fc97a20 \Users\tinfoil\AppData\Roaming\Mozilla\Firefox\Profiles\iosz5xuz.default-release\places.sqlite-shm
0x17fc98dc0 \Users\tinfoil\AppData\Roaming\Mozilla\Firefox\Profiles\iosz5xuz.default-release\places.sqlite
0x17fd23c00 \Users\tinfoil\AppData\Roaming\Mozilla\Firefox\Profiles\iosz5xuz.default-release\places.sqlite
0x17fdaaea0 \Users\tinfoil\AppData\Roaming\Mozilla\Firefox\Profiles\iosz5xuz.default-release\places.sqlite
After extracting the places.sqlite
file located at address 0x17fc91d00
, we can now open up the database using sqlitebrowser
which should allow us to look at the browsing history of the tinfoil
user.
After browsing to the moz_places
table, we see the following (with the IP of the server the files were downloaded from having been redacted by me):
It appears that the user browsed to some cat related xkcd comics, which was somewhat interesting given the cats picture discovered earlier, but ultimately this didn’t end up being of any use to me.
It also appears that the flag.jpg
image was visited, and my next thought after seeing this was that maybe the image was cached. This thought led me down a rabbit hole of extracting everything from the user’s Firefox cache, which to summarize succinctly: although it did contain some cached images and other bits of data, there wasn’t anything that ultimately seemed relevant to the challenge. Therefore, I will spare the remaining details of this Firefox “rabbit hole” for now…
Wallpaper
You may have noticed in my earlier assessment of the .jpg
files located in the memory dump, that there was one in particular that I didn’t extract or look at initially, and that was TranscodedWallpaper.jpg
.
However, after going down the previous rabbit holes and getting stuck, I did end up wrapping back and taking a look at it, thinking (hoping) that maybe the flag.jpg
was set as the user’s wallpaper at some point.
After extracting the file with volatility
, I ended up with a mostly corrupted image which looked like this:
Luckily, the “Potentially Flat?” part I could see written on the top of the whiteboard strongly made me suspect that this image contained the flag, however it appeared like I would need to fix the corruption in the image data in order to obtain it.
JPEG Corruption
Disclaimer: I am NOT an expert on fixing corrupted images, please don't use this info to try to recover your own images. You do so at your own risk.
Doing some research on JPEG corruption, I learned that if an image is cut off and the rest is filled in with grey, it’s likely that this image data is recoverable.
This can be caused by something as simple as the bytes ff d9
being placed in the image data prematurely, as these bytes ultimately signal that it’s the end of the image data.
Opening TranscodedWallpaper.jpg
up with a hex editor, we see that this is indeed the case with this extracted file.
At address 0x00025A15
we see a premature ff d9
that is followed by 4,073 null bytes:
After deleting all of the aforementioned bytes and exporting the new file, we now have a slightly improved, but still corrupted, image:
At this point, I could see enough to know that the flag is indeed written on the whiteboard in the bottom left of the image, however it was not nearly clear enough to be able to capture it.
Although I did make several attempts to fix the corruption in a way that would properly recover the entire image, being pressed for time, and admittedly not being knowledgeable enough in this area (see previous disclaimer), I then turned to deleting chunks of bytes in areas of the hex where I thought the corruption may exist.
Knowing that the flag was contained in a relatively small portion of the image, I knew that I could delete a substantial part of the image data and still recover the flag.
For example, deleting the bytes from 0x00010000
to 0x000764FF
resulted in this image (with an additional edit afterwards in order to redact the flag):
It is worth mentioning that from conversation that took place after the CTF was finished, one person did mention this exact methodology of extracting the TranscodedWallpaper.jpg
as being their solution, however they didn’t mention any issue about the image being corrupted, so I’m not quite sure why it was for me, but it did seem like I was using a different version of volatility
, so I’m going to look into that further, but for now, I don’t have a reasonable explanation.
Update - 4/26/2023: I went back and tested it with the original version of volatility
instead of volatility3
and the original version was able to extract TranscodedWallpaper.jpg
much better, so if I hadn’t have tried to use the latest and greatest, I could have avoided the fixing the corruption part altogether.
It also became apparent to me after the fact that there were multiple ways you could have obtained the flag, and thus, I needed to backtrack to the Firefox “rabbit hole” in order to further my learning.
A Short Intermission
What makes some CTF challenges (and other challenges for that matter) cause you to question your ability and entire existence as a human being is that your line of thinking can sometimes be 100% correct, but you just miss the thing. This can lead to frustration, but also this is the part where you have an opportunity to learn, which is an amazing thing, and the most enjoyable part for me, personally.
Firefox - continued…
With that being said, my line of thinking with Firefox was correct, but the thing that I missed was that the image may be contained somewhere in the memory dump of (one of) the running Firefox processes.
So, the first step for another way to solve the challenge would be to first list all of the running Firefox processes in the memory dump like so:
┌──(kali㉿kali)-[~/conspiracy_nut]
└─$ vol -f conspiracy_nut.dump windows.pslist.PsList | grep 'firefox'
1936 1928 firefox.exe 0xfa800574d060
2404 1936 firefox.exe 0xfa8004a29b30
1344 1936 firefox.exe 0xfa800514da30
2772 1936 firefox.exe 0xfa8004c30060
1608 1936 firefox.exe 0xfa8004ca9310
800 1936 firefox.exe 0xfa8004d4f060
2532 1936 firefox.exe 0xfa8004ddb060
880 1936 firefox.exe 0xfa8004def920
2332 1936 firefox.exe 0xfa8004d495f0
1964 1936 firefox.exe 0xfa8004d14060
3128 1936 firefox.exe 0xfa8004cd9b30
3240 1936 firefox.exe 0xfa8004ce4ab0
This gives us a total of 12 different Firefox processes that we can dump with volatility’s memmap
plugin using the PID from the left column. Since there are 12 of them and doing it one by one may be quite annoying, I will go ahead and create a bash script to do the remaining portion of the analysis, as this will likely come in handy in the future as well.
The bash script I created above will automate the redundant actions of grabbing all 12 of the PIDs of the Firefox processes, dumping all of the memory from these PIDs, and subsequently using foremost
to extract the file types we want from them (in this case, we know we want .jpg
).
After running the script, we are left with a directory of all of the extracted .jpg
files from all of the Firefox processes:
This ended up containing all of the images that I previously found in the Firefox cache, and even several more, as well as the flag.jpg
image, which ended up being a quite humorous parody of a “conspiracy nut”, with the flag being written on a flag on the moon: