peCloak.py – An Experiment in AV Evasion

Written on:March 9, 2015
Comments
Add One

Introduction

I just wrapped up the Offensive Security Cracking The Perimeter (CTP) course and one of the topics was AV evasion. Although I write a lot of custom scripts and tools, when it comes to AV evasion, I typically rely on the tools and methods of others (Veil, powershell, python, custom shellcode). That said, the great thing about courses like CTP is they give me an excuse to investigate a topic that I haven’t had an opportunity to delve into in much detail.

The CTP course was developed several years ago and I was curious how far AV vendors have come since then; so, after completing the course module, I decided to delve a bit further and devised a little experiment to see how easy it would be to consistently bypass detection of some of the market leading AV products. I spent a weekend tapping out some code and what resulted was a simple proof-of-concept python script I dubbed “peCloak” which automates the process of hiding a malicious windows executable from AV detection (a copy of the beta version is available at the end of this post).

The Experiment

Before we get wrapped up in the terms, let me just say that I’m using the word “experiment” very loosely. There won’t be any control groups or random selection so please don’t go critiquing my application of the scientific method! :)

Hypothesis

My hypothesis was simple and based on common knowledge: AV detection is heavily reliant on file signatures with limited application of sandbox / heuristic-based detection.

Therefore I was confident that by modifying portions of the executable and introducing basic sandbox-defeating functionality I could render most client-side AV detection ineffective.

Requirements

I set out with the following requirements:

  1. The modified PE file must evade AV detection from market-leading products with up-to-date definitions.
  2. The encoded malicious payload must execute without error. Failure to execute regardless of AV detection would be considered an unsuccessful bypass.
  3. The entire process (encoding, decoding, etc) must be automated. No manual manipulation of code caves or jump codes within a debugger.

The Test Environment and Selected AV Products

All testing was performed on a virtualized Windows XP SP3 machine (except for Symantec SEP testing which was conducted on a Mac Host). A Kali VM was used to verify operability of pre- and post-encoded reverse shell payloads.

I wanted to represent the “market share leaders” in the AV product market so I decided on using the opswat January 2015 report.

pecloak1

How accurately this truly represents market share is questionable (especially with a sample size of 4000) so I decided to test every vendor outside of the “Other” category as well as a sampling of vendors within that category. In the end, the vendors I chose were:

Avast Comodo
Microsoft Spybot
AVG Panda
Avira Trend Micro
Symantec Bitdefender
McAfee Bullguard
ESET Malwarebytes
Kaspersky Lab

With the exception of Symantec SEP, all tested AV products were the free versions offered by the respective vendor. The specific product name appears in the results section that follows.

