Saturday, September 10, 2016

Extrabacon's Sploit Framework 1: Static Analysis


Sploit is the modular core that runs the EXTRABACON exploit in the (supposed) Equation group tool dump. While everyone is focused on the news of the 0-days, the recent porting of this old exploit to newer ASA versions (http://www.securityweek.com/leaked-cisco-asa-exploit-adapted-newer-versions) I chose to look at the underlying structure. First because there are already a number of talented researchers covering every angle of each exploit in greater detail than I could.


Second because the hidden jewel that is the Sploit framework deserves some attention as well. As a quick aside, and on an opinion level I do not believe this dump is in fact what it claims to be. Certain traces left through the code appear, at least to me, to be intentionally placed to point at the American government. When dealing with any code of unknown origin it pays to reject the easy conclusions. The tools are definitely genuine hacker warez, and may even be from the supposed Equation Group. But, I still believe these files have been altered to make that point blatantly clear. For example, some of the hard-coded I.P. addresses point back at publicly-listed government servers. Come on now, even skids know better than that. Now back to the fun stuff....the tech.

Over the next few posts I will describe my analysis of the Sploit framework. I will also include my work on incorporating and extending Sploit in future versions of Rellik. In this first post I will be going over the static (white-box) analysis.

First let's look at the motivation for the tool and what exactly it appears designed to do. The EXBA directory has 1 file named extrabacon_1.1.0.1.py and 3 folders – Mexeggs/, scapy/, and versions/.

I will cover what is in these in a minute. In addition to these, there is a text file describing how to deploy the exploits: EXTRABACON.txt . From this document we can see the tool is used for detecting, exploiting, and spoofing traffic on Cisco ASA devices over SNMP.

The extrabacon_1.1.0.1.py file is actually a good guide to the algorithm of exploitation. At a high level it fingerprints the device it is targeting, and tries to match it's version to an exploit in the versions/ directory. It looks up the shellcode bits from the appropriate python file and then builds a payload. The payload can change the authentication mode from either “pass-disable” or “pass-enable” to bypass or re-enable admin authentication.

The scapy/ directory appears to be a local copy of the scapy lib. I have not compared these files to original source yet, but intend to do so before testing any of the code under this directory (for obvious reasons). Looking at the rest of the code though, it appears to be used in the typical packet manipulations you'd expect to see from scapy.

Under the versions/ directory is a list of python based exploits aimed at different versions of the ASA firmware. They are essentially the modules that are used to construct the actual shellcode exploits. Each is tagged by a specific version it targets (for example ver=”asa802”). When we move on to discussing porting the tool I will dive into the structure of an exploit in more detail.

Finally, the Mexeggs/ directory. This is the custom bits of framework that makeup the core of the exploits. 
  • __init__.py – Your standard Python Module entry point. Empty in this case.
  • all.py – imports the Sploit module and the Version module. Appears to be for convenience.
  • argparse.py – From the code “This module is an optparse-inspired command-line parsing library”.
  • hexdump.py – Defines two methods to help sanely print byte dumps. The two methods are:
    • hexdump(x,lead="[+] ",out=sys.stdout) – dump cleaned up hex to stdout or other pipe
    • sane(x) – used by hexdump to prettify values of x
  • log.py – Extension of the loglib.AbstractLog class made to speed logging packets
  • loglib.py – This one is covered in more detail below.
  • sploit.py – This is also covered in more detail below
  • version.py – Builds a DictionaryOfTuples object filled (from a file verinfo file ). Covered in more detail below

Examining sploit.py

When you look at the Extrabacon class definition it extends a Sploit object. So let's examine what a general Sploit consists of. The file holds several core classes which are quick access to communication commands. There are several helper methods for parsing addresses, ports, etc. here is the overall list of Classes and helper functions:

The Subcommand class is the core for the next few child classes so I will cover it quickly. Each subcommand has special use cases that one might want fast access to when deploying an exploit. By adding a custom child of the Subcommand class you can add a menu option to control when the subcommand is activated in the setup_parse. You can also define what code runs to execute the SubcommandIt defines three methods that can be overridden. 

The BurnSubcommand class is for deleting keys from the exploit's key dir. It adds the –all and –Burn options to the menu. It saves the boolean True under the burnburn variable to delete all the keys. Most likely a post-exploitation cleanup or panic feature.

ExecSubcommand is called for that actual exploitation. It takes the file containing the chosen payload and they key data. The code then calls, in order, the exp.load_vinfo(), exp.pre_exploit(), and exp.send_exploit() functions (where exp is the exploit object passed in the parameters). When extending this framework later we will want to make sure we define these method (or at least stub them out). This is not an unfamiliar style of exploit modularization. If you are familiar with the routersploit project from reverse-shell they use a similar check-then-exploit model as detailed here https://github.com/reverse-shell/routersploit/wiki/Creating-Exploit. It seems to me that porting exploits between the two should be possible if not fairly easy.

PseudoSocket and FragmentedPseudoSocket are similar to each other. They both use the socket module's functions to lookup connection details to a given I.P. Address and port. It then uses the results to try to open a connection. The send() command for both takes a packet object as input. This is where they really start to differ. The PseudoSocket sends the packet object as a string in a single shot. This is good for direct communication channels, but on bandwidth-restricted networks or when you want to redirect the packets, you want to send this data in pieces. That is the case for using the FragmentedPseudoSocket class, which opens a streaming socket and begins to send fragments of a configurable size. During the call to Sploit.create_socket() This is set with the exploit's --redirect or --spoof parameters are present. Otherwise the PseudoSocket is used. According to the code:
The --redirect option requires 5 fields as follows outbound_tunnel_local_ip:outbound_tunnel_local_port:return_tunnel_remote_ip:return_tunnel_remote_port:listen_port.
The --spoof option requires 3 or 4 fields as follows redir_ip:redir_port:spoofed_ip[:spoofed_srcport]”

As you can also see from the above snippet of Sploit class code, the default fragment size for FragmentedPseudoSocket is set in Sploit.DEFAULT_FRAGMENT_SIZE (From the point of view of the Subcommand class that is). The hard-coded value in the code is 460 bytes. Each fragment is passed through the hexdump cleaner, optionally logged, and then sent along the socket. If you set the raw_send flag it will force the stream to create new connection's for each fragment. A useful feature for obscuring traffic details such as connection time, data stream size, etc.

The InfoSubcommand gets information from the infected system by calling the exp.send_touch() method. The underlying exploit defines exactly what happens here.

The ForceSubcommand is used for copying the key data from the exp.params.key_data section to the exp.key_data variable.

Finally the moment I have been building towards. The Sploit class is the skeleton (or the definition of the structure) of an exploit we can pass through the framework. 

That is a lot to cover, but luckily a good portion of it is intuitive. Without much investigation you could probably guess what get_key_file() or pre_exploit() are meant to do. One variable in the initialization method appears to be a nod towards another Exploit Platform SecondDate. The terminateFlingOnException parameter is set to False by default. The other class data holds information about the environment, the user based parameters, the log object, the subcommands that are defined for the exploit, etc. The parser variable holds the opts list that is configured based on the subcommand settings for the exploit being run. The value for this is filled out when Sploit.setup_parser() is called. It is the result of calling the submodule.setup_parser() function under each configured submodule.
The description() function returns a string with the exploit name and version number. The create_socket() function was detailed above (under the section on FragmentedPseudoSockets). By default the pre_parse() funtion does some environmental variable setup. Specifically:It sets the program's name, base file name, and real file path. This can be overridden in extensions to provide whatever functionality you would like run prior to any interaction. The post_parse() Function runs after the main and Subcommand options have all been parsed. It's seems most useful for error-checking the inputs since that is what the Sploit class appears to do as well. However, It isn't required, and none of the previously mentioned Sumcommands have used it.
There are two methods for setting up the menu options related to communication and logging. They are add_connection_params() and add_logging_params() respectively. There are others for handling key information and other core tasks that I wont really dive into here. Next are the run() vs. launch() functions. Essentially, The launch() Function is for exploits that use one or more Subcommands to function. Sploit-based classes that don't use Subcommands instead need to override the run() method.You can still call launch() on a Sploit extension class that uses the run() model since launch() defaults to calling run() if no subcommands are found.

The send_touch() function probes an external system via a user defined SNMP packet. You must define a generate_touch() function which returns a valid data string to be sent across the exploit PseudoSocket or FragmentedPseudoSocket (exsock) as a packet. The function then calls the post_touch() function. The post_touch() function can contain any code you may want run directly after a touch_command().

At last, we get to the actual exploit related functions. This happens in 4 stages: Pre-Exploitation, Exploit Generation, Exploit Delivery, and Post Exploitation. When using a Subcommand like the BurnSubcommand() the pre_exploit() and send_exploit() methods are called from within the run() method. If you choose to write an exploit without Subcommands you will need to call these when you overide the run() method. Inside the call to send_exploit() is a call to generate_exploit() which is a custom function for each exploit, that is expected to return the code needed to be sent across the socket to perform the exploitation. You can override this behavior by supplying a list of packets to be sent in the call to send_exploit() I will dive into this in a future post on porting the framework and creating a working exploit in it. If the exploit expects a response (set in the exploit parameters and the socket object.), the code does some logging and calls the post_exploit() function. By default this code checks the response can be cast as an SNMP object. If it can and verbose is set it will show the SNMP response and possibly (depending on the verbosity level) run it through the hexdump class and print that as well.

The last bit of this class has to do with checking that the exploited system is still functioning. This is the perform_healthcheck() related functions. It is an internal method used (if configured in the exploit params) in send_exploit() after sending the actual exploit packet (and possibly waiting for a response). The first check looks to see if a simple TCP healthcheck port has been configured. If not it jumps into an SNMP specific routine. It creates another SNMP packet with the oid of 1.3.6.1.2.1.1.3.0. and uses that to confirm the device is still responsive.

What is an OID you ask? I didn't know off the top of my head either so I looked it up. The quick overview is
SNMP Object Identifiers (OIDs) point to network objects stored in a database called the Management Information Base, often referred to as the "MIB". A MIB holds the structure of the network alarms being monitored”

So far, this class holds the most assumptions about the type of exploitation being performed. It will be easy enough to make part of an exploit to open a specific TCP port that would respond when the system is up, or simply ignore the health check parameters altogether when not using the SNMP exploits, but I would rather look at abstracting this function like the rest of the configuration and exploitation options. That way each exploit may have it's own concept of a heath check algorithm.

Examining loglib.py

This file gets special attention because it has some interesting tidbits. I won't cover ever function in detail (most are not really interesting anyway). First is the initialization method of the AbstractLog class. You can tell the structure was meant to allow for easier log aggregation based on ToolProjectName and ToolProjectVersion as well as custom fields. Here is the constructor:
__init__(self, ToolProjectName, ToolProjectVersion, ToolName=None, ToolVersion=None, options={}, params={})
The initialization also includes some interesting defaults configured as well:


The D:\\ caught my eye since, until I saw that, I assumed this would have been run under a *nix distribution. It could be designed for a specific dual-boot architecture. I have seen this before when looking at scripts to help with Forensic investigation. This technique gives the operator 'the best-of-both-worlds' in terms of tools. The Prefix 'concernedparent' also made me chuckle. I will leave it to you to imagine how or why that was chosen. Another interesting function of the loglib is to function as a threaded Heartbeat Generator (called a pacemaker) for deployed exploits. Here is the code:
We can see that, at the time, this required access to Win32 libraries and functions. This definitely suggests it was designed to be cross-platform with deployment handled in *nix and monitoring done from the Windows side of things.

Examining version.py

The version.py script builds a Dictionary of Tuples from a file. It is interesting because it is imported in the extrabacon_1.1.0.1.py via the Mexeggs.all import statement, but the class itself doesn't appear to be used anywhere in this code. Whats more, the construction of the Dictionary happens in what I consider to be an insecure method.

See that line where tuples = eval(...)? That equates to running unfiltered python code from a file. A specially crafted file passed in through the filename parameter could be used to corrupt the underlying system.

That is all for the first phase white-box analysis of the underlying exploitation architecture. You can see how it aids in the rapid development and deployment of remote exploits. More than just SNMP exploits can be deployed. In fact any exploit you could deploy over a network socket could be used. I will dive into that topic more by porting an exploit from a different framework into this one.

No comments:

Post a Comment