CVE-2024-3400: PAN-OS Command Injection Vulnerability in GlobalProtect Gateway. Learn More

CVE-2024-3400: PAN-OS Command Injection Vulnerability in GlobalProtect Gateway. Learn More

Services
Capture
Managed Detection & Response

Eliminate active threats with 24/7 threat detection, investigation, and response.

twi-managed-portal-color
Co-Managed SOC (SIEM)

Maximize your SIEM investment, stop alert fatigue, and enhance your team with hybrid security operations support.

twi-briefcase-color-svg
Advisory & Diagnostics

Advance your cybersecurity program and get expert guidance where you need it most.

tw-laptop-data
Penetration Testing

Test your physical locations and IT infrastructure to shore up weaknesses before exploitation.

twi-database-color-svg
Database Security

Prevent unauthorized access and exceed compliance requirements.

twi-email-color-svg
Email Security

Stop email threats others miss and secure your organization against the #1 ransomware attack vector.

tw-officer
Digital Forensics & Incident Response

Prepare for the inevitable with 24/7 global breach response in-region and available on-site.

tw-network
Firewall & Technology Management

Mitigate risk of a cyberattack with 24/7 incident and health monitoring and the latest threat intelligence.

Solutions
BY TOPIC
Offensive Security
Solutions to maximize your security ROI
Microsoft Exchange Server Attacks
Stay protected against emerging threats
Rapidly Secure New Environments
Security for rapid response situations
Securing the Cloud
Safely navigate and stay protected
Securing the IoT Landscape
Test, monitor and secure network objects
Why Trustwave
About Us
Awards and Accolades
Trustwave SpiderLabs Team
Trustwave Fusion Security Operations Platform
Trustwave Security Colony
Partners
Technology Alliance Partners
Key alliances who align and support our ecosystem of security offerings
Trustwave PartnerOne Program
Join forces with Trustwave to protect against the most advance cybersecurity threats
SpiderLabs Blog

Defeating Flame String Obfuscation with IDAPython

Like many other security research firms, SpiderLabs Research has been actively investigating the Flame (a.k.a. sKyWIper) malware that was revealed earlier this week. For those unaware of what Flame is, I'll provide a very brief summary. Essentially, Flame is a modular, extremely large, piece of malware that was discovered in Iran. The malware was found to be quite complex, providing the attackers with a wealth of information and control over the infected system(s). Many of the components included in Flame provide some form of encryption and/or obfuscation, which is what I will be discussing today. Specifically, I'm going to talk about String obfuscation encountered in the advnetcfg.ocx component, and how I was able to defeat it using IDAPython.

Before I jump straight into IDAPython, however, I'd like to take a step back and describe how I was able to identify the String obfuscation, and ultimately discover the plain text of the Strings in the sample.

Upon analyzing advnetcfg.ocx, I discovered a number of pieces of data that were being supplied as arguments to the same function.

9101_4a417669-020b-41ec-b84c-9ddcc02fc887In the image below, we can see how these blocks of data are being supplied to the function:

7966_1081dfd4-2da6-4976-9c60-ca6ae8586e75Further review revealed that, in total, 179 references were being made to this function. The large number of references, coupled with the data being supplied to the function, provided a strong clue that some form of de-obfuscation or decryption routine might be taking place. If we jump into sub_1000BE16, we start to get a better understanding of what is happening.

7724_05d1fc9c-e119-4c76-a0c5-505a3ecdce24Ok, so maybe the screenshot above doesn't provide the best representation of what is going on. Below, I've essentially taken the above function and converted it to Ruby.

8199_1c101881-5ea9-4963-b3cd-2ea1d23b3cc2The function above is taking the obfuscated String as a parameter, and checking the sixteenth byte to determine if it is null. This byte is acting as a Boolean value to tell the function if the String has already been decoded. In the event that this byte is not set to null, or 0x00, another function is called, and the sixteenth byte is set to 0x00. Finally, the result of String that was initially supplied as a variable, with an offset of +20, is returned. If I were a betting man, I'd suspect that the second function (named 'deobfuscate() in the above Ruby code) is manipulating the data somehow. In order to find out, let's investigate what is going on.

If we look above, we can see that this new function is supplied two arguments—The 'obfuscated_string' variable with an offset of +20, as well as the eighteenth byte in 'obfuscated_string'. We can see how these arguments are used below:

9960_7401b829-8d46-4d7e-a5b4-d906ca3b3cb4Don't worry about reading the above Assembly, as I have it converted to Ruby below. I'm simply providing the Assembly as a reference to those that are interested.

