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