TL;DR: Week 9 of the #MagnetWeeklyCTF began a new case, this one involving a memory image.
Check out the week 1 blog post for how to get started on the Magnet Weekly CTF.
Get the first challenge
The weekly challenge for week 9 was split into seven parts! The first was:
The user had a conversation with themselves about changing their password. What was the password they were contemplating changing too. Provide the answer as a text string.
The absolute scariest thing to me about memory forensics is that you realize just how much of what we think of as “secure” is absolutely not. Passwords are no exception, especially when you are “chatting with yourself”. Since I did not yet have Volatility installed, I resorted to the good old standby:
The first command runs
strings on our memory dump, then pipes that to
grep looking for a case insensitive (
-i) instance of the word “password”, and finally pipes that output to
grep looking for a case insensitive instance of the word “change”. Turns out, we have a hit, which thrilled me as I didn’t want to have to sift through all of the strings output. Normally, I would expect
strings to return the next line in the file immediately after this line, but since I used
grep twice, I ripped the line from its context and had to go back to get it. Thankfully, the string that returned has a typo in it (“mmaybe”), which should make for a quick grep.
The second command is running
strings on the same file, then piping the result to
grep looking for a case insensitive instance of the word “mmaybe” and returning the next three lines (
-A 3) to get it in context. The result shows our answer: “wow_this_is_an_uncrackable_password”
Get the second challenge
The second challenge was:
What is the md5 hash of the file which you recovered the password from?
I have a bit of a complaint about this question because the right answer should be “224f93209cbea29e862890f30dfa762d” which is the
memdump.mem. Since that is the file which contains all of this, it should be correct.
Assuming Magnet was being coy in the question, I decided to refresh my memory of
volatility. This is my go to memory tool, since it works nicely from the command line and is free/open source. After cloning the repository from Github, I started exploring what the right starting point was. Initially, I remembered I needed to have the right profile to get volatility to play nice, so I started with
Volatility’s first guess as to what to use for the profile was
Win7SP1x64 so I used that for the rest of the challenge.
Since we are looking for a file, I decided to do this the hard way and just dumped all the files out using
dumpfiles, making sure to include the file name in the exported file name (
--name), then grepped for the answer to see which had it.
The dumped file in question (
file.3180.0xfffffa803316f710.AutoRecovery save of Document1.asd.dat) is a Microsoft Word document, and had an MD5 hash of
af1c3038dca8c7387e47226b88ea6e23. That MD5 hash is the right answer.
Get the third challenge
The third challenge was:
What is the birth object ID for the file which contained the password?
To find the birth object ID, you need to dig into the NTFS information for the file. To get that information, we’ll look at the Master File Table (MFT), which is serviced by volatility’s
In this case, I saved the
mftparser output as a text file, then used
cat to send the output to
grep, looking for three different lines. I matched on anything that said “MFT entry found”, the extension “.asd”, or “Birth Object ID”. I then piped that further into
grep to give me one line before (
-B 1) and after (
-A 1), but only for the line with “.asd”.
grep would hit for every file and groom volatilty’s output down from a lot of extra things, to just the line giving the MFT Entry offset, and the Birth object ID, or a filename with “.asd” in it. The second
grep then goes through that groomed output and finds the one file with “.asd”, so we know the line before and after is its information. In this case, the birth object listed (“31013058-7f31-01c8-6b08-210191061101”) is the correct answer.
Get the fourth challenge
The fourth challenge was:
What is the name of the user and their unique identifier which you can attribute the creation of the file document to? Format: #### (Name)
The volatility plugin to find the security IDs of the users for each process is
getsids. As I had previously identified process 3180 as the process for WINWORD, this was a quick one.
The only user account using this program is “Warren”. His security ID is “S-1-5-21-4288132831-552422005-3632184702-1000”, but they specify the format to be “XXXX”, hence the right answer is just “1000”.
Get the fifth challenge
The fifth challenge was:
What is the version of software used to create the file containing the password?
In this case, I only used volatility’s
procdump plugin to drop the executable to disk, then used
pe-tree to read the information.
pe-tree will bring up a GUI and in the VS_VERSION section, you’ll see that the version is “15.0.5233.1000”. After submitting that, and having it not be right, I played around to discover Magnet only wanted the major version (“15”). That is the correct answer.
Get the sixth challenge
The sixth challenge was:
What is the virtual memory address offset where the password string is located in the memory image?
This question is where things went a bit sideways. The question hinges on the mapping between physical offsets in the actual file and the virtual offset that it represents. Or to reword it, where to find each bit of the memory we imaged in the file we saved it in. Volatility’s
memmap plugin will show you that mapping between the virtual and physical nicely, as long as you know where it is you want to look.
To find out where to look, we’re using
strings and telling it to display the output of where it finds the string in hex (
-tx). This says that in the dump file, our target string starts at
0xaf12a2d. Once we know the rough physical address, we can look at the
memmap for the WINWORD process (
-p 3180) and
grep for the beginning of the address. We don’t want to look for the entire address because memory is allocated in blocks and I’d looked earlier to see it was probably a block of 1000 (in hex).
We have two decisions from this output, in the first line you can see that virtual address 0x2180000 is mapped to physical address 0xaf12000. In the second line, virtual address 0xaf12000 is mapped to physical address 0xac6d9000. Because we saw the string at physical address 0xaf12a2d, we want the first answer. We can then take the last three digits of the string address and add it to our base address to get the answer: 0x2180a2d. We can do this because we’re just comparing the offset from the start of the block, whether physical or virtual. Since we are another 0xa2d into the physical block, we’ll be another 0xa2d into the virtual block.
The problem is…. that wasn’t the right answer. I tried it in hex, I tried it in octal, I tried it in decimal. I tried the physical address, I tried all of the above with all the 0’s on front as well, and with and without the “0x”. None of it worked. Finally, I hit up Jessica Hyde to ask if, maybe, the answer was wrong. Thankfully, after she dug in, she realized there was a single leading 0 on the answer, making the “correct” answer actually “0x02180a2d”.
I was very happy after the answer was fixed to allow the version without a leading 0 and greatly appreciate her digging into the issue as quickly as she did.
Get the seventh challenge
The seventh challenge was:
What is the physical memory address offset where the password string is located in the memory image?
We had to answer this question to answer the previous question. The answer was “0xaf12a2d”.
Volatility is an excellent free, open source tool for memory analysis, if you haven’t checked it out, you should. This week was a really good reminder of some memory analysis basics and a Windows refresher after a month of Android and a month of Linux, two OS’s I am much more comfortable with.