23 July, 2013
This blog post is a proposal for a new SNORT®/Suricata keyword "
xbits" that could change
how IDS signature developers approach detection of exploits that cross multiple streams. Today,
in both Snort and Suricata, it is possible to build up a state machine out of a set of related
signatures with the
flowbits keyword in order to
track how an exploit progresses through a vulnerable application layer protocol. This is an important feature, and is used in many
standard Snort signature sets - as of this writing it is in about 6% of all active Snort rules
in the
Emerging Threats rule set.
However, flowbits has an important limitation: it can only
apply within single TCP connections or single UDP conversations (forward and reverse flows). So, it is not
possible to set a flowbit on one TCP connection and then test whether this flowbit is set in a
completely separate connection. This limitation represents an opportunity for innovation, and
it is my belief that this shortcoming partially helped to fuel the demand for products offered by
SIEM vendors (more on this below).
flowbits Example
First, let's see an example of flowbits usage within two Snort signatures - this comes from the online
Snort manual. The following Snort signatures (or "rules"
if you like) show a basic example of tracking the IMAP protocol and generate an event for
the IMAP "LIST" command but only after a successful login:
alert tcp any 143 -> any any (msg:"IMAP login"; content:"OK LOGIN"; flowbits:set,logged_in; flowbits:noalert;)
alert tcp any any -> any 143 (msg:"IMAP LIST"; content:"LIST"; flowbits:isset,logged_in;)
So, the first signature sets the flowbit "
logged_in", and then the second tests whether this flowbit
has been set on the same TCP connection along with the "LIST" content match. Note the "noalert" modifier suppresses the alert from the first rule
and triggering it merely signals internally to Snort that a necessary precondition for the
second signature has been met. It is the second signature that causes an alert to be generated
if it is triggered. Note also that the "
logged_in" flowbit is set on traffic returned to the
client from the IMAP server vs. the "
isset" criteria which tests the logged_in flowbit in the second
rule on traffic coming from the client. This illustrates the ability of flowbits to place match criteria
on communications emanating from both sides of a connection.
Why is flowbits useful?
flowbits is important because it allows the signature developer to let network traffic progress
in a natural way and have Snort/Suricata track it as it unfolds. It lets sets of signatures work
together as group for more reliable exploit detection, and there are plenty of exploits that can be
detected using the current flowbits implementation. However, what types of exploits are missed because
flowbits cannot apply across multiple TCP connections? Put another way, would detection of
malicious traffic be significantly improved with a cross-stream flowbits keyword?
A New Keyword: xbits
The proposed
xbits keyword would function as follows:
- Fundamentally, an xbit could be set on one TCP connection or UDP conversation, and tested in
a different connection or conversation. This would require a different interface to the stream
tracking portions of Snort and Suricata than currently implemented by flowbits.
- All xbits semantics would match those in flowbits for existing flowbits modifiers such as
set, unset,
noalert, etc.
- xbits would offer a new modifier "track" that accepts arguments "ip_pair"
(to associate xbits by pairs of IP addresses), and "expire" (to allow xbits to be cleared
automatically after a specified number of seconds).
This blog post is not to say that existing Snort rules that use flowbits don't work properly, or that flowbits
is fundamentally flawed. Rather, in some cases these rules could be made more reliable and harder to evade
with the proposed xbits keyword. It is the
sequence of connections that look a certain way that is
important, and xbits tries to promote this concept directly into the Snort signature language. Without xbits,
the information conveyed by such sequences is lost. One could imagine other cases where having xbits
would be useful such as:
- Use of a compromised system after successful exploitation. An attacker sends an exploit
against a system where the exploit itself is difficult to detect, but following the exploit connection
a new successful connection is made to a backdoor port that the exploit forces the compromised system to
open (or a connect-back shell can be initiated the other
way - the detection rules can be written to take either scenario into account). If the exploit itself
can only be described by a signature that may also produce unacceptably high rates of false positives on legitimate
traffic, then xbits provides an alternative since this rule never has to trigger any alert at all. Only
the use of the compromised system after successful exploitation causes an alert.
Now, why not just have a signature that triggers on every connection to the backdoor port?
Well, sure, but if xbits existed then a set of higher confidence signatures related together by xbits
can be created for the same thing. Once again, the sequence of communications contains
information that is important for better exploit detection. Further, nothing prohibits both strategies
from being used simultaneously; existing non-xbits signatures can be used at the same time.
- Better detection of Metasploit traffic, and by extension better detection of sophisticated
adversaries. Here are a few examples of Metasploit modules that require multiple streams for successful
exploitation:
- SCADA 7-Technologies IGSS Rename Overflow
- Apache ISAPI DoS
- ContentKeeper Web Remote Code Execution
There are many more modules that require multiple streams, and here is a quick way to identify those that
may fall into this category (requires additional investigation). We just look for calls
to connect(), connect_udp(), and send_request_cgi():
$ git grep -c "^[[:space:]]*connect" modules | grep -v ":1" | wc -l
125
$ git grep -c "send_request_cgi" modules | grep -v ":1" | wc -l
154
- Detection of network trickery that by its nature requires multiple streams. How about
detecting SSH connections that have been authenticated with Single Packet Authorization?
In this case, one needs a way to trigger an alert if a base64-encoded blob of data goes to UDP port 62201
followed closely after this by an SSH connection to the same system. Note that there are many ways SPA
can deployed where this technique would not be effective
(port randomization,
SPA packet spoofing, sending
SPA packets over Tor, and more), but still
it is useful to consider how xbits could be applied to detect styles of communications that can't easily
be expressed with current Snort/Suricata signature languages.
Metasploit Example
Let's examine the
ContentKeeper Web remote code execution
exploit mentioned above in a little more depth, and show how xbits can offer a detection alternative. This
exploit attempts to escalate privilege and execute code as either the Apache or root user on the webserver
as follows:
- Check for a vulnerable version of ContentKeeper by looking for a '500 Internal' error in response to
issuing an HTTP request to /cgi-bin/ck/mimencode as seen
here.
This is an optional step (part of the Metasploit check() function for this exploit), but is generally a good idea
since the Metasploit user probably does not want to upload a payload to a patched
version of ContentKeeper (and thereby needlessly expand their own risk).
- Upload a base64-encoded perl script payload via an HTTP POST to the ContentKeeper webserver. Due to the
vulnerability, the payload overwrites a specified file in the webserver filesystem. This connection
is made to /cgi-bin/ck/mimencode as seen
here.
- Wait three seconds after the HTTP upload connection is closed.
- Connect to the webserver via an HTTP GET and execute the uploaded payload script via /cgi-bin/ck/<script>.
This step can be seen
here.
In the context of this post, the important thing to note about the exploit steps above is that two separate
HTTP connections are required - one to upload the payload via an HTTP POST, and the second to execute the
payload via an HTTP GET. These two requests are required for exploitation regardless of whether the
reconnaissance check is made in step one, though in our example rule set below we'll assume the recon check
is issued as well. With the xbits keyword, the following signatures can detect this pattern of communications:
- Set xbit "Metasploit.ContentKeeper.recon" on initial HTTP connection in Metasploit step 1 above. Track by ip_pair.
- Test "Metasploit.ContentKeeper.recon" xbit with 'isset' and if it matches, then set
xbit "Metasploit.ContentKeeper.recon_status_is_vuln" on '500 Internal' webserver response. Track by ip_pair.
- Look for an HTTP POST that uploads the base64 encoded perl script and test "Metasploit.ContentKeeper.recon_status_is_vuln" xbit.
If this xbit is set, then set xbit "Metasploit.ContentKeeper.payload_uploaded" and track by ip_pair.
- Look for an HTTP GET to /cgi-bin/ck/ and test the "Metasploit.ContentKeeper.payload_uploaded" xbit. If
it is set then generate an event "Metasploit ContentKeeper Web remote code exec".
The complete example rule set can be downloaded
here.
Obviously these won't run properly in Snort or Suricata until xbits is actually implemented. In
this rule set a number of trade offs have been made such as: looking for the recon '500 Internal' error check,
tracking by IP pair for the recon check and the exploit step, tracking by IP pair between the payload
upload connection and the exploit connection, and allowing xbit values to expire after 30 seconds (see
the xbits "
track" criteria). The attacker is always free to slow things down and not use the same IP pair
across each of these connections and still gain successful code execution. But, the attacker may not utilize
different source IP's across these connections, and if not then the pattern above becomes a highly reliable
indicator of a successful attack. Further, as mentioned previously, individual non-xbits rules
can be deployed at the same time to catch each step by itself as well.
The SIEM Connection
At its core, xbits allows the IDS engine to process network traffic such that associations are
made among groups of signatures in a manner that is not restricted to single TCP connections or UDP conversations.
There is much analogous precedent for this concept in the SIEM world. SIEM vendors commonly allow security
alerts to be built up from multiple independent sources of information such as syslog data, firewall logs,
IDS events, webserver logs, netflow data, and more. A good example is "
send an alert if source IP a.b.c.d
triggers a port sweep event in my IDS, followed by SQL errors via my webserver, followed by a connection
initiated back from the webserver to IP a.b.c.d". Having the SIEM automatically trigger an alert
based on all of these events coming together in the specified order is far more valuable than
trying to arrive at the same result through manual interpretation of each indicator by itself
(which isn't practically possible for any decently large network).
This doesn't mean the raw event data is turned off or thrown away - far from it. The event
data is simply processed by the SIEM in a way that gives priority to the sequence of events
without necessarily caring about the sources of the events themselves (firewall log, etc.).
Making an analogy to Snort/Suricata, the absence of xbits would be like a SIEM that could only
generate an alert based on looking at one event source at a time. I.e., SSH brute force
attempts logged via syslog could not be correlated with, say, a port sweep event from an IDS.
Further, in the absence of xbits, in the Metasploit example above a set of regular Snort rules
could be deployed to detect each stage of the Metasploit traffic individually and log this data
to a SIEM. From there, the SIEM itself could implement the same logic as xbits does - i.e.
generate an alert if the raw events come together in the same sequence as what the xbits rules
require. Given that this style of matching is useful, why not implement such a capability within
the Snort signature language directly?
Performance?
The implementation of xbits would certainly impact performance, and this may be one reason
neither Snort nor Suricata have developed something similar. However, some portion of xbits
is clearly possible to implement with a reasonable set of constraints. These constraints may
include limitations on the maximum number of xbits, enforcing a maximum amount of time that
a set xbit is allowed to remain set, or limiting the number of comparisons that a signature
is allowed to trigger for checking whether an xbit is set. It is my belief that a workable
performance level could be achieved for many deployments of Snort/Suricata.
What About Shared Object (SO) Rules?
The whole point of binary
shared object (SO) rules
is to allow the signature author to alter the
detection capabilities offered in the standard Snort signature language. However, implementing
an SO rule is significantly more complex than just writing a regular Snort rule for most
signature authors. If the concept of xbits could improve the detection landscape, then it
would be desirable to have it built directly into the signature language itself where it is
more accessible and readily applied to real world network traffic.
Why Not Just Extend flowbits?
Instead of creating a new Snort/Suricata signature language keyword, why not just extend flowbits
so that it can apply to multiple transport layer conversations? Because maintaining backwards
compatibility with existing Snort rule sets would become difficult and error prone. Matching
across mutiple conversations is such a fundamentally different model that it would be better to
clearly differentiate this capability with a new keyword.
Conclusion
This blog post proposes an extension to the Snort/Suricata signature language to allow those
IDS engines to detect malicious traffic that crosses multiple streams. Attackers do not limit
themselves to traffic patterns that must stay within a single transport layer conversation, and
neither should standard intrusion detection engines. One only needs to look at the Metasploit
project for excellent examples of exploits that span multiple streams. For the record, I had
proposed this idea on a panel discussion with
Ron Gula
and
Marty Roesch at the
SANS "
What Works in Incident Detection and Log Management Summit" in 2010. At the time I
didn't use the "xbits" name, but (to me) writing up this blog post has solidified xbits as a
decent name for the concept.