Friday, September 9, 2011

What is PAF?

Snort is constantly being updated to improve detection and/or performance to keep pace with the networks it monitors. The stream5 preprocessor was updated for 2.9.0 to perform stream normalization that enables better detection prior to acknowledgement of the data. In Snort 2.9.1 we further that effort with the addition of what we call Protocol Aware Flushing (PAF).

To understand PAF, we need to look at how TCP, the Transmission Control Protocol, is used to provide reliable communication between hosts. The basic idea with TCP is that a sequence of octets goes in one end and that exact same sequence comes out the other, nothing added, deleted, or otherwise changed.

The key here is that we are talking about a sequence. TCP knows nothing of how the data is structured or where one message ends and the next begins. That makes things interesting for Snort because, internally, TCP will slice an arbitrarily long sequence of octets into segments as it sees fit.

Consider this example where an HTTP client wants to send two GETs to a server (one packet per line):

GET /1 HTTP/1.0\r\n\r\n
GET /2 HTTP/1.0\r\n\r\n

Snort might see one packet per GET, but in the general case, especially where the payload is longer than the MTU, there will be multiple packets and Snort may see something like this:

TP/1.0\r\n\r\nGET /2

There are literally billions of ways to slice this little 38 character sequence, from one character per packet to both requests in a single packet. Historically, IDS evasion techniques used small TCP segments, and those were overcome by doing TCP reassembly within Snort. Without reassembly, rule contents would not reliably match.

Reassembling the accumulated data and releasing the associated buffers is called flushing. Prior to PAF, stream5 would flush when the number of segments and the number of octets accumulated reached certain thresholds. These thresholds were effective but ultimately a "one-size-fits-all" approach.

To take detection to the next level, the flush points had to be protocol specific and PAF allows the application preprocessors to determine when to flush. The first preprocessors to use this stream5 feature are http_inspect and dce2. In the example above, each GET request will be flushed separately, regardless of how it is segmented by TCP.

To enable PAF, add this to your snort.conf:

config paf_max: 16000

In our testing, using 16k has resulted in improved accuracy of detection. Larger values can improve detection but also increase packet processing latency and variance.

HTTP and DCE/RPC were the first choices based on traffic volume and complexity, respectively. Later releases of Snort will add PAF support for other protocols, and new preprocessors are being designed to use this feature.