What I Have Done - Hacking Malware
I was looking back through my old talks and papers (2005-2015) and realized some of them still apply today so I've decided to make some article posts rehashing them with a few updates in some cases. This is the first one.
This is from a talk I gave with a co-speaker in 2005 at Defcon about hacking malware which is both attacking vulnerabilities in the malware itself as well as figuring out how to bypass their protections. This talk focused on the following areas:
- Virtualization Detection
- Bypassing Binary Obfuscation
- Bypassing Anti-Debugger Techniques
- Exploiting a Buffer Overflow in the Sasser Worm
- The release of the Offensive Computing automated malware analysis platform (think VirusTotal before VirusTotal existed)
VIRTUALIZATION DETECTION
The goal of virtualization detection in malware is typically for an attacker to determine if their malware is being analyzed in a VM or running somewhere they don't want it to be. If they detect virtualization they can then call code that exits and deletes itself or take some other action.
A very simple example of virtualization detection can be found in variants of the Dasher worm.
In this case the malware simply shells out and runs the net start command to look for VMware related services. There are a couple of different ways to address this as an analyst.
- Stop VMware related services: net stop "vmware tools". This will cause a degradation of VMWare capabilities but will bypass this simple type of detection.
- Another approach is to hex edit the binary and get rid of the detection altogether. First, Identify the function that calls the VM detection code:
3. Find the Hex representation of this call:
4. Hex edit the binary and No Operation (NOP) out the bytes for the call to the VM check:
At the time when this talk was presented there were a few different types of Virtual Machines:
- Fully Emulated instruction set
Instructions are translated on the fly to host OS
Generally have a 1-1 representation of host OS
- “Somewhat” Emulated
Stack operation emulation
Descriptor table translation
IDT, GDT, LDT
- Hardware Virtualization
Intel Vanderpool Instruction Set
AMD Pacifica Instruction Set
Certain registers have system-wide applicability:
- LDT – Local Descriptor Table
- GDT – Global Descriptor Table
- IDT – Interrupt Descriptor Table
- MSW – Machine Status Word
This means that in some cases interrogating these registers can give hints about if the context is virtualized or not. Each register has its pros and cons for VM detection:
IDT Technique (sometimes known as redpill, skoopy_doo)
- Simple signature match on IDT register value
- Effective for single-processor machines
- Multiprocessor/Dual Core have separate tables - failed 1/n times n = number of processors
GDT had similar results
LDT showed static results across processors
- Used for accessing local data relevant to process
- Memory addressed similarly despite context switches
- Fails on full emulation. (e.g. Disable acceleration on VMWare)
MSW good to use if LDT fails.
In addition to these I have come up with a couple other options for virtualization detection on Linux:
- Checking the CPUID
- Checking the process table for VM related processes
- Checking timestamp counter (TSC) values for anomalies
- Checking the SMBIOS
- Checking for VM hardware under sys
I created a POC with many of these techniques and threw it up on the Red Crow Lab Github. (Be gentle, I'm not a coder. Bug fixes welcome!)
https://github.com/redcrowlab/rcDetectVirtual
BINARY OBFUSCATION
Two main types of binary obfuscation were covered in this talk:
Binary Compression - Similar to zip. Creates smaller binaries, less bandwidth usage, smaller footprint, makes it harder to disassemble and analyze, obfuscates the Original Entry Point (OEP).
Binary Encryption - The use of encryptor tools like Morphine, telock, Yoda's Crypter, etc. Could also include string encryption within the binary as well.
The general process for defeating these protections is:
- Scan binary with a detector to determine if it is compressed or encrypted and with something known or custom.
- De-obfuscate the binary if a tool exists for doing so.
- Disassemble the binary and attempt to identify and analyze the decryption stub.
- Step through the decryption routines by running the malware in a debugger and pause execution when de-obfuscated. (Tools like x86emu, IDA Pro, Ollydbg, WinDbg, x64dbg apply)
- Dump process memory and hopefully have a cleartext binary.
ANTI DEBUGGER
Some malware incorporates code which detects if it is being debugged and then takes some action in response such as exiting, deleting itself, etc. A very rudimentary example:
Windows provides an API called IsDebuggerPresent which does a simple check. I've seen many malware samples that employ this approach.
This method is vulnerable in a couple of ways:
- Create a JMP near the debugger check using hex editing.
- Identify the check in IDA and then change the Z flag in the debugger to lie to the program and tell it no debugger was found to be present.
- Some debuggers like Ollydbg have plugins which bypass this check for you.
The following image shows a graph of xrefs that point to the IsDebuggerPresent() call, the hex codes for both Jump if Zero and simple Jump assembly codes, the disassembly of the debugger check, and a shot of the hex dump:
Since this talk I have learned a bunch of different techniques from handle manipulation, using specific interrupts, reading special registers for hardware breakpoints, kernel calls, and checking for debug privilege.
I found a cool git repo with examples for many of these approaches:
https://github.com/LordNoteworthy/al-khaser/tree/master/al-khaser/AntiDebug
I'll be adding a rcDetectDebugger tool to the Red Crow repo soon as well.
EXPLOITING MALWARE
The Sasser Worm was one of the most impactful worms of the 2000's. This worm carried with it its own FTP server called avserve that it used for propagation. In this worm it was packed so first I had to de-obfuscate it. (I'll do an article on de-obfuscation examples in the future).
Then I found a basic buffer overflow in the disassembly of the FTP server, specifically in the PORT command:
Since this worm was ripping through the organization I worked for at the time, the first thing I tried to do was create a DoS attack against the FTP server which would stop it from propagating.
The original purpose of Metasploit was to create a framework for quickly developing exploits. By having a library of shellcode, protocols, and clue code, something that used to take weeks would take hours or a couple of days. Its a little ironic that it ended up being primarily a penetration testing tool but it was great for this purpose.
I created a metasploit module that would launch the DoS attack and implemented the following attack:
my $request = "PORT" . "\x41" x 295;
This sends 295 A characters to the FTP PORT command which causes the server to crash and the worm to stop spreading.
Then I decided to take it up a notch and try to get a shell through the worm by attacking this buffer overflow over the network. This attack uses a Structured Exception Handler (SEH) overwrite attack which takes advantage of a vulnerability in a program's exception handling mechanism.
In normal program execution flow, when an exception occurs (e.g. divide by zero), the program's SEH mechanism kicks in and attempts to handle the exception gracefully, often by jumping to a specific block of code called an exception handler.
An SEH overwrite technique involves overwriting the SEH handler with a pointer to malicious code, so that when an exception occurs, the program jumps to the malicious code instead of the legitimate exception handler. This allows an attacker to gain control of the program and execute arbitrary code. SEH applies to Windows only as far as I know.
To create this attack I spent a few days fighting with WinDBG and watching debugger output to find loaded libraries, see what was happening in memory, etc. The "trampoline" aka the jump forward and backwards through memory was particularly hard to figure out. I also used a cool tool in metasploit called msfpescan which scans a windows exe for various types of information including something called POP POP RET's.
In assembly, the POP instruction is used to remove the top value from the stack and store it in a register. The POP POP RET technique involves using two consecutive POP instructions to remove two values from the stack, which are then used to overwrite the return address on the stack with a pointer to the attacker's malicious code. The RET instruction is then executed, causing the program to jump to the attacker's code.
The final attack ended up looking like this:
The blue text explains what each component of the attack is doing. The red text shows the code for the exploit request. This exploit worked pretty well and gave me a shell on many machines infected with Sasser.
The rest of the talk focused on complaining about the AV industry. At the time this talk came out it was very difficult to get ahold of malware samples and AV companies would attack anyone who tried to get involved in virus research. This isn't really an issue anymore so I'm not going to spend any time on it here.
I hope you find this helpful and thanks for listening!
A.