I wanted to test multiple “malicious” executable payloads that would be easily detected by any AV product so I chose the following four:

  • Two metasploit payloads (meterpreter_reverse_tcp and shell_reverse_tcp)
  • A local privilege escalation exploit (KiTrap0D aka”vdmallowed” – http://www.exploit-db.com/exploits/11199/)
  • A metasploit reverse_tcp backdoored executable (strings.exe from sysinternals)

All were verified to function prior to any modification/encoding.

The Approach

For successful AV evasion, I figured I needed a few features.

  • First, I had to implement some form of encoding or encryption that would defeat signature based detection. I gave myself the additional constraint that I could only use simple xor, add, or sub instructions in my encoder — not because anything else would be too complicated, but rather to show that the encoding approach did not have to be complex to defeat signature based detection.
  • Second, I needed to defeat any sandbox -based, heuristic run time detections that might be employed by an AV product.
  • Third, I wanted to minimize the static nature of the decoding/heuristic code that would be included in the modified executable to avoid having it become a signature for AV detection.

A closer look at peCloak.py

To meet all requirements I wrote a python script that I dubbed “peCloak”. While I walk through the basic approach, please keep in mind that the bulk of this was written over a weekend so there are plenty of potential improvements that could be made. I am not presenting this as an alternative to existing tools like the Veil Framework and I don’t plan on maintaining the script beyond this simple beta version. This was simply the automated approach to AV evasion I developed in the context of my little “experiment”; though I hope that some of the approaches I used might be helpful to you if you’re considering delving deeper in the world of AV evasion.

Here’s a copy of my current (beta) version of peCloak.py:

peCloak.py
peCloak.py
Version: Beta
48.3 KiB
674 Downloads
Details

Please note there are a few dependencies should you desire to try it out for yourself:

While I won’t be covering all of the code in-depth (it’s fairly well commented for a beta version), let me walk you through some of the approaches I used when developing this script.

Encoding

To avoid signature-based detections, there is an obvious requirement for some form of encoding. With my self-imposed constraints of using only basic add, sub, xor instructions, and dynamic construction of the encoding order, I came up with the following really simple encoder routine (portions of the function removed for brevity):

It meets all of my criteria — a simple set of instructions whose number, order, and modifiers are all chosen pseudo-randomly to increase variation.

The encoding process happens at script run-time by reading in the contents of the file and encoding the designated section(s) byte by byte. By default, the script encodes the entirety of the PE section that contains the executable code (typically the .text or .code section) but that’s a configurable option. I leverage the pefile library to do the heavy lifting for mapping the contents of the file and retrieving various sections.

You can see this basic encoding process illustrated in the below excerpt of the encode_data function:

Decoding

Decoding is also relatively simple in that it’s just the reverse of the encoding routine. The order of instructions is reversed (FIFO) and the instructions themselves must be inverse (add becomes sub, sub becomes add and xor remains the same). For example, here is an example encoding routine and it’s corresponding decoder.

Encoder Decoder
  1. ADD 9
  2. SUB 3
  3. XOR 2E
  4. ADD 12
  5. SUB 1
  6. XOR 3F
  7. ADD 7
  1. SUB 7
  2. XOR 3F
  3. ADD 1
  4. SUB 12
  5. XOR 2E
  6. ADD 3
  7. SUB 9

The decode function looks something like this:

To build the decoder, I simply use a dictionary of assembly opcodes for the inverse instructions of the various encode operations. I then loop through the encoder that was previously created and use that to build the corresponding decoder. This is necessary since the encoder is dynamically constructed (and therefore different) each time.

Here’s a look at that function:

Heuristic Bypass

The heuristic bypass routine is nothing more than a set of instructions that waste cycles in an effort to trick the AV scanner that the executable is benign. NOPS, INC/DEC, ADD/SUB, PUSH/POP are all candidates. Just as with the encoding routine, I select a pseudo random number and order of these benign instructions and pair them with an incrementing counter /compare instruction (also chosen pseudo – randomly from a given range) to create a loop of finite iterations .

The number of loops within a given heuristic routine is configurable at script run time, though keep in  mind that the more iterations you implement, the longer it will take for the cloaked executable to start.

The calls to add_fill_instructions() in both the heuristic and decoder creation functions simply pseudo-randomly select from a dictionary of the aforementioned benign instructions (inc/dec, push/pop, etc).

Carving out a code cave

Ultimately what the script does is encode the designated portions of the PE file and insert a code cave containing the heuristic bypass and corresponding decoder function. The location of this code cave is determined at script run time by first checking each PE section for a minimum number of consecutive null bytes (currently hard-coded at 1000). If found, it will make that section executable and insert the code cave at that location. Otherwise, the script will create a new section (named “.NewSection”) using the SectionDoubleP code. You can override the script’s attempt to insert the code cave in an existing section (if it appears to be corrupting the file) with the -a | –add option.

Jumping to the code cave

In order to jump to the code cave, the execution flow of the PE file has to be modified at ModuleEntryPoint. This process is two-fold:

  1. Create the jump instruction using the address of the previously created code cave
  2. Preserve the overwritten instructions at ModuleEntryPoint so they can be replayed later

The latter function is relatively simple in that I leverage the pydasm library to read the entry instructions and obtain the corresponding asm.

One important aspect of this function is to ensure that it preserves the instructions in their entirety. For example, assume the original entry instructions are

If your code cave jump overwrite is 5 bytes, you still want to ensure you’re preserving all 7 of the first two instructions or you’ll end up with corrupted code.

Restoring execution flow

At this point, the module entry contains the jump instruction to the code cave, which will start with the heuristic bypass function and then proceed to decode the encoded section(s) of the pe file. Once that’s done, execution flow has to be redirected back to its original location so the executable can function as intended. This is a two step operation:

  1. Replay the overwritten original instructions
  2. Jump back to the module entry point (offset by the added code cave jump)

Replaying the original instructions is complicated by the fact that they may contain relative jump/call instructions. The location of these jumps/calls need to be re-calculated from the current location in the code cave.

I’ve addressed this by recalculating relative jumps based on the original destination and the current address within the code cave.

The conditional_jump_opcodes and unconditional_jump_opcodes variables are just dictionaries of the respective opcodes. The referenced update_jump_location function is really simple and looks as follows:

Other features

As with anything I do, there’s usually a fair amount of scope creep and so I built a few extra features into the tool to help analyze the target file. For example, during testing, sometimes I wanted to be able to view a particular section of the PE file to determine what might be triggering signature based detection so I built in a simple hex-based viewer

pecloak2

Writing the Modified PE File

One last note is that in order to get expected results from my modification function I had to modify the pefile library slightly. Specifically, I ran into the issue that when pefile saves a modified executable, it overlays the section structure data on top of the modified bytes. In other words, if you modify the first 50 bytes of the .rdata section of a given file, that modification will be replaced by the original section header. To prevent this behavior, I added an additional parameter (SizeofHeaders) to the pefile write() function. This allows me to preserve the pe header but replace everything after should I choose:

pecloak3

Similarly, strings are also overwritten so I made some additional modifications to the write() function to prevent this as well:

pecloak4

Depending on the level of control you require of your modification, additional changes may be necessary, though these two modifications suited by simple testing just fine.

Here’s a look at the output (run with default settings):

pecloak25

Running the Experiment (peCloak in action)

Now that I had the tool, it was time to see how effective it was. Using the previously identified list of AV vendors, I downloaded their respective free AV products and got to testing. Again, my goal was to evade AV detection for each of the four test executables without breaking the exploit’s functionality.

Here is a summary of the results:

pecloak5

As you can see, a green check mark indicates successful evasion, a red X indicates peCloak could not successfully bypass AV evasion, and N/A indicates the AV product did not even detect the original uncloaked version so additional encoding was unnecessary. It should be noted that several products did not detect any of the uncloaked malicious executables (McAfee, Spybot, and TrendMicro) despite updated virus definitions. There were no apparent configuration problems or errors indicated by the product so the reason for detection failure is unknown. Regardless, these products were disqualified from further testing as a result. That left a total of 12 AV products that were tested.

The summary is pretty telling … I was able to successfully hide all four executables from detection in 9 of the 12 products (in some cases, evasion was unnecessary for one or two of the files as the original, unencoded files were not even detected. The only products that provided at least partial protection were Avast ,Bitdefender, and BullGuard. This is largely because any bytes contained outside of the PE file sections (.text, .data, .rdata, .rsrc, etc) are not modified by my peCloak script. For example, in at least one of these AV products, the signature detection was the result of bytes contained within the PE Header, which my script does not attempt to modify.

A quick glance at the table, will demonstrate that despite a few of the products detecting some of the executables, the best method of evading AV detection is by cloaking a backdoored executable (as I did with strings.exe). In fact, as you’ll see below, one of the products actually automatically whitelisted my backdoored executable without any action on my part!

A Closer Look

In case you want to replicate these findings with peCloak, or your own tool, what follows are the exact options I used to cloak each file from the respective AV product. A couple of things to note:

First, I did not include all of the screenshot evidence of each scan result for each file as I thought it would make this post way too long, though I did provide a sampling to illustrate some of the results.

Second, most of the byte range values I used to encode the files were not optimized. For example, if encoding bytes 0 through 500 of the .rdata section resulted in successful AV detection, as long as the executable still functioned as intended, I didn’t test it further to see exactly which bytes were responsible for detection. I’ll leave that exercise up to you should you so desire.

Third, when I refer to peCloak’s “default” settings, I’m referring to a heuristic bypass level of 3 (-H 3) and encoding of only the .text section. This is what happens if you simply run peCloak.py with no additional options.

Also, as reminder, the four files that were tested for evasion were:

  • av_test_msfmet_rev_tcp.exe – Metasploit Meterpreter reverse_tcp executable
  • av_test_msfshell_rev_tcp.exe – Metasploit reverse tcp shell executable
  • strings_evil.exe – strings.exe backdoored with Metasploit reverse_tcp exploit
  • vdmallowed.exe – local Windows privilege escalation exploit

The first three were constructed directly from Metasploit and the third was compiled using the source code at the link I provided at the beginning of this post. No efforts to encode these files was made prior to testing them with peCloak.

Avast Free AntiVirus (Evasion: 1/3, 1 N/A)

This product did not detect the unencoded version of vdmallowed.exe file but did detect the other three as malicious.

I successfully evaded strings_evil.exe by encoding a portion of the rdata section:
peCloak.py -e .text,.rdata:50:500 strings_evil.exe

pecloak21

I was not able to evade either Metasploit executable, even with all PE sections encoded (and the file rendered inoperable). Additional testing indicated detection resulted from the contents of the file header (which is outside of the scope of my simple peCloak script), so no additional evasion was attempted.

MSFT Security Essentials (Evasion: 4/4)

This product successfully detected all four uncloaked test files.

pecloak8

Three of the files (av_test_msfmet_rev_tcp.exe, av_test_msfshell_rev_tcp.exe, and strings.exe) successfully evaded detection with default peCloak settings (peCloak.py [executable name]).

I was able to successfully evade detection of  vdmallowed.exe by encoding an additional portion of the data section: peCloak.py -e .text,.data:50:5000 vdmallowed.exe

Avira (Evasion: 4/4)

This product successfully detected all four uncloaked test files.

Three of the files (av_test_msfmet_rev_tcp.exe, av_test_msfshell_rev_tcp.exe, and strings.exe) successfully evaded detection with default peCloak settings.

I was able to successfully evade detection of  vdmallowed.exe by encoding an additional portion of the data section: peCloak.py -e .text,.data:50:5000 vdmallowed.exe

AVG Free 2015 (Evasion: 4/4)

This product successfully detected all four uncloaked test files. peCloak successfully evaded detection for all four files using the default settings, though evasion was inconsistent. In other words, if an executable was cloaked twice using the exact same peCloak options, one of those cloaked executables would evade detection and the other would not. Additional testing showed that the detection did not appear to come from any of the sections of the PE file (leaving the header) though this makes it even stranger as to why detection would be inconsistent from file to file. This was the only AV product to exhibit this behavior. In addition, once a cloaked file was created that successfully evaded AV detection, testing showed that it would always evade detection, meaning the test files could in fact be reliably cloaked.

pecloak7

Successful evasion of one of the Metasploit payloads

Symantec SEP (Evasion: 3/3, 1 N/A)

As stated previously, testing of SEP was the only AV product tested on a Mac client (simply because I already had it installed). This product did not detect the pre-cloaked strings_evil.exe so additional evasion was not necessary. The remaining three pre-cloaked test files were detected.

pecloak6

I successfully evaded detection for both of the Metasploit executable files using default settings.

I successfully evaded detection of vdmallowed.exe by encoding a portion of the data section: f:\peCloak.py -e .text,.data:50:200 vdmallowed.exe

McAfee AntiVirus Plus (Disqualified)

This product did not detect any of the uncloaked malicious test executables despite having up-to-date signatures and exhibiting no errors before or after the scan. This may not be indicative of its normal behavior and as such it was disqualified from further testing.

pecloak17

ESET NOD32 Antivirus (Evasion: 3/3, 1 N/A)

This product did not detect the unencoded version of vdmallowed.exe file but did detect the other three as malicious.

pecloak11

I successfully evaded detection for strings_evil.exe using default settings. I successfully evaded detection for both av_test_msfmet_rev_tcp.exe and av_test_msfshell_rev_tcp.exe by encoding a portion of the .rdata section on each:

peCloak.py -e .text,.data:17000:1500,.rdata:50:500 av_test_msfmet_rev_tcp.exe

peCloak.py -e .text,.data:16000:50,.rdata:50:500 av_test_msfshell_rev_tcp.exe

pecloak13

Successful evasion of one of the Metasploit payloads

Kaspersky Anti-Virus 2015 (Evasion: 4/4)

This product successfully detected all four uncloaked test files.

I successfully evaded detection for strings_evil.exe and vdmallowed.exe using default settings.

pecloak14

I successfully evaded detection for both of the Metasploit executable files by encoding a portion of the .data section on each:

peCloak.py -e .text,.data:500:10000 av_test_msfmet_rev_tcp.exe

peCloak.py -e .text,.data:500:10000 av_test_msfshell_rev_tcp.exe

Comodo Free Antivirus (Evasion: 3/3, 1 N/A)

This product did not detect the unencoded version of vdmallowed.exe file but did detect the other three as malicious.

pecloak15

All three of the remaining files were successfully cloaked using the default peCloak settings.

pecloak16

Successful evasion of one of the Metasploit payloads

Spybot 2.4 Free Edition (Disqualified)

Similar to McAfee, this product did not detect any of the uncloaked malicious test executables despite having up-to-date signatures and exhibiting no errors before or after the scan. Even worse, it actually automatically whitelisted strings_evil.exe! This product was disqualified from further testing.

pecloak18

Bitdefender Antivirus Free Edition (Evasion: 2/4)

This product successfully detected all four uncloaked test files.

pecloak19

Two of the files (vdmallowed.exe and strings.exe) successfully evaded detection with default peCloak settings.

I was not able to evade either Metasploit executable, even with all PE sections encoded (and the file rendered inoperable) indicating signature detection was likely resulting from the contents of the file header, so no additional evasion was attempted.

BullGuard Antivirus (Evasion: 2/4)

This product successfully detected all four uncloaked test files.

pecloak20

Two of the files (vdmallowed.exe and strings.exe) successfully evaded detection with default peCloak settings.

I was not able to evade either Metasploit executable, even with all PE sections encoded (and the file rendered inoperable) indicating signature detection was likely resulting from the contents of the file header, so no additional evasion was attempted.

Malwarebytes Anti-Malware Free (Evasion: 2/2, 2 N/A)

This product did not detect the unencoded versions of the vdmallowed.exe or strings_evil.exe files but did detect both Metasploit stand-alone executables which were successfully cloaked by encoding a portion of the .data section.

peCloak.py -e .text,.data:50:500 av_test_msfmet_rev_tcp.exe

peCloak.py -e .text,.data:50:500 av_test_msfshell_rev_tcp.exe

Panda Antivirus Pro (Evasion: 3/3, 1 N/A)

This product did not detect the unencoded version of strings_evil.exe file but did detect the other three as malicious. I successfully evaded detection for vdmallowed.exe using default settings. Both Metasploit stand-alone executables were successfully cloaked by encoding a portion of the .data section.

peCloak.py -e .text,.data:50:500 av_test_msfmet_rev_tcp.exe

peCloak.py -e .text,.data:50:500 av_test_msfshell_rev_tcp.exe

pecloak22

Trend Micro Antivirus + Security (Disqualified)

This product did not detect any of the uncloaked malicious test executables despite having up-to-date signatures and exhibiting no errors before or after the scan. This may not be indicative of its normal behavior and as such it was disqualified from further testing.

pecloak23 pecloak24

Conclusion

What does this all mean? Well probably nothing you didn’t already know — AV detection is flawed. At the same time, so many organizations seem to put a lot of stock in the use of AV and while I wouldn’t advocate throwing it away entirely, it certainly shouldn’t be thought of as an absolute control.

Also, as we continue to hear about all of these “advanced” attacks that used “sophisticated” malware that went undetected, you have to wonder how advanced were they really? … especially if one can easily hide a known malicious binary so easily?

At the very least, I think I supported my hypothesis and this little experiment has demonstrated that if you’re faced with needing to bypass AV detection for a penetration test, developing your own method may not be that difficult after all.

Until next time,

Mike

EggSandwich – An Egghunter with Integrity

Written on:February 12, 2015
eggsandwich6

Introduction A while back I introduced the EggSandwich in my tutorial on Egghunting as a means to implement some basic integrity checks into the traditional Egghunter and overcome the problem of fragmented / corrupted shellcode. I recently took the opportunity to update my implementation so it could accomodate shellcode of any size. The code and a brief explanation follows. What is the EggSandwich? I ran into a situation when developing an exploit for an…

Read more...

Developing a Security Assessment Program

Written on:December 19, 2014
appsec_process_04

Introduction Most organizations and are deploying new applications and technologies at a high rate and without a means to adequately assess them prior to implementation, it’s difficult to accurately gauge your organization’s risk. No matter what the size or industry, it’s imperative that an organization has a standardized and repeatable process for assessing the security of the IT solutions it implements.  My goal with today’s post is to provide some recommendations on…

Read more...

Exploiting MS14-066 / CVE-2014-6321 (aka “Winshock”)

Written on:November 29, 2014
ms14066_36

Introduction I think enough time has passed now to provide a little more detail on how to exploit MS14-066 schannel vulnerability (aka “Winshock”). In this post I won’t be providing a complete PoC exploit, but I will delve into the details on exactly how to trigger the heap overflow along with some example modifications to OpenSSL so you can replicate the issue yourself. This vulnerability was announced while I was on…

Read more...

Windows OLE RCE Exploit MS14-060 (CVE-2014-4114) – Sandworm

Written on:October 22, 2014
ms14_060_2

This recent exploit (dubbed “Sandworm”) took advantage of a vulnerability in which a specially crafted OLE object could allow remote code execution. In the case of the live sample exploit PPSX file I examined, it automatically downloaded the payload from a remote SMB share. I won’t rehash much of the details that others have covered but if you want to read more, here are some resources: Microsoft Security Bulletin: https://technet.microsoft.com/en-us/library/security/ms14-060.aspx Original Discovery by…

Read more...

Drupal 7 SQL Injection (CVE-2014-3704)

Written on:October 17, 2014
drupal_sqli_5

Introduction This vuln has been getting a lot of attention, and rightfully so. The good news is an update is available (and a supplemental patch has been released as well). The bad news is that it’s pre-auth SQLi. The basic problem is the way Drupal core 7.x versions prior to 7.32 construct a SQL query. Contrary to some claims, this is not a flaw in the use of prepared statements/parameterized queries, which…

Read more...

Phishing for Shellshock

Written on:October 10, 2014
phishing_shellshock_1

Introduction I thought I was done writing about Shellshock, but a recent discussion with some colleagues got me back on the topic. We were commenting about how organizations tend to react very quickly to patching external assets for a bug like Shellshock but many probably wait to patch internal assets due to a false sense of security. It got me thinking about how an external actor could exploit a bug like…

Read more...

Shellshock – Targeting Non-CGI PHP

Written on:September 30, 2014
shellshock_php_0

I’ve seen debates as to whether or not it’s possible to have an unpatched PHP server running in mod_php mode (i.e. not CGI) that is vulnerable to Shellshock. From my testing, the answer appears to be Yes…with some prerequisite conditions. First, the PHP application would have to be using Bash for its system commands — exec(), passthru(), system(), popen(), etc. This is pretty obvious since Shellshock is a Bash-specific vulnerability. Although PHP system command…

Read more...

The Search For Shellshock

Written on:September 28, 2014
shellshock_2

Introduction By now there are hundreds or even thousands of posts and articles about the Bash “Shellshock” vuln and more will be written tomorrow (and the next day …). With that in mind, this post will be fairly short and I won’t be rehashing what shellshock is or why it’s a problem. For that you can simply Google “shellshock” and you’ll find all you wanted to know and more. If you want…

Read more...

Why Google Makes My Job More Difficult

Written on:September 23, 2014
google_13

Let me start this post by saying I’m a huge Google fan. I use multiple Android devices and like many others, I’ve become an avid user of services such as Gmail, Docs, Maps, Photos, and Youtube. I even find myself fondly reminiscing about discontinued services such as Reader. And, if you’re like me, Google search has become an instrumental tool in your professional endeavors. So please keep in mind, this post is…

Read more...