10775_98cf7e6e-5adb-4c9f-b0cf-c047d95ba04bOK, so let's see what is happening. As we can see above, the first argument (obfuscated_string+20) is actually the true obfuscated string. The second argument of obfuscated_string[18] is the size of the obfuscated_string+20—essentially telling the function when to stop. I've tried to demonstrate this below, in the event people are having trouble following:

10831_9bdcc950-4800-4f20-bbe5-94b0e4c1dd8fSo this function appears to call a third function (last one I promise), and proceeds to subtract the resulting number from the specific character in the string before replacing it. So if we were looking at the first byte (0xA7), and the third function returned 0x82, we would get the following:

0xA7 – 0x82 = 0x25 ("%")

So that brings us to the third, and last, function in this de-obfuscation routine. This function, unlike the previous two, is quite small:

12822_fac7469d-29b2-432d-8e4e-bc54c039e418
The above function decodes to the following in Ruby:

11690_c5911dc6-c086-4efb-96e9-08145474b44aThe argument the above function takes is an incrementing position in the obfuscated String. So the first time it is called, 'index' is equal to 0, then 1, 2, 3, etc. until it reaches the end of the obfuscated string.

At this point we've concluded recreating the de-obfuscation routine that is used in advnetcfg.ocx. So you're probably sitting on your comfy lay-z-boy asking yourself, "Wait a minute, I thought you said you were going to defeat it with IDAPython!? What's all this Ruby nonsense?" Well, it's true; I made a slight blunder when I originally dove into this code.

I originally wrote everything in Ruby, only to realize that writing it in Python might have been a better option (you'll see why in a minute). No, it's not because Python is a superior scripting language, but it's because IDA Pro (http://www.hex-rays.com/) has graciously provided a plugin that integrates the Python language, allowing us to run scripts inside of IDA Pro. Remember how I said earlier that the de-obfuscation routine was referenced 179 times? I don't know about you, but I sure don't want to manually copy each obfuscated String into a script and manually comment the resulting value into my IDB file. As such, I looked into using IDAPython.

Now I'll be the first to admit it—I'm probably as far as you can get from being a "Python expert", but I did manage to get through it without too many bumps in the road. The first step was to convert the work I'd done earlier into Python. Overall it didn't prove to be terribly difficult as Ruby and Python share a lot of commonality.

The second step was to find all of the obfuscated strings that get supplied to the de-obfuscation routine. If we look back, we recall that before each call to the de-obfuscation function, there was a 'push offset' call, like so:

10897_9ed6132b-abce-442e-8887-63228e2f2a79

I've included the hex representation of each Assembly call, as this information will be important later on. If we look closely at the hex of the 'push offset unk_1008FBB8', we can see that the 'push offset' portion is represented by 0x68. The remaining 4 bytes represent the location of the obfuscated string, in the reverse order (due to the endianness).

11086_a8289ee1-f8d5-4bf6-b738-506bd96bc18e

Knowing this, we can use the CodeRefsTo() function to determine all of the XREFs to the de-obfuscation function. We can then subtract 4 from each location in order to point to the obfuscated string location. Using the information we gathered earlier regarding the size of the obfuscated string being located at the eighteenth byte, along with knowing that the actual obfuscated segment starts at the twentieth byte, we can obtain the information needed, like so:

11043_a5b8aaac-8276-4ca7-ab86-45ab6db292eeNext, we take this data and supply it to the previously created decrypt function. Finally, we take the resulting de-obfuscated string and store it as a comment in the IDB file. For this, we can use the MakeRptCmt() function, to make a repeatable comment. Also, just to keep things clean, let's throw a debug message to the user, letting them know what de-obfuscated Strings were discovered, and where they can be found.

The complete code can be found here.

An example of what it looks like when it is run can be seen below:

8264_1f96cde7-9688-4122-954e-e40d90cd4d08

In addition to the above functionality, John Miller (@ethackal) provided this wonderful one-liner that will also rename the data blocks to their de-obfuscated string representation. The following code accomplishes this:

11669_c4d3316d-a500-4a32-85af-74313b2dd3dcAt this point we can continue our analysis of the advnetcfg.ocx without worrying about those pesky obfuscated Strings.

Latest SpiderLabs Blogs

EDR – The Multi-Tool of Security Defenses

This is Part 8 in my ongoing project to cover 30 cybersecurity topics in 30 weekly blog posts. The full series can be found here.

Read More

The Invisible Battleground: Essentials of EASM

Know your enemy – inside and out. External Attack Surface Management tools are an effective way to understand externally facing threats and help plan cyber defenses accordingly. Let’s discuss what...

Read More

Fake Dialog Boxes to Make Malware More Convincing

Let’s explore how SpiderLabs created and incorporated user prompts, specifically Windows dialog boxes into its malware loader to make it more convincing to phishing targets during a Red Team...

Read More