Crossing the Streams in IDS Signature Languages
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).
- 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.
- 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 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?