snort-rule 1.3.0 → 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/lib/snort/rule.rb +38 -3
- data/lib/snort/rule/version.rb +1 -1
- data/test/test_snort-community-rules.rb +64 -0
- data/test/test_snort-rule.rb +25 -29
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e2eabb911b41cd33e776dd69cc3f50ba807ccaf8
|
4
|
+
data.tar.gz: 7bfa5b2a310dc398d362991c6cecd7b1c72fb022
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dc95c1a7217f9d624cb887e53a7a1f8bcc0d710a617863f1d484259edec11423033005e4082547e823489bcd0fe4eb8d999dfce13236c6e566b59ca3d639095e
|
7
|
+
data.tar.gz: fb1d93af758a6485bf2ae7a39509f4c117325c0b15c7820d891301450dd9c23223f325437993fd6a1d49c4b2c1098ea8b1c3ec38bfab466f249da99a4ca0c036
|
data/.gitignore
CHANGED
data/lib/snort/rule.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require "snort/rule/version"
|
2
2
|
require "snort/rule/option"
|
3
|
+
require 'pp'
|
3
4
|
# Generates and parses snort rules
|
4
5
|
#
|
5
6
|
# Authors:: Chris Lee (mailto:rubygems@chrislee.dhs.org),
|
@@ -85,17 +86,51 @@ module Snort
|
|
85
86
|
@options = []
|
86
87
|
@options_hash = {}
|
87
88
|
end
|
89
|
+
|
90
|
+
def get_option(option_name)
|
91
|
+
if @options_hash[option_name]
|
92
|
+
if @options_hash[option_name].length == 1
|
93
|
+
if @options_hash[option_name][0].arguments.length == 1
|
94
|
+
return @options_hash[option_name][0].arguments[0]
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
nil
|
99
|
+
end
|
100
|
+
|
101
|
+
def get_option_first(option_name)
|
102
|
+
if @options_hash[option_name]
|
103
|
+
if @options_hash[option_name].length > 0
|
104
|
+
if @options_hash[option_name][0].arguments.length > 0
|
105
|
+
return @options_hash[option_name][0].arguments[0]
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
nil
|
110
|
+
end
|
111
|
+
|
112
|
+
def get_option_last(option_name)
|
113
|
+
if @options_hash[option_name]
|
114
|
+
if @options_hash[option_name].length > 0
|
115
|
+
if @options_hash[option_name].last.arguments.length > 0
|
116
|
+
return @options_hash[option_name].last.arguments[0]
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
nil
|
121
|
+
end
|
88
122
|
|
89
123
|
# Parse a snort rule to generate an object
|
90
124
|
def Rule::parse(string)
|
91
125
|
rule = Snort::Rule.new
|
126
|
+
rulestr = string.strip
|
92
127
|
# If the string begins with /^#+\s*/, then the rule is disabled.
|
93
128
|
# If disabled, let's scrub the disabling substring from the string.
|
94
|
-
if
|
129
|
+
if rulestr.index(/^#/)
|
95
130
|
rule.enabled = false
|
96
|
-
|
131
|
+
rulestr.gsub!(/^#+\s*/,'')
|
97
132
|
end
|
98
|
-
rulepart, optspart =
|
133
|
+
rulepart, optspart = rulestr.split(/\s*\(\s*/,2)
|
99
134
|
rule.action, rule.proto, rule.src, rule.sport, rule.dir, rule.dst, rule.dport = rulepart.split(/\s+/)
|
100
135
|
if not ['<>', '<-', '->'].index(rule.dir)
|
101
136
|
# most likely, I have a parse error, maybe it's just a random comment
|
data/lib/snort/rule/version.rb
CHANGED
@@ -0,0 +1,64 @@
|
|
1
|
+
unless Kernel.respond_to?(:require_relative)
|
2
|
+
module Kernel
|
3
|
+
def require_relative(path)
|
4
|
+
require File.join(File.dirname(caller[0]), path.to_str)
|
5
|
+
end
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
require_relative 'helper'
|
10
|
+
|
11
|
+
class TestSnortCommunityRules < Minitest::Test
|
12
|
+
def setup
|
13
|
+
destination = "test"
|
14
|
+
if not File.exist?("#{destination}/community-rules/community.rules")
|
15
|
+
require 'open-uri'
|
16
|
+
require 'zlib'
|
17
|
+
require 'rubygems/package'
|
18
|
+
require 'fileutils'
|
19
|
+
|
20
|
+
url = "https://www.snort.org/downloads/community/community-rules.tar.gz"
|
21
|
+
puts "downloading #{url} to #{destination}/community-rules/community.rules"
|
22
|
+
tarfile = open(url)
|
23
|
+
|
24
|
+
# un-gzips the given IO, returning the
|
25
|
+
# decompressed version as a StringIO
|
26
|
+
z = Zlib::GzipReader.new(tarfile)
|
27
|
+
unzipped = StringIO.new(z.read)
|
28
|
+
z.close
|
29
|
+
tarfile.close
|
30
|
+
Gem::Package::TarReader.new unzipped do |tar|
|
31
|
+
tar.each do |tarfile|
|
32
|
+
destination_file = File.join destination, tarfile.full_name
|
33
|
+
if tarfile.directory?
|
34
|
+
FileUtils.mkdir_p destination_file
|
35
|
+
else
|
36
|
+
destination_directory = File.dirname(destination_file)
|
37
|
+
FileUtils.mkdir_p destination_directory unless File.directory?(destination_directory)
|
38
|
+
File.open destination_file, "wb" do |f|
|
39
|
+
f.print tarfile.read
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_complete_rules_file
|
48
|
+
rules = []
|
49
|
+
File.open("test/community-rules/community.rules").each_line do |line|
|
50
|
+
next unless line =~ /alert/
|
51
|
+
begin
|
52
|
+
rule = Snort::Rule.parse(line)
|
53
|
+
if rule
|
54
|
+
rules << rule
|
55
|
+
end
|
56
|
+
rescue ArgumentError => e
|
57
|
+
rescue NoMethodError => e
|
58
|
+
end
|
59
|
+
end
|
60
|
+
assert_equal 3127, rules.length
|
61
|
+
assert_equal 2522, rules.count{|r| ! r.enabled}
|
62
|
+
assert_equal 605, rules.count{|r| r.enabled}
|
63
|
+
end
|
64
|
+
end
|
data/test/test_snort-rule.rb
CHANGED
@@ -25,8 +25,8 @@ class TestSnortRule < Minitest::Test
|
|
25
25
|
rule.src = '192.168.0.1'
|
26
26
|
rule.dir = '<>'
|
27
27
|
rule.dport = 53
|
28
|
-
rule.
|
29
|
-
rule.
|
28
|
+
rule.add_option(Snort::RuleOption.new('sid', 48))
|
29
|
+
rule.add_option(Snort::RuleOption.new('threshold', 'type limit,track by_src,count 1,seconds 3600'))
|
30
30
|
assert_equal rule.to_s, "pass udp 192.168.0.1 any <> any 53 (sid:48; threshold:type limit,track by_src,count 1,seconds 3600;)"
|
31
31
|
end
|
32
32
|
|
@@ -39,18 +39,14 @@ class TestSnortRule < Minitest::Test
|
|
39
39
|
rule.dir = '->'
|
40
40
|
rule.dst = '$EXTERNAL_NET'
|
41
41
|
rule.dport = '$HTTP_PORTS'
|
42
|
-
rule.
|
43
|
-
rule.
|
44
|
-
rule.
|
45
|
-
rule.
|
46
|
-
rule.
|
47
|
-
rule.
|
48
|
-
rule.
|
49
|
-
rule.
|
50
|
-
rule.options << Snort::RuleOption.new('flow', 'to_server,established')
|
51
|
-
rule.options << Snort::RuleOption.new('threshold', 'type limit, track by_src, count 1, seconds 300')
|
52
|
-
rule.options << Snort::RuleOption.new('classtype', 'bad-unknown')
|
53
|
-
rule.options << Snort::RuleOption.new('sid', '100000000')
|
42
|
+
rule.add_option(Snort::RuleOption.new('msg', '"HTTP Host www.baddomain.com"'))
|
43
|
+
rule.add_option(Snort::RuleOption.new('content', ['"Host|3a|"', 'nocase', 'http_header']))
|
44
|
+
rule.add_option(Snort::RuleOption.new('content', ['"www.baddomain.com"', 'nocase', 'http_header']))
|
45
|
+
rule.add_option(Snort::RuleOption.new('pcre', '"/^Host\\x3a(.*\\.|\\s*)www\\.baddomain\\.com\\s*$/mi"'))
|
46
|
+
rule.add_option(Snort::RuleOption.new('flow', 'to_server,established'))
|
47
|
+
rule.add_option(Snort::RuleOption.new('threshold', 'type limit, track by_src, count 1, seconds 300'))
|
48
|
+
rule.add_option(Snort::RuleOption.new('classtype', 'bad-unknown'))
|
49
|
+
rule.add_option(Snort::RuleOption.new('sid', '100000000'))
|
54
50
|
assert_equal 'alert tcp $HOME_NET any -> $EXTERNAL_NET $HTTP_PORTS (msg:"HTTP Host www.baddomain.com"; content:"Host|3a|"; nocase; http_header; content:"www.baddomain.com"; nocase; http_header; pcre:"/^Host\x3a(.*\.|\s*)www\.baddomain\.com\s*$/mi"; flow:to_server,established; threshold:type limit, track by_src, count 1, seconds 300; classtype:bad-unknown; sid:100000000;)', rule.to_s
|
55
51
|
end
|
56
52
|
|
@@ -63,33 +59,33 @@ class TestSnortRule < Minitest::Test
|
|
63
59
|
rule.dir = '->'
|
64
60
|
rule.dst = '$EXTERNAL_NET'
|
65
61
|
rule.dport = '$HTTP_PORTS'
|
66
|
-
rule.
|
67
|
-
rule.
|
68
|
-
rule.
|
69
|
-
rule.
|
70
|
-
rule.
|
71
|
-
rule.
|
72
|
-
rule.
|
73
|
-
rule.
|
74
|
-
rule.options << Snort::RuleOption.new('flow', 'to_server,established')
|
75
|
-
rule.options << Snort::RuleOption.new('threshold', 'type limit, track by_src, count 1, seconds 300')
|
76
|
-
rule.options << Snort::RuleOption.new('classtype', 'bad-unknown')
|
77
|
-
rule.options << Snort::RuleOption.new('sid', '100000000')
|
62
|
+
rule.add_option(Snort::RuleOption.new('msg', '"HTTP Host www.baddomain.com"'))
|
63
|
+
rule.add_option(Snort::RuleOption.new('content', ['"Host|3a|"', 'nocase', 'http_header']))
|
64
|
+
rule.add_option(Snort::RuleOption.new('content', ['"www.baddomain.com"', 'nocase', 'http_header']))
|
65
|
+
rule.add_option(Snort::RuleOption.new('pcre', '"/^Host\\x3a(.*\\.|\\s*)www\\.baddomain\\.com\\s*$/mi"'))
|
66
|
+
rule.add_option(Snort::RuleOption.new('flow', 'to_server,established'))
|
67
|
+
rule.add_option(Snort::RuleOption.new('threshold', 'type limit, track by_src, count 1, seconds 300'))
|
68
|
+
rule.add_option(Snort::RuleOption.new('classtype', 'bad-unknown'))
|
69
|
+
rule.add_option(Snort::RuleOption.new('sid', '100000000'))
|
78
70
|
assert_equal '#alert tcp $HOME_NET any -> $EXTERNAL_NET $HTTP_PORTS (msg:"HTTP Host www.baddomain.com"; content:"Host|3a|"; nocase; http_header; content:"www.baddomain.com"; nocase; http_header; pcre:"/^Host\x3a(.*\.|\s*)www\.baddomain\.com\s*$/mi"; flow:to_server,established; threshold:type limit, track by_src, count 1, seconds 300; classtype:bad-unknown; sid:100000000;)', rule.to_s
|
71
|
+
assert_equal '100000000', rule.get_option('sid')
|
72
|
+
assert_nil rule.get_option('content')
|
73
|
+
assert_equal '"Host|3a|"', rule.get_option_first('content')
|
74
|
+
assert_equal '"www.baddomain.com"', rule.get_option_last('content')
|
79
75
|
end
|
80
76
|
|
81
77
|
def test_parse_an_existing_rule_and_generate_the_same_rule
|
82
|
-
rule = Snort::Rule.parse("pass udp 192.168.0.1 any <> any 53 ( sid:48; threshold:type limit,track by_src,count 1,seconds 3600; )")
|
78
|
+
rule = Snort::Rule.parse(" pass udp 192.168.0.1 any <> any 53 ( sid:48; threshold:type limit,track by_src,count 1,seconds 3600; )")
|
83
79
|
assert_equal rule.to_s, "pass udp 192.168.0.1 any <> any 53 (sid:48; threshold:type limit,track by_src,count 1,seconds 3600;)"
|
84
80
|
end
|
85
81
|
|
86
82
|
def test_parse_an_existing_disabled_rule_and_generate_the_same_rule
|
87
|
-
rule = Snort::Rule.parse("#pass udp 192.168.0.1 any <> any 53 ( sid:48; threshold:type limit,track by_src,count 1,seconds 3600; )")
|
83
|
+
rule = Snort::Rule.parse(" #pass udp 192.168.0.1 any <> any 53 ( sid:48; threshold:type limit,track by_src,count 1,seconds 3600; )")
|
88
84
|
assert_equal rule.to_s, "#pass udp 192.168.0.1 any <> any 53 (sid:48; threshold:type limit,track by_src,count 1,seconds 3600;)"
|
89
85
|
end
|
90
86
|
|
91
87
|
def test_parse_a_disabled_rule_and_generate_the_normalized_disabled_rule
|
92
|
-
rule = Snort::Rule.parse("### pass udp 192.168.0.1 any <> any 53 ( sid:48; threshold:type limit,track by_src,count 1,seconds 3600; )")
|
88
|
+
rule = Snort::Rule.parse(" ### pass udp 192.168.0.1 any <> any 53 ( sid:48; threshold:type limit,track by_src,count 1,seconds 3600; )")
|
93
89
|
assert_equal rule.to_s, "#pass udp 192.168.0.1 any <> any 53 (sid:48; threshold:type limit,track by_src,count 1,seconds 3600;)"
|
94
90
|
end
|
95
91
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: snort-rule
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- chrislee35
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-11-
|
11
|
+
date: 2014-11-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -86,6 +86,7 @@ files:
|
|
86
86
|
- lib/snort/rule/version.rb
|
87
87
|
- snort-rule.gemspec
|
88
88
|
- test/helper.rb
|
89
|
+
- test/test_snort-community-rules.rb
|
89
90
|
- test/test_snort-rule.rb
|
90
91
|
- test/test_snort_rule_option.rb
|
91
92
|
homepage: http://github.com/chrislee35/snort-rule
|
@@ -114,5 +115,6 @@ specification_version: 4
|
|
114
115
|
summary: Class for parsing and generating Snort Rules
|
115
116
|
test_files:
|
116
117
|
- test/helper.rb
|
118
|
+
- test/test_snort-community-rules.rb
|
117
119
|
- test/test_snort-rule.rb
|
118
120
|
- test/test_snort_rule_option.rb
|