Michael Rash, Security Researcher

Crossing the Streams in IDS Signature Languages

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:

  1. 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.

  2. 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
    $ git grep -c "send_request_cgi" modules | grep -v ":1" | wc -l

  3. 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:

  1. 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).
  2. 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.
  3. Wait three seconds after the HTTP upload connection is closed.
  4. 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:

  1. Set xbit "Metasploit.ContentKeeper.recon" on initial HTTP connection in Metasploit step 1 above. Track by ip_pair.
  2. 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.
  3. 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.
  4. 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?


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.


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.