snortor 0.0.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.
- data/.gitignore +6 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +14 -0
- data/README.md +67 -0
- data/Rakefile +13 -0
- data/lib/rule.rb +36 -0
- data/lib/rule_finder.rb +25 -0
- data/lib/rule_loader.rb +23 -0
- data/lib/rulefile.rb +19 -0
- data/lib/rulefile_collection.rb +120 -0
- data/lib/snortor.rb +135 -0
- data/lib/snortor/version.rb +3 -0
- data/snortor.gemspec +32 -0
- data/test/fixtures/ruleset1.rules +3 -0
- data/test/fixtures/ruleset2.rules +4 -0
- data/test/helper.rb +7 -0
- data/test/out/ruleset1.rules +2 -0
- data/test/out/ruleset2.rules +4 -0
- data/test/test_snortor.rb +89 -0
- metadata +96 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
data/README.md
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
# FIDIUS Snortor
|
2
|
+
|
3
|
+
Snortor provides an interface to configure snort rules.
|
4
|
+
You can:
|
5
|
+
|
6
|
+
* import rules
|
7
|
+
* export rules
|
8
|
+
* find rules by message
|
9
|
+
* activate or deactivate single rules
|
10
|
+
* import/export possible via scp
|
11
|
+
|
12
|
+
## Installation
|
13
|
+
|
14
|
+
Simply install this package with Rubygems:
|
15
|
+
|
16
|
+
$ gem install snortor
|
17
|
+
|
18
|
+
## Usage
|
19
|
+
|
20
|
+
Some examples on how Snortor can be used.
|
21
|
+
|
22
|
+
require 'snortor'
|
23
|
+
|
24
|
+
# import some rules from remote host
|
25
|
+
Snortor.import_rules({:host=>"10.10.10.254",:user=>"root",:password=>"xxx",:remote_path=>"/etc/snort/rules/"})
|
26
|
+
|
27
|
+
# or import rule files from local path
|
28
|
+
Snortor.import_rules("/home/user/myrules")
|
29
|
+
|
30
|
+
# work with your rules
|
31
|
+
puts "#{Snortor.rules.size}"
|
32
|
+
puts "#{Snortor.rules[1].active}"
|
33
|
+
Snortor.rules[1].active = false
|
34
|
+
|
35
|
+
# find specific rules
|
36
|
+
rule = Snortor.rules.find_by_msg("BAD-TRAFFIC")
|
37
|
+
rule.active = true
|
38
|
+
|
39
|
+
# find all rules by name
|
40
|
+
rules = Snortor.rules.find_all_by_msg("BAD-TRAFFIC")
|
41
|
+
rules.each do |rule|
|
42
|
+
rule.active = false
|
43
|
+
end
|
44
|
+
|
45
|
+
Snortor.export_rules({:host=>"10.10.10.254",:user=>"root",:password=>"xxx",:remote_path=>"/etc/snort/rules/"})
|
46
|
+
|
47
|
+
## Authors and Contact
|
48
|
+
|
49
|
+
fidius-evasiondb was written by
|
50
|
+
|
51
|
+
* FIDIUS Intrusion Detection with Intelligent User Support
|
52
|
+
<grp-fidius+evasiondb@tzi.de>, <http://fidius.me>
|
53
|
+
* in particular:
|
54
|
+
* Bernhard Katzmarski <bkatzm+snortor@tzi.de>
|
55
|
+
|
56
|
+
If you have any questions, remarks, suggestion, improvements, etc. feel free to drop a line at the
|
57
|
+
addresses given above. You might also join `#fidius` on Freenode or use the contact form on our
|
58
|
+
[website](http://fidius.me/en/contact).
|
59
|
+
|
60
|
+
|
61
|
+
# Acknowledgement
|
62
|
+
|
63
|
+
This Gem uses snort-rule from Chris Lee which provided the ability to parse rules.
|
64
|
+
|
65
|
+
## License
|
66
|
+
|
67
|
+
Simplified BSD License and GNU GPLv2. See also the file LICENSE.
|
data/Rakefile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# fix error: cant convert nil into String
|
2
|
+
# Rakefile:1 in include?
|
3
|
+
unless ENV['GEM_HOME'] && (__FILE__.include? ENV['GEM_HOME'])
|
4
|
+
require 'bundler'
|
5
|
+
Bundler::GemHelper.install_tasks
|
6
|
+
end
|
7
|
+
|
8
|
+
require 'rake/testtask'
|
9
|
+
Rake::TestTask.new(:test) do |test|
|
10
|
+
test.libs << 'lib' << 'test'
|
11
|
+
test.pattern = 'test/**/test_*.rb'
|
12
|
+
test.verbose = true
|
13
|
+
end
|
data/lib/rule.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# This module is provided by snort-rule gem.
|
2
|
+
# Only do a monkey patch here to have the activation ability of single rules.
|
3
|
+
module Snort
|
4
|
+
# this class is extended to have activation ability of single rules
|
5
|
+
class Rule
|
6
|
+
attr_accessor :active
|
7
|
+
attr_accessor :line
|
8
|
+
|
9
|
+
|
10
|
+
def initialize(kwargs={})
|
11
|
+
super(kwargs)
|
12
|
+
@active=true
|
13
|
+
end
|
14
|
+
|
15
|
+
def active=(a)
|
16
|
+
@active = a
|
17
|
+
end
|
18
|
+
|
19
|
+
def message
|
20
|
+
opts['msg']
|
21
|
+
end
|
22
|
+
def self.parse_rule(line)
|
23
|
+
rule = self.parse(line)
|
24
|
+
if rule.message
|
25
|
+
rule.line = line
|
26
|
+
return rule
|
27
|
+
else
|
28
|
+
return nil
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_line
|
33
|
+
@line.to_s
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/lib/rule_finder.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
module Snortor
|
2
|
+
module RuleFinder
|
3
|
+
def find_by_msg(title)
|
4
|
+
self.each do |r|
|
5
|
+
begin
|
6
|
+
msg = r.opts["msg"]
|
7
|
+
return r if msg[title]
|
8
|
+
rescue
|
9
|
+
end
|
10
|
+
end
|
11
|
+
return nil
|
12
|
+
end
|
13
|
+
|
14
|
+
def find_all_by_msg(title)
|
15
|
+
res = []
|
16
|
+
self.each do |rule|
|
17
|
+
msg = rule.opts["msg"]
|
18
|
+
if msg[title]
|
19
|
+
res << rule
|
20
|
+
end
|
21
|
+
end
|
22
|
+
return res
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/rule_loader.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
module Snortor
|
2
|
+
module RuleLoader
|
3
|
+
def read_rules_from_file(f,&block)
|
4
|
+
file = File.new(f, "r")
|
5
|
+
while (line = file.gets)
|
6
|
+
block.call(f,line)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def read_rules_from_dir(d,&block)
|
11
|
+
Dir.foreach(d) do |filename|
|
12
|
+
full_file_path = File.join(d,filename)
|
13
|
+
next if filename == ".." || filename == "."
|
14
|
+
|
15
|
+
if File.directory?(full_file_path)
|
16
|
+
read_rules_from_dir(full_file_path,&block)
|
17
|
+
next
|
18
|
+
end
|
19
|
+
read_rules_from_file(full_file_path,&block) if File.extname(full_file_path) == ".rules"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/rulefile.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
module Snortor
|
2
|
+
class Rulefile < Array
|
3
|
+
attr_accessor :filename
|
4
|
+
attr_accessor :filepath
|
5
|
+
attr_accessor :relative_path
|
6
|
+
|
7
|
+
def initialize(filepath)
|
8
|
+
raise Errno::ENOENT unless File.exists?(filepath)
|
9
|
+
@filepath = filepath
|
10
|
+
@filename = File.basename(filepath)
|
11
|
+
end
|
12
|
+
|
13
|
+
def calc_relative_path(fullpath)
|
14
|
+
workingdir = fullpath.split("/")
|
15
|
+
thispath = @filepath.split("/")
|
16
|
+
@relative_path = (thispath-workingdir-[filename]).join("/")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
require File.join(SNORTOR_BASE,'rule_loader')
|
2
|
+
require File.join(SNORTOR_BASE,'rule_finder')
|
3
|
+
|
4
|
+
module Snortor
|
5
|
+
class RulefileCollection < Array
|
6
|
+
include RuleLoader
|
7
|
+
include RuleFinder
|
8
|
+
|
9
|
+
alias_method :old_push, :<<
|
10
|
+
alias_method :old_each, :each
|
11
|
+
|
12
|
+
def <<(a)
|
13
|
+
raise "only instances of Rulefile allowed" unless a.class == Rulefile
|
14
|
+
old_push(a)
|
15
|
+
end
|
16
|
+
|
17
|
+
def [](index)
|
18
|
+
offset = 0
|
19
|
+
self.old_each do |rule_file|
|
20
|
+
if index < offset+rule_file.size
|
21
|
+
return rule_file[index-offset]
|
22
|
+
break
|
23
|
+
end
|
24
|
+
offset += rule_file.size
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def size
|
29
|
+
res = 0
|
30
|
+
self.old_each do |rule_file|
|
31
|
+
res += rule_file.size
|
32
|
+
end
|
33
|
+
res
|
34
|
+
end
|
35
|
+
|
36
|
+
def each(&block)
|
37
|
+
self.old_each do |rulefile|
|
38
|
+
rulefile.each do |rule|
|
39
|
+
block.call(rule)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
nil
|
43
|
+
end
|
44
|
+
|
45
|
+
def import_rules(path)
|
46
|
+
rulefile = nil
|
47
|
+
if File.directory?(path)
|
48
|
+
read_rules_from_dir(path) do |filepath,line|
|
49
|
+
if rulefile == nil || rulefile.filepath != filepath
|
50
|
+
rulefile = Rulefile.new(filepath)
|
51
|
+
rulefile.calc_relative_path(path)
|
52
|
+
self << rulefile
|
53
|
+
end
|
54
|
+
begin
|
55
|
+
# only parse lines that seem to be a rule
|
56
|
+
# maybe handle includes and comments as well
|
57
|
+
if line["alert"]
|
58
|
+
if line.strip[0] == "#"
|
59
|
+
line[line.index("#")] = ""
|
60
|
+
rule = Snort::Rule.parse_rule(line.strip)
|
61
|
+
rule.active = false
|
62
|
+
rulefile << rule if rule
|
63
|
+
else
|
64
|
+
rulefile << Snort::Rule.parse_rule(line.strip)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
rescue
|
68
|
+
puts "Problem parsing line #{line} in #{filepath}"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
else
|
72
|
+
|
73
|
+
read_rules_from_file(path) do |filepath,line|
|
74
|
+
if rulefile == nil || rulefile.filepath != filepath
|
75
|
+
rulefile = Rulefile.new(filepath)
|
76
|
+
rulefile.calc_relative_path(path)
|
77
|
+
self << rulefile
|
78
|
+
end
|
79
|
+
begin
|
80
|
+
# only parse lines that seem to be a rule
|
81
|
+
# maybe handle includes and comments as well
|
82
|
+
if line["alert"]
|
83
|
+
if line.strip[0] == "#"
|
84
|
+
line[line.index("#")] = ""
|
85
|
+
rule = Snort::Rule.parse_rule(line.strip)
|
86
|
+
rule.active = false
|
87
|
+
rulefile << rule if rule
|
88
|
+
else
|
89
|
+
rulefile << Snort::Rule.parse_rule(line.strip)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
rescue
|
93
|
+
puts "Problem parsing line #{line} in #{filepath}"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def write_rules(path)
|
100
|
+
Dir.mkdir(path) if !File.exists?(path)
|
101
|
+
self.old_each do |rulefile|
|
102
|
+
begin
|
103
|
+
dest = File.join(path,rulefile.relative_path,rulefile.filename)
|
104
|
+
file = File.new(dest,"w")
|
105
|
+
rescue Errno::ENOENT
|
106
|
+
Dir.mkdir(File.join(path,rulefile.relative_path))
|
107
|
+
file = File.new(dest,"w")
|
108
|
+
end
|
109
|
+
rulefile.each do |rf|
|
110
|
+
if rf.active
|
111
|
+
file.write(rf.to_line.gsub("\n","")+"\n")
|
112
|
+
else
|
113
|
+
file.write("# "+rf.to_line.gsub("\n","")+"\n")
|
114
|
+
end
|
115
|
+
end
|
116
|
+
file.close
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
data/lib/snortor.rb
ADDED
@@ -0,0 +1,135 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
SNORTOR_BASE = File.expand_path('..', __FILE__)
|
3
|
+
|
4
|
+
require 'snort-rule'
|
5
|
+
require 'net/ssh'
|
6
|
+
require 'net/scp'
|
7
|
+
require File.join(SNORTOR_BASE,'rule')
|
8
|
+
require File.join(SNORTOR_BASE,'rulefile')
|
9
|
+
require File.join(SNORTOR_BASE,'rulefile_collection')
|
10
|
+
require 'tmpdir'
|
11
|
+
|
12
|
+
#Snortor provides an interface to configure snort rules. You can:
|
13
|
+
# * import rules
|
14
|
+
# * export rules
|
15
|
+
# * find rules by message
|
16
|
+
# * activate or deactivate single rules
|
17
|
+
# * import/export possible via scp
|
18
|
+
module Snortor
|
19
|
+
class << self
|
20
|
+
@@rules = RulefileCollection.new
|
21
|
+
|
22
|
+
# after import you can work with the rules like
|
23
|
+
# puts "#{Snortor.rules.size}"
|
24
|
+
# puts "#{Snortor.rules[1].active}"
|
25
|
+
# Snortor.rules[1].active = false
|
26
|
+
#
|
27
|
+
def rules
|
28
|
+
@@rules
|
29
|
+
end
|
30
|
+
|
31
|
+
# imports rules from a local_path or via scp connection from a remote host.
|
32
|
+
#
|
33
|
+
# import_rules("/my/local/path")
|
34
|
+
#
|
35
|
+
# import_rules({:host=>x,:user=>x,:password=>x,:remote_path=>x})
|
36
|
+
def import_rules(args)
|
37
|
+
clear
|
38
|
+
if args.class == Hash
|
39
|
+
@@rules.import_rules(download_from_host(args))
|
40
|
+
elsif args.class == String
|
41
|
+
@@rules.import_rules(args)
|
42
|
+
else
|
43
|
+
raise "can not use #{args.class}. provide string or hash for import_rules"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# exports rules to a local directory or via scp connection to a remote host.
|
48
|
+
#
|
49
|
+
# export_rules("/my/local/path")
|
50
|
+
#
|
51
|
+
# export_rules({:host=>x,:user=>x,:password=>x,:remote_path=>xa})
|
52
|
+
def export_rules(args)
|
53
|
+
if args.class == Hash
|
54
|
+
local_path = args[:local_path]
|
55
|
+
local_path = File.join(Dir.tmpdir,"rules") unless local_path
|
56
|
+
Dir.mkdir(local_path) unless File.exists?(local_path)
|
57
|
+
@@rules.write_rules(local_path)
|
58
|
+
args[:local_path] = local_path
|
59
|
+
upload_to_host(args)
|
60
|
+
elsif args.class == String
|
61
|
+
@@rules.write_rules(args)
|
62
|
+
else
|
63
|
+
raise "can not use #{args.class}. provide string or hash for export_rules"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def download_from_host(conn={})
|
68
|
+
if conn[:local_path]
|
69
|
+
local_path = conn[:local_path]
|
70
|
+
else
|
71
|
+
local_path = File.join(Dir.tmpdir)
|
72
|
+
end
|
73
|
+
Dir.mkdir(local_path) unless File.exists?(local_path)
|
74
|
+
raise "no host given for scp download" unless conn[:host]
|
75
|
+
raise "no user given for scp download" unless conn[:user]
|
76
|
+
raise "no password given for scp download" unless conn[:password]
|
77
|
+
raise "no path given for scp download" unless conn[:remote_path]
|
78
|
+
|
79
|
+
options = {}
|
80
|
+
options[:password] = conn[:password]
|
81
|
+
options[:auth_methods] = ["password"]
|
82
|
+
options = options.merge(conn[:options])
|
83
|
+
|
84
|
+
Net::SSH.start(conn[:host], conn[:user], options) do |ssh|
|
85
|
+
ssh.scp.download!(conn[:remote_path], local_path,:recursive=>true) do |ch, name, sent, total|
|
86
|
+
begin
|
87
|
+
print "\r#{name}: #{(sent.to_f * 100 / total.to_f).to_i}%\e[0K"
|
88
|
+
rescue
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
return local_path+"/rules"
|
93
|
+
end
|
94
|
+
|
95
|
+
def upload_to_host(conn={})
|
96
|
+
raise "no host given for scp upload" unless conn[:host]
|
97
|
+
raise "no user given for scp upload" unless conn[:user]
|
98
|
+
raise "no password given for scp upload" unless conn[:password]
|
99
|
+
raise "no remote_path given for scp upload" unless conn[:remote_path]
|
100
|
+
raise "no local_path given for scp upload" unless conn[:local_path]
|
101
|
+
|
102
|
+
options = {}
|
103
|
+
options[:password] = conn[:password]
|
104
|
+
options[:auth_methods] = ["password"]
|
105
|
+
options = options.merge(conn[:options]) if conn[:options]
|
106
|
+
|
107
|
+
Net::SSH.start(conn[:host], conn[:user], options) do |ssh|
|
108
|
+
ssh.scp.upload!(conn[:local_path], conn[:remote_path],:recursive=>true) do |ch, name, sent, total|
|
109
|
+
begin
|
110
|
+
print "\r#{name}: #{(sent.to_f * 100 / total.to_f).to_i}%\e[0K"
|
111
|
+
rescue
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
# clears the rule array
|
118
|
+
#
|
119
|
+
def clear
|
120
|
+
@@rules.clear
|
121
|
+
end
|
122
|
+
|
123
|
+
# find a rule by its message
|
124
|
+
# rule = Snortor.rules.find_by_msg("BAD-TRAFFIC")
|
125
|
+
def find_by_msg(msg)
|
126
|
+
@@rules.find_by_msg(msg)
|
127
|
+
end
|
128
|
+
|
129
|
+
# find all rules by its message
|
130
|
+
# rules = Snortor.rules.find_all_by_msg("BAD-TRAFFIC")
|
131
|
+
def find_all_by_msg(msg)
|
132
|
+
@@rules.find_all_by_msg(msg)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
data/snortor.gemspec
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "snortor/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "snortor"
|
7
|
+
s.version = Snortor::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Bernhard Katzmarski"]
|
10
|
+
s.email = ["bkatzm@tzi.de"]
|
11
|
+
s.homepage = "http://www.fidius.me"
|
12
|
+
|
13
|
+
s.summary = %q{Snortor provides an interface to configure snort rules. You can:
|
14
|
+
* import rules
|
15
|
+
* export rules
|
16
|
+
* find rules by message
|
17
|
+
* activate or deactivate single rules
|
18
|
+
* import/export possible via scp
|
19
|
+
}
|
20
|
+
|
21
|
+
s.description = %q{Descriptions are provided in doc and at fidius.me}
|
22
|
+
|
23
|
+
s.rubyforge_project = "snortor"
|
24
|
+
|
25
|
+
s.add_dependency "snort-rule", ">= 0.0.1"
|
26
|
+
s.add_dependency "net-scp", "~> 1.0.4"
|
27
|
+
|
28
|
+
s.files = `git ls-files`.split("\n")
|
29
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
30
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
31
|
+
s.require_paths = ["lib"]
|
32
|
+
end
|
@@ -0,0 +1,3 @@
|
|
1
|
+
alert tcp $EXTERNAL_NET any <> $HOME_NET 0 (msg:"BAD-TRAFFIC tcp port 0 traffic"; flow:stateless; classtype:misc-activity; sid:524; rev:8;)
|
2
|
+
alert udp $EXTERNAL_NET any <> $HOME_NET 0 (msg:"BAD-TRAFFIC udp port 0 traffic"; reference:bugtraq,576; reference:cve,1999-0675; reference:nessus,10074; classtype:misc-activity; sid:525; rev:9;)
|
3
|
+
|
@@ -0,0 +1,4 @@
|
|
1
|
+
alert tcp $EXTERNAL_NET any -> $HOME_NET $HTTP_PORTS (msg:"ET WEB_SERVER Possible Cisco Subscriber Edge Services Manager Cross Site Scripting/HTML Injection Attempt"; flow:to_server,established; uricontent:"/servlet/JavascriptProbe"; nocase; nocase; uricontent:"documentElement=true"; nocase; uricontent:"regexp=true"; nocase; uricontent:"frames=true"; classtype:web-application-attack; reference:url,www.securityfocus.com/bid/34454/info; reference:url,doc.emergingthreats.net/2010622; reference:url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SERVER/WEB_Cisco; sid:2010622; rev:2;)
|
2
|
+
alert tcp $EXTERNAL_NET any -> $HOME_NET $HTTP_PORTS (msg:"ET WEB_SERVER Cisco IOS HTTP Server Exec Command Execution Attempt"; flow:to_server,established; uricontent:"/level/15/exec/-/"; nocase; pcre:"/\x2Flevel\x2F15\x2Fexec\x2F\x2D\x2F[a-z]/Ui"; classtype:web-application-attack; reference:url,articles.techrepublic.com.com/5100-10878_11-6039967.html; reference:url,doc.emergingthreats.net/2010623; reference:url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SERVER/WEB_Cisco; sid:2010623; rev:2;)
|
3
|
+
#alert tcp $EXTERNAL_NET any -> $HOME_NET $HTTP_PORTS (msg:"ET WEB_SERVER Cisco IOS HTTP Server Exec Command Execution Attempt"; flow:to_server,established; uricontent:"/level/15/exec/-/"; nocase; pcre:"/\x2Flevel\x2F15\x2Fexec\x2F\x2D\x2F[a-z]/Ui"; classtype:web-application-attack; reference:url,articles.techrepublic.com.com/5100-10878_11-6039967.html; reference:url,doc.emergingthreats.net/2010623; reference:url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SERVER/WEB_Cisco; sid:2010623; rev:2;)
|
4
|
+
#alert tcp $EXTERNAL_NET any -> $HOME_NET 135:139 (msg:"DOS Winnuke attack"; flow:stateless; flags:U+; reference:bugtraq,2010; reference:cve,1999-0153; classtype:attempted-dos; sid:1257; rev:10;)
|
data/test/helper.rb
ADDED
@@ -0,0 +1,2 @@
|
|
1
|
+
alert tcp $EXTERNAL_NET any <> $HOME_NET 0 (msg:"BAD-TRAFFIC tcp port 0 traffic"; flow:stateless; classtype:misc-activity; sid:524; rev:8;)
|
2
|
+
alert udp $EXTERNAL_NET any <> $HOME_NET 0 (msg:"BAD-TRAFFIC udp port 0 traffic"; reference:bugtraq,576; reference:cve,1999-0675; reference:nessus,10074; classtype:misc-activity; sid:525; rev:9;)
|
@@ -0,0 +1,4 @@
|
|
1
|
+
alert tcp $EXTERNAL_NET any -> $HOME_NET $HTTP_PORTS (msg:"ET WEB_SERVER Possible Cisco Subscriber Edge Services Manager Cross Site Scripting/HTML Injection Attempt"; flow:to_server,established; uricontent:"/servlet/JavascriptProbe"; nocase; nocase; uricontent:"documentElement=true"; nocase; uricontent:"regexp=true"; nocase; uricontent:"frames=true"; classtype:web-application-attack; reference:url,www.securityfocus.com/bid/34454/info; reference:url,doc.emergingthreats.net/2010622; reference:url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SERVER/WEB_Cisco; sid:2010622; rev:2;)
|
2
|
+
alert tcp $EXTERNAL_NET any -> $HOME_NET $HTTP_PORTS (msg:"ET WEB_SERVER Cisco IOS HTTP Server Exec Command Execution Attempt"; flow:to_server,established; uricontent:"/level/15/exec/-/"; nocase; pcre:"/\x2Flevel\x2F15\x2Fexec\x2F\x2D\x2F[a-z]/Ui"; classtype:web-application-attack; reference:url,articles.techrepublic.com.com/5100-10878_11-6039967.html; reference:url,doc.emergingthreats.net/2010623; reference:url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SERVER/WEB_Cisco; sid:2010623; rev:2;)
|
3
|
+
alert tcp $EXTERNAL_NET any -> $HOME_NET $HTTP_PORTS (msg:"ET WEB_SERVER Cisco IOS HTTP Server Exec Command Execution Attempt"; flow:to_server,established; uricontent:"/level/15/exec/-/"; nocase; pcre:"/\x2Flevel\x2F15\x2Fexec\x2F\x2D\x2F[a-z]/Ui"; classtype:web-application-attack; reference:url,articles.techrepublic.com.com/5100-10878_11-6039967.html; reference:url,doc.emergingthreats.net/2010623; reference:url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SERVER/WEB_Cisco; sid:2010623; rev:2;)
|
4
|
+
alert tcp $EXTERNAL_NET any -> $HOME_NET 135:139 (msg:"DOS Winnuke attack"; flow:stateless; flags:U+; reference:bugtraq,2010; reference:cve,1999-0153; classtype:attempted-dos; sid:1257; rev:10;)
|
@@ -0,0 +1,89 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require 'test/unit'
|
3
|
+
require_relative "helper"
|
4
|
+
|
5
|
+
class SnortorTest < Test::Unit::TestCase
|
6
|
+
def delete_out_directory
|
7
|
+
out = File.join(BASE_DIR,"test","out")
|
8
|
+
FileUtils.rm_rf(out) if Dir.exists?(out)
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_import_rules
|
12
|
+
Snortor.import_rules(FIXTURES_DIR)
|
13
|
+
assert_equal 6, Snortor.rules.size
|
14
|
+
assert !Snortor.rules[4].active
|
15
|
+
|
16
|
+
assert_equal Snortor.rules.find_all_by_msg("BAD-TRAFFIC").size, 2
|
17
|
+
assert Snortor.rules.find_by_msg("BAD-TRAFFIC")
|
18
|
+
|
19
|
+
assert_equal Snortor.rules.find_all_by_msg("Command Execution").size, 2
|
20
|
+
assert Snortor.rules.find_by_msg("Command Execution")
|
21
|
+
|
22
|
+
assert_equal Snortor.rules.find_all_by_msg("TFTP GET filename overflow").size, 0
|
23
|
+
|
24
|
+
|
25
|
+
delete_out_directory
|
26
|
+
Snortor.rules[0].active = false
|
27
|
+
Snortor.export_rules(File.join(BASE_DIR,"test","out"))
|
28
|
+
|
29
|
+
Snortor.import_rules(File.join(BASE_DIR,"test","out"))
|
30
|
+
assert_equal 6, Snortor.rules.size
|
31
|
+
assert !Snortor.rules[0].active
|
32
|
+
assert Snortor.rules[1].active
|
33
|
+
assert Snortor.rules[2].active
|
34
|
+
assert Snortor.rules[3].active
|
35
|
+
assert !Snortor.rules[4].active
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_ruleset
|
39
|
+
a = Snortor::Rulefile.new(File.join(FIXTURES_DIR,"ruleset1.rules"))
|
40
|
+
|
41
|
+
a << Snort::Rule.new({})
|
42
|
+
assert_raise ArgumentError do
|
43
|
+
a << Snortor::Rulefile.new #error
|
44
|
+
end
|
45
|
+
assert_raise Errno::ENOENT do
|
46
|
+
a << Snortor::Rulefile.new("path")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
def test_ruleset_collection
|
52
|
+
a = Snortor::RulefileCollection.new
|
53
|
+
|
54
|
+
rf1 = Snortor::Rulefile.new(File.join(FIXTURES_DIR,"ruleset1.rules"))
|
55
|
+
r1 = Snort::Rule.new({})
|
56
|
+
r2 = Snort::Rule.new({})
|
57
|
+
r3 = Snort::Rule.new({})
|
58
|
+
r4 = Snort::Rule.new({})
|
59
|
+
r5 = Snort::Rule.new({})
|
60
|
+
|
61
|
+
rf1 << r1
|
62
|
+
rf1 << r2
|
63
|
+
rf1 << r3
|
64
|
+
|
65
|
+
rf2 = Snortor::Rulefile.new(File.join(FIXTURES_DIR,"ruleset2.rules"))
|
66
|
+
rf2 << r4
|
67
|
+
rf2 << r5
|
68
|
+
|
69
|
+
a << rf1
|
70
|
+
a << rf2
|
71
|
+
|
72
|
+
assert_equal 5, a.size
|
73
|
+
|
74
|
+
assert_equal r1, a[0]
|
75
|
+
assert_equal r2, a[1]
|
76
|
+
assert_equal r3, a[2]
|
77
|
+
assert_equal r4, a[3]
|
78
|
+
assert_equal r5, a[4]
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_set_deactivated_rule_active
|
82
|
+
Snortor.import_rules(FIXTURES_DIR)
|
83
|
+
assert_equal 6, Snortor.rules.size
|
84
|
+
Snortor.rules.each do |rule|
|
85
|
+
rule.active = true
|
86
|
+
end
|
87
|
+
Snortor.export_rules(File.join(BASE_DIR,"test","out"))
|
88
|
+
end
|
89
|
+
end
|
metadata
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: snortor
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.0.1
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Bernhard Katzmarski
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-12-01 00:00:00 +01:00
|
14
|
+
default_executable:
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: snort-rule
|
18
|
+
prerelease: false
|
19
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
20
|
+
none: false
|
21
|
+
requirements:
|
22
|
+
- - ">="
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: 0.0.1
|
25
|
+
type: :runtime
|
26
|
+
version_requirements: *id001
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: net-scp
|
29
|
+
prerelease: false
|
30
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
31
|
+
none: false
|
32
|
+
requirements:
|
33
|
+
- - ~>
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: 1.0.4
|
36
|
+
type: :runtime
|
37
|
+
version_requirements: *id002
|
38
|
+
description: Descriptions are provided in doc and at fidius.me
|
39
|
+
email:
|
40
|
+
- bkatzm@tzi.de
|
41
|
+
executables: []
|
42
|
+
|
43
|
+
extensions: []
|
44
|
+
|
45
|
+
extra_rdoc_files: []
|
46
|
+
|
47
|
+
files:
|
48
|
+
- .gitignore
|
49
|
+
- Gemfile
|
50
|
+
- Gemfile.lock
|
51
|
+
- README.md
|
52
|
+
- Rakefile
|
53
|
+
- lib/rule.rb
|
54
|
+
- lib/rule_finder.rb
|
55
|
+
- lib/rule_loader.rb
|
56
|
+
- lib/rulefile.rb
|
57
|
+
- lib/rulefile_collection.rb
|
58
|
+
- lib/snortor.rb
|
59
|
+
- lib/snortor/version.rb
|
60
|
+
- snortor.gemspec
|
61
|
+
- test/fixtures/ruleset1.rules
|
62
|
+
- test/fixtures/ruleset2.rules
|
63
|
+
- test/helper.rb
|
64
|
+
- test/out/ruleset1.rules
|
65
|
+
- test/out/ruleset2.rules
|
66
|
+
- test/test_snortor.rb
|
67
|
+
has_rdoc: true
|
68
|
+
homepage: http://www.fidius.me
|
69
|
+
licenses: []
|
70
|
+
|
71
|
+
post_install_message:
|
72
|
+
rdoc_options: []
|
73
|
+
|
74
|
+
require_paths:
|
75
|
+
- lib
|
76
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
77
|
+
none: false
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: "0"
|
82
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
83
|
+
none: false
|
84
|
+
requirements:
|
85
|
+
- - ">="
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: "0"
|
88
|
+
requirements: []
|
89
|
+
|
90
|
+
rubyforge_project: snortor
|
91
|
+
rubygems_version: 1.6.2
|
92
|
+
signing_key:
|
93
|
+
specification_version: 3
|
94
|
+
summary: "Snortor provides an interface to configure snort rules. You can: * import rules * export rules * find rules by message * activate or deactivate single rules * import/export possible via scp"
|
95
|
+
test_files: []
|
96
|
+
|