Thursday, February 4, 2010

Introduction to the Shared Object Rules Generator

This is the first of a series of blog posts about writing Shared Object (SO) rules for snort. Not a lot of documentation exists as yet about how SO rules work or how to write them, and honestly this particular post isn't going to cover a lot of that information directly. Instead, we're going to go with an approach more akin to throwing everyone into the deep end of the pool but with a nice, big inflatable raft. This inflatable raft is the SO Rules Generator, which takes care of most of the grunt work setting up an SO rule and lets you focus on writing the actual detection code. Actual documentation of Shared Object rules, how they work, and how to write them will be covered in a series of blog posts in the near future.

Without any further ado, here's the link -- http://labs.snort.org/cgi-bin/sorules.cgi (This link is also found under "Web Tools" on http://labs.snort.org).

The sparse directions on the Generator page simply say "Paste regular Snort rule into the text box and click Submit. The Shared Object equivalent source will be displayed below the box." Let's expand upon that a bit, shall we?

To start with, let's create a very simple detection that is merely a conversion of a regular snort text rule turned into C code. For this example, we're going to look for TCP traffic to port 4444 that contains the ASCII strings "MESG", "NAME", and "DATA".
alert tcp $EXTERNAL_NET any -> $HOME_NET 4444 (msg:"MISC Intro to SO Rules Generator Example 1"; 
flow:to_server,established; content:"MESG"; content:"NAME"; content:"DATA"; classtype:misc-activity; sid:64500;)
Run that rule through the generator, and paste the results into a file named misc_intro-to-so-gen-1.c. Parts of the naming convention are important. Obviously, the .c is to show it's a C source file, but the "misc_" tells the SO Rules Makefile that the file is to be compiled into the misc.so shared object that will be loaded by snort. So, drop that file in with your other SO Rules, run `make`, and make sure your SO rules are loaded by snort complete with the generated .rules files.

Run snort on this pcap using the -r option, and you get the following alert (packet data removed) --
01/22-09:48:21.146371  [**] [3:64500:1] MISC Intro to SO Rules Generator Example 1 [**]
[Classification: Misc activity] [Priority: 3] {TCP} 192.168.36.1:43809 -> 192.168.36.130:4444
Now, for the next step, we're going to perform a very simple test using C. I've decided that I'm going to stay with my original example, even though I figured out a cooler way to perform this test using a regular snort text rule and blogged about it here. For this test, we are going to extract the four-byte size field after the DATA tag and alert if there is additional data present in the payload. Full details of this "vulnerability" are given in the previously linked blog post.

The changes to the original code are simple: calculate the end of the payload, extract the size field, and see if there are more bytes in the payload than specified by the size field --
// content:"DATA", payload raw, depth 0;
if (contentMatch(p, rule64500options[3]->option_u.content, &cursor_raw) > 0) {
-       return RULE_MATCH;
+
+      // Calculate the end of the payload
+      end_of_payload = sp->payload + sp->payload_size;
+
+      // Verify we have enough space to read the DATA size
+      if(cursor_raw + 4 > end_of_payload)
+         return RULE_NOMATCH;
+
+      // Read the size, big endian.  We can't just typecast the pointer
+      // because we don't know what endianess our device uses
+      data_size = *cursor_raw++ << 24;
+      data_size |= *cursor_raw++ << 16;
+      data_size |= *cursor_raw++ << 8;
+      data_size |= *cursor_raw++;
+
+      // Alert if our data_size doesn't take us to the end of the payload
+      if(cursor_raw + data_size < end_of_payload)
+         return RULE_MATCH;
}
All of the new code replaces the automatically generated piece for the last content match, where it just returns. Example 1, updated to add this new detection (and with a new sid so there is no conflict between the two examples) is available here.

This is just a simple example of what can be done with a shared object rule. Since it is written in C, there is literally no limit to what can be done. In the near future, we will be releasing much more complicated (and admittedly cooler ;) ) shared object rules on VRT Labs, which will of course be announced here on the blog. Please, give Shared Object rules a try and play with the SO Rules Generator. Brian Caswell has put a lot of great work into the generator and we use it extensively on the VRT to create the base file when writing some pretty slick detection routines.

If you have any questions or wish to share your experiences, please do so here in the comments section so others may benefit from the exchange. Or, you can reach me directly at pmullen@sourcefire.com.

I look forward to seeing what the community creates!


----------
The following payload was used with the above example rules.

Protocol structure:
MESG[Total size of all remaining data]
NAME[Size of Record Name][Record Name]
DATA[Size of Data][Data]

Size fields are four byte integers, big endian.

Packet payload:
00000000  4d 45 53 47 00 00 00 64  4e 41 4d 45 00 00 00 10  |MESG...dNAME....|
00000010  42 6c 6f 67 20 49 6e 66  6f 72 6d 61 74 69 6f 6e  |Blog Information|
00000020  44 41 54 41 00 00 00 1f  42 65 20 73 75 72 65 20  |DATA....Be sure |
00000030  74 6f 20 63 68 65 63 6b  20 6f 75 74 20 6f 75 72  |to check out our|
00000040  20 62 6c 6f 67 20 61 74  20 68 74 74 70 3a 2f 2f  | blog at http://|
00000050  76 72 74 2d 73 6f 75 72  63 65 66 69 72 65 2e 62  |vrt-sourcefire.b|
00000060  6c 6f 67 73 70 6f 74 2e  63 6f 6d 2f              |logspot.com/|
Add to Technorati Favorites Digg! This
Post a Comment