Question: How can signature-based Intrusion Detection systems be defeated? Answer: Using polymorphic shellcodes! This might sound really crazy and cyber, but it has nothing to do with inventing fancy new hacking techniques, it’s rather about puzzling. By replacing assembly instructions with other assembly instructions the original functionality is kept intact and signature-based systems are defeated. For example, the following assembly code snippet should give you an idea of what this means:
This simply moves the value 0x2 into eax. Exactly the same functionality could be achieved by using:
or by using:
All examples have in common that in the end 0x2 is put into EAX. It’s the very same functionality with completely different assembly instructions, and this is called a polymorphic shellcode.
Of course there are hundreds of different assembly instructions you could combine to reach the same functionality, and this is what makes the life of IDS/IPS systems really hard. In theory (in a signature-based system), you need to keep samples (or signatures) of many different mutated shellcode versions, just to match one single functionality. Since this is nearly impossible, polymorphic shellcode is used often by attackers to bypass such systems. However many vendors have introduced special heuristics watching the behavior of a shellcode, which is even harder to bypass, but not part of this blog article.
This blog post number 6 as part of my SecurityTube SLAE exam covers creating polymorphic shellcodes. The task is to:
The polymorphic versions must not exceed the size of 150% of the original shellcode
Bonus: Reducing the size of the polymorphic version in comparison to the original shellcode results in bonus points
Spoiler: I have met all requirements and the bonus ;-)
Short note: Before digging into these shellcodes, I need to mention that many shellcodes on shell-storm.org are documented using AT&T assembly syntax, and since I don’t like the AT&T syntax that much, I am using the following commands to convert it to Intel syntax:
Another short note: I have commented my polymorphic shellcodes inline, because think this help to understand the mutations.
The first shellcode by Jean Pascal Pereira is about the deactivation of Address Space Layer Randomization on Linux. ASLR is used to reduce the attack likelihood by randomizing memory addresses and can be queried and configured using /proc/sys/kernel/randomize_va_space. The default setting on my latest Ubuntu test VM is “2”, which means that positions of the stack, VDSO, shared memory regions and the data segment gets randomized:
To (temporarily) disable ASLR and therefore probably increase the success likelihood of other exploits, all an attacker has to do is setting this to “0”, and this is exactly what this shellcode is doing. Please note that you need root privileges to successfully execute this shellcode!
So the original shellcode converted to Intel syntax looks like this:
My basic idea of the first polymorphic shellcode was to primarily obfuscate the string part “/proc/sys/kernel/randomize_va_space” of the shellcode by XORing it:
When my shellcode is executed, ASLR is successfully deactivated:
The size of the original shellcode is 83 bytes, my polymorphic version is 114 bytes, which means an increase by ~38%.
Linux/x86 - Add map in /etc/hosts file - 77 bytes
The second shellcode by Javier Tejedor is about adding a newline to /etc/hosts, which makes it possible to e.g. redirect traffic. The original shellcode adds the entry “127.1.1.1 google.com” to the hosts file:
The main idea of my polymorphic version is to obfuscate the hosts entry by subtracting 0x10 from each byte :
When my shellcode is executed, the new entry is successfully added to /etc/hosts:
The size of the original shellcode is 77 bytes, my polymorphic version is 109 bytes, which means an increase by ~42%.
Linux/x86 - Copy /etc/passwd to /tmp/outfile (97 bytes)
The third shellcode by Paolo Stivanin is about copying the /etc/passwd file to /tmp/outfile, which could be useful for an attcker if the /etc/passwd is not directly accessible because it is e.g. protected by a sandbox:
The main idea of my last polymorphic version is to reduce the size of the resulting shellcode by simply mixing up push instructions, which are responsible for the payload:
When my shellcode is executed, the passwd is successfully copied to /tmp/outfile:
The size of the original shellcode is 97 bytes, my polymorphic version is 95 bytes, which means an decrease by ~2%!
This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification: