Brief notes on some of the Flare-On 2020 challenges
This was my first flare-on and it was quite fun. I ended up procrastinating for a few weeks after finishing challenge 10 so the end result was not quite what was desired. So here are my thoughts on challenges that I consider to be interesting, which mainly focuses on challenge 9 and 10. As the official writeup will come out soon and will no doubt be far better than my writeup, I’ll likely not edit it too much.
Challenge 6
This was a frustrating challenge that took me 11.5 hours (mostly spent figuring out non-solutions) to solve. The binary is a QR code generator written in AutoIt. I initially expected this to be easy since AutoIt was my home turf (however out of practice I might be), however, this proved not to be the case. The deobfuscation was fun and easy to write as the obfuscation is extremely simple. However the final part took far too long, it took me around 8 hours to figure out that the decryption function was collecting bits and combining them into bytes 7 at a time to generate the desired password.
Challenge 7
This is by far my favorite challenge. In short, we have a pcap file of a network attack against an IIS server exploiting CVE-2017-7269. After identifying the exploit, the first step was to extract the shellcode. Initially, I could not get it working, but then after reading an article on the exploit that shows the disassembly of what’s going on behind the scene, I realized that the shellcode is to be converted to wide strings, and after that things were fairly simple. We had to fix up the register in a debugger (I believe ESI was to point to the beginning of the buffer), and then debug and then continuously dump the next stages until we get the flag data.
Challenge 8
I dislike this challenge. The flag was a gibberish string unlike the other challenges so I spent hours that I shouldn’t have. If not for that it would’ve been quite fun. My solution was dumping the ELF binary, patching it so that the check always returns ‘X’, repackage it in the resource and then run it.
Challenge 9
This challenge was fun. The challenge file is a PE file which does 2 things: load a driver using CapCom, and registers a COM DLL.
The manual mapper is written by the author and can be found here. The main difference between the public implementation and the private one is simply some slight obfuscation and the change in the pooltag. The mapped driver registers a registry callback.
Knowing that a driver is in play, I applied one of my techniques for dynamic analysis here that I have not seen discussed anywhere else (though I am sure it has been done by many before). The technique in essence is hooking the free function and dumping the buffer content before freeing. This allows us to see a lot of interesting information in binaries simply by running it without the need for debugging or anything else. In this case, as the target is a kernel driver, I used a hypervisor to hook ExFreePoolWithTag and dump the pool if the caller is not a valid target driver image. This gave us a very interesting string, “H@n.$h0t.FiRst!”, which will later be used. Now, onto static analysis, we can see that the driver registers a registry callback.
Inside it, it checks if the registry key operation is on the COM key “{CEEACC6E-CCB2-4C4F-BCF6-D2176037A9A7}\Config”, and if it matches that, the key is created with the class set to “H@n.$Sh0t.FiRst!”. This confirms that what we extracted earlier from our hypervisor is indeed some sort of password that will be important later on.
Onto the COM DLL that is registered, we can see that it first clears the Password and Flag field inside DllRegisterServer.
This activates the registry callback described before. Next, we can see that DllGetClassObject returns to us an object with a vtable, as is typically the case with COM APIs.
Outside of the standard functions, we can see that there is a custom function which gives us another vtable
This final vtable contains two functions, one which reads the password from the “Password” key and another which decrypted a buffer with it and writes the result to the Flag key. As a result, I LoadLibrary-d and called the functions in the COM DLL to get the password. I originally planned to write a full COM client however I decided to take the more lazy route as it works just fine.
Bugs in the challenge
This challenge had several bugs in it. The first of which is that it does not work on multi-core systems due to CapCom being used in an unsafe manner, thus we have to change our VM to be single-cored.
The second bug lies in the password decryption function. Do you see the bug?
That’s right, the variable pcbData was not initialized. The documentation for RegGetValueW states that the last parameter is a “pointer to a variable that specifies the size of the buffer pointed to by the pvData parameter, in bytes”, however in this case pcbData is not initialized and as such contains a gibberish value. In some cases, we might be fortunate enough that it contains a value that is higher than the size of the registry key and as such the read is successful, however, this is not guaranteed, as the value could be zero and the read could as such fail completely.
Challenge 10
Kudos to whoever made this challenge because it was absolutely painful and fun to work with.
A brief overview of the sample, it is essentially Armadillo but on Linux, it employs the same kind of nanomite-based obfuscation using ptrace and fork. There are two main techniques that I applied for reversing the file: static analysis and LD_PRELOAD hooking. As we cannot perform regular debugging due to the presence of nanomites, I applied the same technique discussed above to dump buffers that are passed into various functions. For reasons unknown, my dlsym hook (which was required for hooking ptrace as the function was dynamically resolved) did not work on Debian, however it worked perfectly on Ubuntu. I’ll publish the code within a few days.
When we look at the main() function, it appears deceptively simple.
However, when we input the string as a flag, the binary tells us that it stole our flag. What’s going on?
Using the technique of LD_PRELOAD hooking, I intercepted various functions such as memcmp, strcmp, as well as logged calls to ptrace() to extract information about what the binary is doing. One call to memcmp in the log stands out:
Well, if that doesn’t look like a part of the flag! What would happen when we enter it into the binary? As it turns out, the binary now consumes the entire CPU core for around 10 minutes or so before telling us that our password is wrong instead of telling us so immediately. So, we’ve likely done something right.
Further static analysis reveals a function that runs before main() which forks and initializes the first nanomite.
The nanomite debugger function then uses ptrace(PTRACE_POKEDATA) to write the UD2 instruction to the sunshine check that we first saw in
When the #UD is eventually raised, execution is redirected to the real password check function.
The function is as follows.
It’s passing rm -rf –no-preserve-root / into execve? What’s going on? As it turns out, ptrace on Linux allows for the interception of syscalls and that is exactly what’s going on here. Various syscalls are intercepted by the nanomite debugger, which then does certain operations depending on the syscall ID in EAX. The syscall ID is XORed with 0xDEADBEEF and multiplied with 0x1337CAFE resulting in the final nanomite operation ID. The IDs, their syscall, and the operations that it does is listed below.
In this case, execve simply removes the new line character at the end of a string, and nice decrypts a string from a table and writes it into the debuggee.
This is then passed into memcmp in the real password check function we’ve seen above. And voila, we have verified that what we obtained earlier is in fact the first part of the flag.
After this, we enter the function that I’ve named “stringhash_teaenc”. This function is the reason why the binary takes forever to run, as it employs not just 1 but 2 layers of nanomite to obfuscate it’s encryption algorithm.
As we can see, it gets a string using nice() and hashes it with crc64. This is then used as the decryption key to decrypt a buffer, which’s initial 20 bytes have been overwritten with the password. The entire buffer decrypts fine except for the first 20 bytes which are invalid as we do not have the password. The rest contains the entire Bee Movie script with a weird binary blob in the middle, which we will revisit later. The tea decryption functions are as follow.
There are several things going on here:
- The uname, pivot_root, chmod and mlockall syscalls are handled by the nanomite 1 debugger. The first 2, uname and pivot_root are simple and their operation can be easily seen in the comments above. The other 2 are more complicated. As we can see below, the mlockall handler tries to call the variable call_nanomite2. This was previously initialized to 0. The result is a SIGSEGV, which is then handled by the second nanomite debugger that we saw created earlier.
In this case, the operation simply set eax to the second parameter + 1.
The chmod call was similar, however in this case it does multiple operations, not just 1.
- As we can see, there are multiple calls to 0 inside the tea decrypt function. This is handled similarly to the way the first nanomite debugger called the second nanomite debugger, however the operation in question is a loop.
In essence, null_call(&loop_start_address, &counter) will loop the counter from 0 to 15 and then returns.
Summing this up, we have enough information to begin implementing a non-obfuscated version of the encryption function. We can identify that it is a TEA-like algorithm based on the constant we retrieved (0x9e3779b9c6ef3720), and the key to the function is the CRC64 hash of a string, which is 0x674a1dea4b695809. Reversing the algorithm, we can decrypt the next part of the flag, which was located in the first 20 bytes of the buffer we saw earlier. We got “4nD_0f_De4th_4nd_d3strUct1oN_4nd”, which makes it “w3lc0mE_t0-Th3_l4nD_0f_De4th_4nd_d3strUct1oN_4nd”.
Recall the buffer I mentioned that was stuck in the middle of the Bee Movie script? That turns out to be a shellcode that does quite a lot of math. It’s not actually called, but reversing it will reveal the final part of the flag. The function in question uses a bignum library to do some calculation based on some data in the binary.
The first problem we have to solve is passing the first check involving bignum_03 and bignum_09. A simplified version of the function stripping out everything that’s irrelevant is as follow:
To pass the equality check, bignum_04 ^ bignum_rand mod bignum_01 must be equal to bignum_03. And as we can see, bignum_04 and bignum_03 are both the same value, and is less than bignum_01. This means that bignum_04 mod bignum_01 == bignum_04, and as such the bignum_rnd value should be 1 to ensure the equality.
The operation in question is essentially
math_powmod_naive(&bignum_02, &bignum_rnd, &bignum_01_p, &bignum_06);
math_divmod(&bignum_rnd, &bignum_01, &bignum_11, &bignum_08);
math_powmod_naive(&bignum_02, &bignum_rnd, &bignum_01, &bignum_06);
math_powmod_naive(&bignum_04, &bignum_rnd, &bignum_01, &bignum_09);
math_mul(&bignum_07, &bignum_06, &bignum_rnd);
math_divmod(&bignum_rnd, &bignum_01, &bignum_11, &bignum_10);
if (bignum_05 == bignum_10)
bignum_06 = bignum_02 ^ (bignum_rnd % bignum_01)
bignum_11 = bignum_rnd / bignum_01 // 1/bignum_01
bignum_08 = bignum_rnd % bignum_01 // 1
bignum_rnd = bignum_06 * bignum_07
bignum_06 = bignum_02 ^ (bignum_rnd % bignum_01)
bignum_09 = bignum_04 ^ (bignum_rnd % bignum_01)
bignum_11 = bignum_rnd / bignum_01
bignum_10 = bignum_rnd % bignum_01
Here, one of the images that was decrypted earlier in the binary gives us a hint as to how to solve the next part. This stackoverflow page might also be helpful.
As this part was solved with the help of someone who’s better at math than me, I’ll avoid inadequately explaining it and simply not explain it at all. You can check the official writeup for a detailed explanation when it comes out. Anyhow, solving it, we obtain the last part of the flag, “_n0_puppi3s@flare-on.com”.
Challenge 11
Challenge 11 is an DFIR challenge where we analyze the registry dump of an user infected with a Gozi-ISFB malware variant. It does not feature anything difficult like challenge 10, rather it is mostly tedious due to the huge amount of things to look through. Hasherezade’s tools were extremely helpful (though it didn’t support 64-bit binaries properly and I had to add that myself). Diaphora was also extremely helpful.
The startup of the malware was interesting and is one I have not seen before. It uses a GroupPolicy Logon Script to execute the powershell script that was stored inside another registry key. The string decodes to “iex (gp ‘HKCU:\SOFTWARE\Timerpro’).D”.
I couldn’t get Autoruns to work properly on the hive, so I initially did not find this, rather, I found the script stored inside TimerPro directly.