Writing Snort Rules A quick guide Brian Caswell 2 The life of a packet through Snort’s detection engine 3 Writing Snort Rules • Figure out what is "bad" • Capture traffic that includes the "bad stuff" • Learn the protocol • Figure out why the "bad stuff" is bad • Write a rule • Test the rule 4 More process • • • • • • • • Rewrite the rule Test the rule Rewrite the rule Test the rule Rewrite the rule Test the rule Rewrite the rule Test the rule 5 Even more process • • • • • • • • Rewrite the rule Test the rule Rewrite the rule Test the rule Rewrite the rule Test the rule Rewrite the rule Test the rule 6 Rule Format - basic rule alert tcp 10.1.1.1 any -> 10.1.1.2 80 (msg:"foo"; content:"bar";) 7 Rule Format – Action alert tcp 10.1.1.1 any -> 10.1.1.2 80 (msg:"foo"; content:"bar";) • Tells snort what the rule does – In our product • alert pass – In snort • alert log pass activate dynamic – In snort-inline • alert log pass activate dynamic drop sdrop 8 Rule Format – Custom Actions • not supported in product ruletype suspicious { type log output log_tcpdump: suspicious.log } suspicious tcp 10.1.1.1 any -> 10.1.1.2 80 (msg:"foo"; content:"bar";) 9 Rule Format – Protocol • alert tcp 10.1.1.1 any -> 10.1.1.2 80 (msg:"foo"; content:"bar";) • Tells snort to look for a specific protocol • Acceptable protocols: – TCP – UDP – ICMP – IP 10 Rule Format - IP Address • alert tcp 10.1.1.1 any -> 10.1.1.2 80 (msg:"foo"; content:"bar";) • Examples 10.1.1.1 • duh 10.1.1.0/24 • 10.1.1.0 through 10.1.1.255 !10.1.1.0/24 • anything but 10.1.1.0 through 10.1.1.255 [10.1.0.0/24,10.2.0.0./24] • 10.1.0.0 through 10.1.0.255 or 10.2.0.0 through 10.2.0.255 ![10.1.0.0/24,10.2.0.0./24] • anything but 10.1.0.0 through 10.1.0.255 or 10.2.0.0 through 10.2.0.255 11 Rule Format - Port • alert tcp 10.1.1.1 any -> 10.1.1.2 80 (msg:"foo"; content:"bar";) • Examples: any 80 1:1023 • 1 through 1023 (inclusive) :1023 • less than or equal to 1023 10: • greater than or equal to 10 !53 • not 53 !53:100 • not 53 through 100 (inclusive) NOTE: NO PORT LISTS. 80,8080 IS NOT VALID!!!! 12 Rule Format - Direction • alert tcp 10.1.1.1 any -> 10.1.1.2 80 (msg:"foo"; content:"bar";) -> – From the first IP/Port to the second IP/Port <> • From either the first IP/Port to the second IP/Port OR • From either the first IP/Port to the second IP/Port 13 Rule Format - ... Oh yeah, variables var EXTERNAL_NET any var HTTP_PORTS 80 var SMTP_SERVERS 10.1.1.1 alert tcp $EXTERNAL_NET any -> $SMTP_SERVERS $HTTP_PORTS 14 Rule Format – Body • alert tcp 10.1.1.1 any -> 10.1.1.2 80 (msg:"foo"; content:"bar";) • • • • • • • meat of the detection capabilities key value pairs (key:value;) types of keywords meta-data Payload non-payload post-detection 15 Meta-Data keywords • Msg – msg:"my evil attack"; • Reference – reference:url,www.snort.org; • sid – sid:100000; • Rev – rev:100000; • Classtype (see classification.config) – classtype:attempted-recon; • Priority – priority:3; 16 Payload • Content – content:"foo"; • Nocase – content:"foo"; nocase; • Rawbytes – content:"foo"; rawbytes; • Depth – content:"foo"; depth:10; • Offset – content:"foo"; offset:10; • Uricontent – uricontent:"foo"; 17 Complicated Payload Options • • • • • • distance Within Isdataat byte_test byte_jump pcre 18 Broken Payload Keywords • Regex • content-list • rpc 19 Non-Payload options: • ack (TCP Acknowledge Number) – ack:0; • dsize (Packet Size) – dsize:>10; • id (IP ID) – id:10; • fragoffset (fragment offset) – fragoffset:0; • fragbits (IP fragment bits) – fragbits:MD; 20 More non-payload options • ttl (IP Time To Live) – ttl:1; • tos (IP TOS) – tos:30; • ipopts (IP option) – ipopts:lsrr; • flags (TCP flags) – flags:SF; • flow (TCP State) – flow:to_server,established; 21 Even more non-payload options: • seq (TCP Sequence Number) – seq:0; • ttl (IP Time To Live) – ttl:10; • window (TCP Window Size) – window:55808; • itype (ICMP Type) – itype:8; • icode (ICMP Code) – icode:0; 22 Even more non-payload options (again) • icmp_id (ICMP ID) – icmp_id:0; • icmp_seq (ICMP Sequence Number) – icmp_seq:0; • ip_proto (IP Protocol) – ip_proto:6; • sameip (Are the IPs the same) – sameip; • stateless (Not part of a flow) – stateless; 23 The complicated options • • • • • • distance Within isdataat byte_test byte_jump pcre 24 Distance content:”SITE”; content:”EXEC”; distance:0; 53 49 54 45 20 20 20 20 20 45 58 45 43 20 65 76 69 6C 66 6F 6F 0A SITE ilfoo. EXEC ev 25 Distance content:”SITE”; content:”EXEC”; distance:0; 53 49 54 45 20 20 20 20 20 45 58 45 43 20 65 76 69 6C 66 6F 6F 0A SITE ilfoo. EXEC ev 26 Distance content:”SITE”; content:”EXEC”; distance:0; 53 49 54 45 20 20 20 20 20 45 58 45 43 20 65 76 69 6C 66 6F 6F 0A SITE ilfoo. EXEC ev 27 Distance content:”SITE”; content:”EXEC”; distance:0; 53 49 54 45 20 20 20 20 20 45 58 45 43 20 65 76 69 6C 66 6F 6F 0A SITE ilfoo. EXEC ev 28 Within content:”SITE”; content:!”|0a|”; within:50; 53 49 54 45 20 20 20 20 20 45 58 45 43 20 65 76 69 6C 66 6F 6F 0A SITE ilfoo. EXEC ev 29 Within content:”SITE”; content:!”|0a|”; within:50; 53 49 54 45 20 20 20 20 20 45 58 45 43 20 65 76 69 6C 66 6F 6F 0A SITE ilfoo. EXEC ev 30 Within content:”SITE”; content:!”|0a|”; within:50; 53 49 54 45 20 20 20 20 20 45 58 45 43 20 65 76 69 6C 66 6F 6F 0A SITE ilfoo. EXEC ev 31 Within content:”SITE”; content:!”|0a|”; within:50; 53 49 54 45 20 20 20 20 20 45 58 45 43 20 65 76 69 6C 66 6F 6F 0A SITE ilfoo. EXEC ev 32 Isdataat content:”SITE”; content:!”|0a|”; within:50; 53 49 54 45 20 SITE 33 Isdataat content:”SITE”; content:!”|0a|”; within:50; 53 49 54 45 20 SITE 34 Isdataat content:”SITE”; content:!”|0a|”; within:50; 53 49 54 45 20 SITE 35 Isdataat content:”SITE”; isdataat:50,relative; content:!”|0a|”; within:50; 53 49 54 45 20 SITE 36 Byte Test content:" LSUB |22|"; content:"|22| {"; distance:0; byte_test:5,>,256,0,string,dec,relative; 31 20 4C 53 55 42 20 22 22 20 7B 31 30 36 34 7D 1 LSUB "" {1064} 37 Byte Test content:" LSUB |22|"; content:"|22| {"; distance:0; byte_test:5,>,256,0,string,dec,relative; 31 20 4C 53 55 42 20 22 22 20 7B 31 30 36 34 7D 1 LSUB "" {1064} 38 Byte Test content:" LSUB |22|"; content:"|22| {"; distance:0; byte_test:5,>,256,0,string,dec,relative; 31 20 4C 53 55 42 20 22 22 20 7B 31 30 36 34 7D 1 LSUB "" {1064} 39 Byte Test content:" LSUB |22|"; content:"|22| {"; distance:0; byte_test:5,>,256,0,string,dec,relative; 31 20 4C 53 55 42 20 22 22 20 7B 31 30 36 34 7D 1 LSUB "" {1064} 40 Byte Test content:" LSUB |22|"; content:"|22| {"; distance:0; byte_test:5,>,256,0,string,dec,relative; 31 20 4C 53 55 42 20 22 22 20 7B 31 30 36 34 7D 1 LSUB "" {1064} 41 Byte Test content:" LSUB |22|"; content:"|22| {"; distance:0; byte_test:5,>,256,0,string,dec,relative; 31 20 4C 53 55 42 20 22 22 20 7B 31 30 36 34 7D 1 LSUB "" {1064} 42 Byte Jump content:"|00 00 00 00|"; offset:8; depth:4; content:"|00 01 86 F3|"; offset:16; depth:4; content:"|00 00 00 07|"; distance:4; within:4; byte_jump:4,4,relative,align; byte_jump:4,4,relative,align; byte_test:4,>,128,0,relative; 00 00 00 6C 00 41 41 41 41 41 00 01 00 68 00 41 41 41 41 41 0F 86 00 6F 00 41 41 41 41 41 9C F3 20 73 00 41 41 41 41 41 36 00 37 74 00 41 41 41 41 41 51 00 5E 00 00 41 41 41 41 41 D5 00 D1 00 00 41 41 41 41 41 2B 01 6A 00 00 41 41 41 41 41 00 00 00 00 00 41 41 41 41 41 00 00 00 00 00 41 41 41 41 41 00 00 00 00 00 41 41 41 41 41 00 07 09 00 00 41 41 41 41 41 00 00 6C 00 00 41 41 41 41 41 00 00 6F 00 00 41 41 41 41 41 00 00 63 00 0F 41 41 41 41 41 02 01 61 00 FF 41 41 41 41 41 ....6Q.+........ ................ ... 7^.j....loca lhost........... ................ AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA 43 Byte Jump content:"|00 00 00 00|"; offset:8; depth:4; content:"|00 01 86 F3|"; offset:16; depth:4; content:"|00 00 00 07|"; distance:4; within:4; byte_jump:4,4,relative,align; byte_jump:4,4,relative,align; byte_test:4,>,128,0,relative; 00 00 00 6C 00 41 41 41 41 41 00 01 00 68 00 41 41 41 41 41 0F 86 00 6F 00 41 41 41 41 41 9C F3 20 73 00 41 41 41 41 41 36 00 37 74 00 41 41 41 41 41 51 00 5E 00 00 41 41 41 41 41 D5 00 D1 00 00 41 41 41 41 41 2B 01 6A 00 00 41 41 41 41 41 00 00 00 00 00 41 41 41 41 41 00 00 00 00 00 41 41 41 41 41 00 00 00 00 00 41 41 41 41 41 00 07 09 00 00 41 41 41 41 41 00 00 6C 00 00 41 41 41 41 41 00 00 6F 00 00 41 41 41 41 41 00 00 63 00 0F 41 41 41 41 41 02 01 61 00 FF 41 41 41 41 41 ....6Q.+........ ................ ... 7^.j....loca lhost........... ................ AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA 44 Byte Jump content:"|00 00 00 00|"; offset:8; depth:4; content:"|00 01 86 F3|"; offset:16; depth:4; content:"|00 00 00 07|"; distance:4; within:4; byte_jump:4,4,relative,align; byte_jump:4,4,relative,align; byte_test:4,>,128,0,relative; 00 00 00 6C 00 41 41 41 41 41 00 01 00 68 00 41 41 41 41 41 0F 86 00 6F 00 41 41 41 41 41 9C F3 20 73 00 41 41 41 41 41 36 00 37 74 00 41 41 41 41 41 51 00 5E 00 00 41 41 41 41 41 D5 00 D1 00 00 41 41 41 41 41 2B 01 6A 00 00 41 41 41 41 41 00 00 00 00 00 41 41 41 41 41 00 00 00 00 00 41 41 41 41 41 00 00 00 00 00 41 41 41 41 41 00 07 09 00 00 41 41 41 41 41 00 00 6C 00 00 41 41 41 41 41 00 00 6F 00 00 41 41 41 41 41 00 00 63 00 0F 41 41 41 41 41 02 01 61 00 FF 41 41 41 41 41 ....6Q.+........ ................ ... 7^.j....loca lhost........... ................ AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA 45 Byte Jump content:"|00 00 00 00|"; offset:8; depth:4; content:"|00 01 86 F3|"; offset:16; depth:4; content:"|00 00 00 07|"; distance:4; within:4; byte_jump:4,4,relative,align; byte_jump:4,4,relative,align; byte_test:4,>,128,0,relative; 00 00 00 6C 00 41 41 41 41 41 00 01 00 68 00 41 41 41 41 41 0F 86 00 6F 00 41 41 41 41 41 9C F3 20 73 00 41 41 41 41 41 36 00 37 74 00 41 41 41 41 41 51 00 5E 00 00 41 41 41 41 41 D5 00 D1 00 00 41 41 41 41 41 2B 01 6A 00 00 41 41 41 41 41 00 00 00 00 00 41 41 41 41 41 00 00 00 00 00 41 41 41 41 41 00 00 00 00 00 41 41 41 41 41 00 07 09 00 00 41 41 41 41 41 00 00 6C 00 00 41 41 41 41 41 00 00 6F 00 00 41 41 41 41 41 00 00 63 00 0F 41 41 41 41 41 02 01 61 00 FF 41 41 41 41 41 ....6Q.+........ ................ ... 7^.j....loca lhost........... ................ AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA 46 Byte Jump content:"|00 00 00 00|"; offset:8; depth:4; content:"|00 01 86 F3|"; offset:16; depth:4; content:"|00 00 00 07|"; distance:4; within:4; byte_jump:4,4,relative,align; byte_jump:4,4,relative,align; byte_test:4,>,128,0,relative; 00 00 00 6C 00 41 41 41 41 41 00 01 00 68 00 41 41 41 41 41 0F 86 00 6F 00 41 41 41 41 41 9C F3 20 73 00 41 41 41 41 41 36 00 37 74 00 41 41 41 41 41 51 00 5E 00 00 41 41 41 41 41 D5 00 D1 00 00 41 41 41 41 41 2B 01 6A 00 00 41 41 41 41 41 00 00 00 00 00 41 41 41 41 41 00 00 00 00 00 41 41 41 41 41 00 00 00 00 00 41 41 41 41 41 00 07 09 00 00 41 41 41 41 41 00 00 6C 00 00 41 41 41 41 41 00 00 6F 00 00 41 41 41 41 41 00 00 63 00 0F 41 41 41 41 41 02 01 61 00 FF 41 41 41 41 41 ....6Q.+........ ................ ... 7^.j....loca lhost........... ................ AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA 47 Byte Jump content:"|00 00 00 00|"; offset:8; depth:4; content:"|00 01 86 F3|"; offset:16; depth:4; content:"|00 00 00 07|"; distance:4; within:4; byte_jump:4,4,relative,align; byte_jump:4,4,relative,align; byte_test:4,>,128,0,relative; 00 00 00 6C 00 41 41 41 41 41 00 01 00 68 00 41 41 41 41 41 0F 86 00 6F 00 41 41 41 41 41 9C F3 20 73 00 41 41 41 41 41 36 00 37 74 00 41 41 41 41 41 51 00 5E 00 00 41 41 41 41 41 D5 00 D1 00 00 41 41 41 41 41 2B 01 6A 00 00 41 41 41 41 41 00 00 00 00 00 41 41 41 41 41 00 00 00 00 00 41 41 41 41 41 00 00 00 00 00 41 41 41 41 41 00 07 09 00 00 41 41 41 41 41 00 00 6C 00 00 41 41 41 41 41 00 00 6F 00 00 41 41 41 41 41 00 00 63 00 0F 41 41 41 41 41 02 01 61 00 FF 41 41 41 41 41 ....6Q.+........ ................ ... 7^.j....loca lhost........... ................ AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA 48 Byte Jump content:"|00 00 00 00|"; offset:8; depth:4; content:"|00 01 86 F3|"; offset:16; depth:4; content:"|00 00 00 07|"; distance:4; within:4; byte_jump:4,4,relative,align; byte_jump:4,4,relative,align; byte_test:4,>,128,0,relative; 00 00 00 6C 00 41 41 41 41 41 00 01 00 68 00 41 41 41 41 41 0F 86 00 6F 00 41 41 41 41 41 9C F3 20 73 00 41 41 41 41 41 36 00 37 74 00 41 41 41 41 41 51 00 5E 00 00 41 41 41 41 41 D5 00 D1 00 00 41 41 41 41 41 2B 01 6A 00 00 41 41 41 41 41 00 00 00 00 00 41 41 41 41 41 00 00 00 00 00 41 41 41 41 41 00 00 00 00 00 41 41 41 41 41 00 07 09 00 00 41 41 41 41 41 00 00 6C 00 00 41 41 41 41 41 00 00 6F 00 00 41 41 41 41 41 00 00 63 00 0F 41 41 41 41 41 02 01 61 00 FF 41 41 41 41 41 ....6Q.+........ ................ ... 7^.j....loca lhost........... ................ AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA 49 Byte Jump content:"|00 00 00 00|"; offset:8; depth:4; content:"|00 01 86 F3|"; offset:16; depth:4; content:"|00 00 00 07|"; distance:4; within:4; byte_jump:4,4,relative,align; byte_jump:4,4,relative,align; byte_test:4,>,128,0,relative; 00 00 00 6C 00 41 41 41 41 41 00 01 00 68 00 41 41 41 41 41 0F 86 00 6F 00 41 41 41 41 41 9C F3 20 73 00 41 41 41 41 41 36 00 37 74 00 41 41 41 41 41 51 00 5E 00 00 41 41 41 41 41 D5 00 D1 00 00 41 41 41 41 41 2B 01 6A 00 00 41 41 41 41 41 00 00 00 00 00 41 41 41 41 41 00 00 00 00 00 41 41 41 41 41 00 00 00 00 00 41 41 41 41 41 00 07 09 00 00 41 41 41 41 41 00 00 6C 00 00 41 41 41 41 41 00 00 6F 00 00 41 41 41 41 41 00 00 63 00 0F 41 41 41 41 41 02 01 61 00 FF 41 41 41 41 41 ....6Q.+........ ................ ... 7^.j....loca lhost........... ................ AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA 50 PCRE • Perl Compatable Regular Expressions • a few snort specific options • when using, ALWAYS include a regular content • NOT PART OF FAST PATTERN MATCHER! • Read Mastering Regular Expressions 51 PCRE Format pcre:[!]"(/<regex>/|m<delim><regex><delim>)[i smxAEGRUB]"; • Examples – – – – – pcre:"/blah.*blah/"; pcre:"m?blah/.*blah?"; pcre:"/blah.*blah/i"; pcre:!"/blah/i"; content:"foo"; pcre:!"/blah/R"; 52 PCRE basic options pcre:"/blah.*blah/OPTIONS_GO_HERE"; • i – case insensitive • s – include newlines in the dot metacharacter • m – match on all line breaks • x – ignore whitespace in rules 53 PCRE options PCRE specific pcre:"/blah.*blah/OPTIONS_GO_HERE"; • A – the pattern must match only at the start of the buffer (same as ^) • E – $ only matches end of string • G – Invert greedyness (match as little as possible) 54 PCRE options Snort specific • pcre:"/blah.*blah/OPTIONS_GO_HERE"; • R – Relative Match (same as distance:0;) • U – URI match (same as uricontent) • B – Do not use the decoded buffers (same as rawbytes) 55 PCRE Regex metacharacters • \ – Quote the next metacharacter • ^ – • Match the beginning of the line . – Match any character (except newline) • $ – Match the end of the line (or before newline at the end) • | – Alternation • () – Grouping • [] – Character class • pcre:"/^(foo|bar)$/"; 56 PCRE patterns • \t – tab • \n – newline (LN) • \r – return (CR) • \033 – octal char (think of a PDP-11) • \x0a – hex char 57 more PCRE patterns • \x{263a} – wide hex char (Unicode SMILEY) • \l – lowercase next char (think vi) • \u – uppercase next char (think vi) • \L – lowercase till \E (think vi) • \U – uppercase till \E (think vi) • \Q – quote (disable) pattern metacharacters till \E • \E – end case modification (think vi) 58 Even more PCRE patterns • \w – Match a "word" character (alphanumeric plus "_") • \W – Match a non-"word" character • \s – Match a whitespace character • \S – Match a non-whitespace character • \d – Match a digit character • \D – Match a non-digit character • Example – "/\w\s\w/“ – Matches: "FOO BAR“ – Doesn't Match: "FOO "; 59 PCRE Quantifiers • * – Match 0 or more times • + – Match 1 or more times • ? – Match 1 or 0 times • {n} – Match exactly n times • {n,} – Match at least n times • {n,m} – Match at least n but not more than m times • Example pcre:"/\w{3,5}}/"; 60 PCRE Example • • CVE: CVE-1999-0095 Attack rcpt to: | /bin/id OR rcpt to: ; /bin/id • PCRE Example /rcpt to: | /bin/id/ OR /rcpt to: ; /bin/id/ /rcpt to: [;|] /bin/id/ • /rcpt to:\s*[;|]/ /^rcpt to\x3b\s*[\x3b|]/ /^rcpt to\x3b\s*[\x3b|]/i /^rcpt to\x3b\s*[\x3b|]/mi 61 PCRE Example (regex) • Attack rcpt to: | /bin/id OR rcpt to: ; /bin/id • PCRE /rcpt to: | \/bin\/id/ OR /rcpt to: ; \/bin\/id/ 62 PCRE Example (character classes) • Attack rcpt to: | /bin/id OR rcpt to: ; /bin/id • PCRE /rcpt to: [;|] \/bin\/id/ 63 PCRE Example (remove command) • Attack rcpt to: | /bin/id OR rcpt to: ; /bin/id • PCRE /rcpt to: [;|]/ 64 PCRE Example (remove : and ;) • Attack rcpt to: | /bin/id OR rcpt to: ; /bin/id • PCRE /rcpt to\x3a [\x3b|]/ 65 PCRE Example (remove evasion) • Attack rcpt to: | /bin/id OR rcpt to: ; /bin/id • PCRE /rcpt to\x3a\s*[\x3b|]/i 66 PCRE Example (remove false positives) • Attack rcpt to: | /bin/id OR rcpt to: ; /bin/id • PCRE /^rcpt to\x3a\s*[\x3b|]/mi 67 PCRE completed example • alert tcp any any -> any 25 (flow:to_server,established; content:"rcpt to\:"; nocase; pcre:"/^rcpt\s+to\x3a\s*[|\x3b]/mi";) 68 The required bits • rule header - action ip port direction ip port • Msg • content (if you can) • Classtype • Sid • Rev • flow/stateless (for TCP rules) 69 A few notes • when multiple rules match at a time, longest content "wins“ • long contents are good • multiple contents are ok, split up instead of being evaded • pcre without content is bad • include many references • test test test test test • use variables, they are there for a reason