snortor 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|