Thursday, September 8, 2011

Flow matters

Recently on one of the Snort lists, there was a thread that argued that the "flow" statement in rules didn't matter if you had your variables set correctly.  This is a common misconception, so I thought I'd write a post about it and explain why flow, and its use in rules is important.

First let's talk about what flow is.  The Snort reference manual says:
The flow keyword is used in conjunction with TCP stream reassembly. It allows rules to only apply to certain directions of the traffic flow.
You can click on the link above to read all about the different flow operators there are, I'm not going to regurgitate them here.  But one thing to keep in mind, is that to_client and from_server are the same.  As are to_server and from_client.

Let's take four rules for example.  
alert tcp $HOME_NET any -> $EXTERNAL_NET $HTTP_PORTS (flow:to_server,established;) 
Simple.  Someone on your HOME_NET going to EXTERNAL_NET on a HTTP_PORTS specified port, and the client initiated the conversation. 
Example:  Someone going to "" or any Web site from your network outbound.

What about the opposite of that?

alert tcp $EXTERNAL_NET $HTTP_PORTS -> $HOME_NET any (flow:to_client,established;)
Again, pretty simple, someone went to a webpage, and now your rule is looking for the result of that action.  The webpage (or file, or whatever) is coming down to the browser from the server.
Example:  Someone went to "" and downloaded a malicious PDF.  You are not attempting to see if someone requested a ".pdf" as a download, (although you may do that to set a flowbit, see my post on resolving flowbit dependancies here), but you are looking for the actual PDF coming back down from the server. 
So, let's take our first example and flip the flow.  Remember, this is all assuming that you have HOME_NET and EXTERNAL_NET set, just like the email thread was implying.

alert tcp $HOME_NET any -> $EXTERNAL_NET $HTTP_PORTS (flow:to_client,established;)
So, traffic headed outbound from my network over HTTP_PORTS, but HOME_NET did not initiate the conversation.
Example:  Let's say someone sets their source port as 80, and then infiltrates your network through a connection that starts outside (the initial SYN packet was sent inbound to HOME_NET), you are looking for the traffic leaving your network headed back to that attacker who set his source port as 80.  Maybe they are exfiltrating the DOC files off of your network.
Finally, let's look at the opposite of example two above.

alert tcp $EXTERNAL_NET $HTTP_PORTS -> $HOME_NET any (flow:to_server,established;)
Traffic headed inbound to the network over $HTTP_PORTS but HOME_NET again did not initiate the conversation.
Example:  Again, let's say someone sets their source port as 80, and then infiltrates your network, this rule will look for the connections inbound to your network.  Let's say they are requesting a DOC file from your network.  Whereas the previous rule would look for the DOC file leaving, this rule will look for the initial request.
These are very simplistic examples, hopefully this post will help explain why flow is so important.  Variables tell Snort which direction the traffic is going (inbound or outbound of your network in the simplest of terms), flow tells Snort who is responsible for which aspect of the conversation (are you a server, or a client?).

Any further questions about Snort and it's operation should be directed to the Snort mailing lists.  The best place to get your questions answered.