“Corona Virus” — RE Challenge Writeup
After an inevitable long break from CTFs, I had the chance to participate with my team in the Insomni’hack 2022 Teaser CTF.
This challenge is a great way for people to learn about process hollowing while reversing it in action and also get some mileage with highly obfuscated code.
In addition, I used Lumina and Lumen in a pretty smart way to save sometime and I will elaborate about it in this write-up. This write-up can also come in handy for researches that want to see some practical use of Lumina and Lumen.
If you think you are down for the challenge, I suggest you to stop right here and head to Insomni’hack Teaser website.
If you want to learn from reading, or you tried this challenge and want to get some hints — Dive in with me.
The challenge comes as an encrypted zip file with a malware. The first thing that pops when decrypting this malware is a yara signature of mimikatz. As there was no clear sign of mimikatz, it was a tricky question to understand what made the jump but Lumina helped clear this issue, which I am not going to spoil right ahead in the intro — but we’ll get there soon ;)
In addition, PEstudio resolved that the file has an executable resource. This resource though was a legit checkaccess executable.
The file was also split to sections and the entry point was in a section named “elite”:
apart from regular code in that section, the text section looked like another different unrelated malware. But more on that later.
Part 1 — Hollower
Understanding the methodology
First thing first — Used Lumina to cover some code fast and with no over load.
Lumina & Lumen:
IDA: Lumina server
The Lumina server is currently very simple: it holds metadata (function names, prototypes, comments, operand types, and…
Lumina is basically a collaborative server by hex-rays that all researches can push metadata and pull metadata about functions in order to make reversing a bit easier and collaborated.
Alternative Lumina server for IDA Pro - Allows users to pull function metadata from function signatures
Lumen is just a private server and surprisingly, it works great.
Using the combination of both I unraveled about 1200 functions before even starting to invetigate the malware.
While going over some functions I saw a suspicious malware fully written including a start address and a main — in the text section:
The malware never gets here and actually, turns out that the authors of this challenge inserted this code just to make it jump on yaras so no one unrelated to cyber world that accidently stumbles opon this challenge would accidently run it. Thank you Lumina&Lumen, I would have wasted way to much time over this without it.
Analyzing the “elite” flow
It’s pretty clear that the code is meant to be PIE. It gets the functions it imports straight from the IAT using the “get_function_from_stackstring”. In addition it has the function which I called “xor_name_woth_sbox_index” which takes a string and a “sbox” and xors all the values in the xbox with the string and saves the result in the sbox.
Further research approves that this “sbox” is actually the next stager waiting to be decrypted with the computer name as the key. It is a PE. we can see it in the “do_with_res” function, where it looks for the values MZ in the start of the code:
Decrypting the payload (PE)
At this part, curiosity killed me and I had to decrypt this payload. My intuition led me to think that if it’s a PE, There should be a place filled with nullbytes. Meaning I would see the computer name Instantly:
From this point, revealing the start of the computer was as easy as xoring M with the first sbox value (0x00) and Z with the second, revealing the computer name: MOI_S1KRIT_KOMP
Hollowing the malicious PE
Reversing is basically just working by the hunch, and my hunch told me this executable is going to get hollowed. But hunches are hypothesises and a hypothesis has to be proved. so I kept on investigating the hollower more for a couple of minutes and saw the following flow:
This loop here is pretty much the bread and butter of process hollowing. If you are not familiar with the concept, I suggest this amazing blog about it:
Analyzing Malware Hollow Processes
The Malware Analyst's Cookbook is a great book. In it the authors talked about an interesting technique they called…
Just like the blog mentioned, before the writeprocess memory loop — we had a process creation (duplicate of the hollower) and unmapping of the memory.
Part 2 — Main Stager
Now that my hypothesis was proven correctly, I was eager to start analyzing the core of the main stager that was hollowed. Unfortunately, this is what I saw:
As it is unclear of how bummed I was to see this, I will try explaining it with a picture of the first few lines of code:
After a couple of head-banging-table it was pretty clear to me that 92% of the code in this flow graph is just garbage, including the “calc_for_rax” which basically calculated nothing. At this point the only choice I had is to treat the code the way you treat obfuscated code and there is only one true way to treat obfuscated code and it is — F8ing + BPs all the way.
diving in the code and f8ing all my way I bumped into somewhat funny strings that not always meant anything, i.e:
During F8ing I found some nice insights:
- There is a “malicious” function that shoots at “wrong” places such as AD (Anti-Debugging) checks or wrong values that interpret that this malware was not aimed at you (A.K.A the frustration of the malware, described at the start of this article).
This function basically makes the computer get stuck, mouse buttons to switch, weird beeps are starting to come from the computer and eventually crashing my VM with a BSOD when dynamically running it in order to invetigate all the capabilities. So here is another reminder to always work on a VM while you are investingating malware.
2. A file is being written in the end of the horrible main function, under a yet another horrible sub-function. The file being created is flag.png and it has the content: “starting to get scared now…”
3. There is internet connection being made after wininet.dll is loaded dynamically, just before the file creation. This is a request that generates the result to be written to flag.png
The next step was of course to investigate the url request and understand exactly the way it is generated to maybe find a request that will yield the flag instead of the “scary” sentence.
But just before that, I didn’t want to make any mistakes and hear the horrible sound of the malicious function so I patched out all it’s calls.
Internet request URL:
The request looked in the following way:
The token was the interesting file because it looked like a nonsense blob, but when trying to get the request without it yielded “unauthorized” and with it, it yielded the “scared” message.
Reversing the token structure
In depth analysis of the token revealed that it is combined out of 4 components, seperated by a “|” (0x7C):
- Random chars that change in each run:
- First 12 bytes of an mp4 audio that we don’t have or have a way to restore but is supposed to be stored locally in the “wanted computer”, as hex digits, meaning 24 hexadecimals.
- Hex digits of the username of the computer xored with the string “qoef13iurbn2408”. The username is currently unknown but we will have to look for away to find it.
- Hex digits of the Computer Name of the computer xored with the string “qoef13iurbn2408”. The Computer name, unlike the username is known From the last part.
I have changed my omputer name to “ “, so comparing manual xor with the result sent in the url by the malware confirmed my hypothesis and findings, resulting with:
Finding the wanted userame was prety easy — It was one of the strings that were thrown while the malware ran, probably as a check but I didn’t even try to figure this part out because I wanted to finish the challenge ASAP.
The username was — “The!Spy!Konstantin-K”
Finding the first 12 bytes of the mp4 was harder because turns out there are 19 different types of mp4 headers:
[“avc1”, “iso2”, “isom”, “mmp4”, “mp41”, “mp42”, “mp71”, “msnv”, “ndas”, “ndsc”, “ndsh”, “ndsm”, “ndsp”, “ndss”, “ndxc”, “ndxh”, “ndxm”, “ndxp”, “ndxs”]
Also, the first 4 bytes of an mp4 file depend on it’s header size:
MP4 Video Signature Format: Documentation and Recovery Example
MPEG-4 Part 14 or MP4 is a digital multimedia format most commonly used to store video and audio, but can also be used…
With a guess that the size would not extend 60, there are some options for wanted the 12 bytes but not more than a 100 options.
Writing a Python PWN Script — NO BRUTEFORCE
In order to find the correct mp4 format, I wrote a script that generates the wanted token and sends a get request to the url with it. The script runs less than a 100 time so it’s not bruteforcing and was pretty quick the result with the answer which wasn’t actually a png of a flag but a text with the flag itself:
My full code can be found here:
Pwn script for corona-virus challenge CTF - Pastebin.com
Pastebin.com is the number one paste tool since 2002. Pastebin is a website where you can store text online for a set…
I want to take this time to thank the authors of this challenge and also apologize about the things I said in my heart while debugging the obfuscated code. You did a great job and I had a blast.
I want to also thank my team — @shablul for participating with me through the CTF. While we did not reach our wanted goals this time, we certainly had a great time.
Last but not least, I want to thank my partner in crime Tomer Barkai who joined me for the second part of this challemge. Always a pleasure Reversing keyboard to keyboard with you brother, even remotely.
I am a cyber security researcher with quite a bit of experience, especially in the field of Reverse Engineering.
Lately I decided to give myself some free time to just research and write about anything that comes up to my mind from CTF challenges to General ideas and even some POCs regarding cyber security. This way I can practice two of my hobbies — Reverse Engineering and Writing.
If you’ve found this article interesting and want to hear more from me you can subscribe to my channel.
I made myself a challenge to post every two weeks but, let’s see what happens.