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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 29dd2030dcab15c7a79fe409f387f365833d6ef9
4
- data.tar.gz: c000e78ab850620360e3cf169a6675081b43f067
3
+ metadata.gz: e2eabb911b41cd33e776dd69cc3f50ba807ccaf8
4
+ data.tar.gz: 7bfa5b2a310dc398d362991c6cecd7b1c72fb022
5
5
  SHA512:
6
- metadata.gz: 719fa4d1026c38c683d06364c16c930be551c3dca3fe4b67493e23d6f33d52125a5d74bd9e05cb0b2528469792cac3e3cdcd70dcd0a29eb38b15d566879b5d27
7
- data.tar.gz: 9158d07dc87858e5179bb6355f8b3e285645db5c65e14bf2e8f1ec6bf82a46ce669abe9c38cc59f7ddcc1f7a125bbe282b10f788d1ecb50f11ba38c905910f81
6
+ metadata.gz: dc95c1a7217f9d624cb887e53a7a1f8bcc0d710a617863f1d484259edec11423033005e4082547e823489bcd0fe4eb8d999dfce13236c6e566b59ca3d639095e
7
+ data.tar.gz: fb1d93af758a6485bf2ae7a39509f4c117325c0b15c7820d891301450dd9c23223f325437993fd6a1d49c4b2c1098ea8b1c3ec38bfab466f249da99a4ca0c036
data/.gitignore CHANGED
@@ -14,4 +14,5 @@ rdoc
14
14
  spec/reports
15
15
  test/tmp
16
16
  test/version_tmp
17
+ test/community-rules
17
18
  tmp
@@ -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 string.index(/^#+\s+/)
129
+ if rulestr.index(/^#/)
95
130
  rule.enabled = false
96
- string.gsub!(/^#+\s*/,'')
131
+ rulestr.gsub!(/^#+\s*/,'')
97
132
  end
98
- rulepart, optspart = string.split(/\s*\(\s*/,2)
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
@@ -1,5 +1,5 @@
1
1
  module Snort
2
2
  class Rule
3
- VERSION = "1.3.0"
3
+ VERSION = "1.4.1"
4
4
  end
5
5
  end
@@ -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
@@ -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.options << Snort::RuleOption.new('sid', 48)
29
- rule.options << Snort::RuleOption.new('threshold', 'type limit,track by_src,count 1,seconds 3600')
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.options << Snort::RuleOption.new('msg', '"HTTP Host www.baddomain.com"')
43
- rule.options << Snort::RuleOption.new('content', '"Host|3a|"')
44
- rule.options << Snort::RuleOption.new('nocase')
45
- rule.options << Snort::RuleOption.new('http_header')
46
- rule.options << Snort::RuleOption.new('content', '"www.baddomain.com"')
47
- rule.options << Snort::RuleOption.new('nocase')
48
- rule.options << Snort::RuleOption.new('http_header')
49
- rule.options << Snort::RuleOption.new('pcre', '"/^Host\\x3a(.*\\.|\\s*)www\\.baddomain\\.com\\s*$/mi"')
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.options << Snort::RuleOption.new('msg', '"HTTP Host www.baddomain.com"')
67
- rule.options << Snort::RuleOption.new('content', '"Host|3a|"')
68
- rule.options << Snort::RuleOption.new('nocase')
69
- rule.options << Snort::RuleOption.new('http_header')
70
- rule.options << Snort::RuleOption.new('content', '"www.baddomain.com"')
71
- rule.options << Snort::RuleOption.new('nocase')
72
- rule.options << Snort::RuleOption.new('http_header')
73
- rule.options << Snort::RuleOption.new('pcre', '"/^Host\\x3a(.*\\.|\\s*)www\\.baddomain\\.com\\s*$/mi"')
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.3.0
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-05 00:00:00.000000000 Z
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