@@ -0,0 +1,105 @@
begin
require 'snortor'
rescue
raise "can not find snortor gem. Please gem install snortor"
end
#require 'evasion-db/vendor/bitfield'
require File.join(FIDIUS::EvasionDB::GEM_BASE, 'evasion-db', 'vendor', 'bitfield')

module FIDIUS
module EvasionDB
module SnortRuleFetcher
@@rule_path = nil


@@ssh_host = nil
@@ssh_pw = nil
@@ssh_remote_path = nil
@@ssh_user = nil
@@fetch_remote = false
@@ssh_options = {}

def import_rules_to_snortor
raise "no rulepath given" unless @@rule_path
if @@fetch_remote
a = {:host=>@@ssh_host,:user=>@@ssh_user,:password=>@@ssh_pw,:remote_path=>@@ssh_remote_path,:options=>@@ssh_options}
puts "Snortor.import_rules(#{a.inspect})"
Snortor.import_rules(a)
else
Snortor.import_rules(@@rule_path)
end
end
# generate a bitvector based on activated rules
# and assign this bisvector to the given attack_module
def fetch_rules(attack_module)
import_rules_to_snortor

raise "this attack_module has an ruleset bitvector" if attack_module.enabled_rules

start_time = Time.now
rules_enabled = BitField.new(Snortor.rules.size)
i = 0
Snortor.rules.each do |rule|
if rule.message
rules_enabled[i] = (rule.active == true)? 1 : 0
i += 1
end
end
end_time = Time.now

ruleset = FIDIUS::EvasionDB::Knowledge::EnabledRules.create(:bitstring=>rules_enabled.to_s)
ruleset.attack_module = attack_module
ruleset.save
end

# fetches rules with snortor
# and stores them all into db
def import_rules
raise "rules imported already" if FIDIUS::EvasionDB::Knowledge::IdsRule.all.size > 0
import_rules_to_snortor

start_time = Time.now
puts "rules exported save to db now"

i = 0
insert_query = []
Snortor.rules.each do |rule|
if rule.message
insert_query << FIDIUS::EvasionDB::Knowledge::IdsRule.sub_query_for_insert(rule.message,i)
i += 1
end
end
begin
FIDIUS::EvasionDB::Knowledge::IdsRule.connection.execute("INSERT IGNORE INTO ids_rules (rule_text,rule_hash,sort) VALUES #{insert_query.join(',')};")
rescue
begin
# try without IGNORE statement
FIDIUS::EvasionDB::Knowledge::IdsRule.connection.execute("INSERT INTO ids_rules (rule_text,rule_hash,sort) VALUES #{insert_query.join(',')};")
rescue
puts $!.message+":"+$!.backtrace.to_s
end
end
end_time = Time.now
puts "Import needed #{end_time-start_time} seconds"
end

def config(conf)
return unless conf
conf = conf["snort-fetcher"]
return unless conf.class == Hash

@@rule_path = conf["rule_path"]#"/home/bernd/fidius/snort/rules/fetched"

@@ssh_host = conf["ssh_host"] #"10.10.10.254"
@@ssh_pw = conf["ssh_pw"]#"fidius09"
@@ssh_remote_path = conf["ssh_remote_path"] #"/etc/snort/rules/"
@@ssh_user = conf["ssh_user"] #"fidius"
@@fetch_remote = @@ssh_host != nil
end

def self.ssh_options=(a)
@@ssh_options = a
end
end
end
end
@@ -0,0 +1,7 @@
puts "loading snort_fetcher"
FIDIUS::EvasionDB.rule_fetcher "Snortrule-Fetcher" do
install do
require (File.join File.dirname(__FILE__), 'lib', 'snort.rb')
self.extend FIDIUS::EvasionDB::SnortRuleFetcher
end
end
@@ -0,0 +1,66 @@
# NAME: BitField
# AUTHOR: Peter Cooper
# LICENSE: MIT ( http://www.opensource.org/licenses/mit-license.php )
# COPYRIGHT: (c) 2007 Peter Cooper (http://www.petercooper.co.uk/)
# VERSION: v4
# HISTORY: v4 (fixed bug where setting 0 bits to 0 caused a set to 1)
# v3 (supports dynamic bitwidths for array elements.. now doing 32 bit widths default)
# v2 (now uses 1 << y, rather than 2 ** y .. it's 21.8 times faster!)
# v1 (first release)
#
# DESCRIPTION: Basic, pure Ruby bit field. Pretty fast (for what it is) and memory efficient.
# I've written a pretty intensive test suite for it and it passes great.
# Works well for Bloom filters (the reason I wrote it).
#
# Create a bit field 1000 bits wide
# bf = BitField.new(1000)
#
# Setting and reading bits
# bf[100] = 1
# bf[100] .. => 1
# bf[100] = 0
#
# More
# bf.to_s = "10101000101010101" (example)
# bf.total_set .. => 10 (example - 10 bits are set to "1")
class BitField
attr_reader :size
include Enumerable

ELEMENT_WIDTH = 32

def initialize(size)
@size = size
@field = Array.new(((size - 1) / ELEMENT_WIDTH) + 1, 0)
end

# Set a bit (1/0)
def []=(position, value)
if value == 1
@field[position / ELEMENT_WIDTH] |= 1 << (position % ELEMENT_WIDTH)
elsif (@field[position / ELEMENT_WIDTH]) & (1 << (position % ELEMENT_WIDTH)) != 0
@field[position / ELEMENT_WIDTH] ^= 1 << (position % ELEMENT_WIDTH)
end
end

# Read a bit (1/0)
def [](position)
@field[position / ELEMENT_WIDTH] & 1 << (position % ELEMENT_WIDTH) > 0 ? 1 : 0
end

# Iterate over each bit
def each(&block)
@size.times { |position| yield self[position] }
end

# Returns the field as a string like "0101010100111100," etc.
def to_s
inject("") { |a, b| a + b.to_s }
end

# Returns the total number of bits that are set
# (The technique used here is about 6 times faster than using each or inject direct on the bitfield)
def total_set
@field.inject(0) { |a, byte| a += byte & 1 and byte >>= 1 until byte == 0; a }
end
end
@@ -1,5 +1,5 @@
module FIDIUS
module EvasionDB
VERSION = "0.0.1"
VERSION = "0.0.2"
end
end
@@ -12,9 +12,10 @@ module EvasionDB
GEM_BASE = File.expand_path('..', __FILE__)
$logger.debug "GEM_BASE ist: #{GEM_BASE}"

autoload :VERSION, 'evasion-db/version'
autoload :LogMatchesHelper, 'evasion-db/log_matches_helper'
autoload :Knowledge, 'evasion-db/knowledge'
autoload :VERSION, "#{GEM_BASE}/evasion-db/version"
autoload :LogMatchesHelper, "#{GEM_BASE}/evasion-db/log_matches_helper"
autoload :Knowledge, "#{GEM_BASE}/evasion-db/knowledge"
autoload :BitField, "#{GEM_BASE}/evasion-db/vendor/bitfield"

# install fetchers
require File.join(GEM_BASE, 'evasion-db', 'idmef-fetchers', 'fetchers.rb')
@@ -23,5 +24,9 @@ module EvasionDB
# install recorders
require File.join(GEM_BASE, 'evasion-db', 'recorders', 'recorders.rb')
FIDIUS::EvasionDB.install_recorders

# install rule_recorder
require File.join(GEM_BASE, 'evasion-db', 'rule_fetchers', 'rule_fetchers.rb')
FIDIUS::EvasionDB.install_rule_fetchers
end
end
@@ -22,3 +22,13 @@ evasion_db:
username: root
password:
socket: /opt/lampp/var/mysql/mysql.sock

snort-fetcher:
# path with *.rules files
rule_path: /home/bernd/fidius/snort/rules/fetched
# optional ssh credentials
# content of folder remote_path will be copied via ssh tu rule_path
ssh_host: 10.10.10.254
ssh_pw: fidius09
ssh_remote_path: /etc/snort/rules/
ssh_user: root
@@ -34,7 +34,9 @@ def commands
"send_event_payload" => "send a given payload of an idmef-event to generate false positive",
"config_exploit" => "configures an exploit with the options of a previous runtime",
"delete_events" => "deletes events from knowledge",
"set_autologging" => "true|false automatically log all executed modules"
"set_autologging" => "true|false automatically log all executed modules",
"import_rules" => "import rules based on your config (this could take some time)",
"assign_rules_to_attack" => "assigns bitvector of activated rules to the given attack"
}
end

@@ -113,6 +115,17 @@ def send_payload_to_host(payload,host,port)
end
end

def cmd_import_rules(*args)
FIDIUS::EvasionDB.current_rule_fetcher.import_rules
end

def cmd_assign_rules_to_attack(*args)
raise "please provide an attack module id" if args.size != 1
a = FIDIUS::EvasionDB::Knowledge::AttackModule.find(args[0].to_i)
FIDIUS::EvasionDB.current_rule_fetcher.fetch_rules(a)
end


def cmd_send_packet(*args)
raise "please provide packet id" if args.size != 1
packet = FIDIUS::EvasionDB::Knowledge.get_packet(args[0].to_i)
@@ -134,6 +147,14 @@ def cmd_show_events(*args)
print_line "-"*60
print_line "#{events.size} idmef-events fetched"
print_line "-"*60

if exploit.enabled_rules
print_line "-"*60
all = exploit.enabled_rules.count(:all)
active = exploit.enabled_rules.count(:active)
print_line "Rules: #{active}/#{all}"
print_line "-"*60
end
events.each do |event|
print_line "(#{event.id})#{event.text} with #{event.payload_size} bytes payload"
end
@@ -221,6 +242,8 @@ def initialize(framework, opts)
FIDIUS::EvasionDB.config(dbconfig_path)
FIDIUS::EvasionDB.use_recoder "Msf-Recorder"
FIDIUS::EvasionDB.use_fetcher "PreludeDB"
FIDIUS::EvasionDB.use_rule_fetcher "Snortrule-Fetcher"
FIDIUS::EvasionDB::SnortRuleFetcher.ssh_options = {:auth_methods=>["password"],:msfmodule=>FIDIUS::MsfModuleStub}

add_console_dispatcher(ConsoleCommandDispatcher)
framework.events.add_general_subscriber(FIDIUS::ModuleRunCallback.new)
@@ -376,3 +399,13 @@ def initlog
end
end #SocketTracer
end #FIDIUS

module FIDIUS
class MsfModuleStub
# do nothing to prevent metasploits lib/net/ssh.rb from dieing
def self.add_socket(a)
end
def self.remove_socket(a)
end
end
end
@@ -9,3 +9,10 @@ ids_db:
database: ids_db.sqlite3
pool: 5
timeout: 5000

snort-fetcher:
rule_path: test/fixtures
#ssh_host: 10.10.10.254
#ssh_pw: fidius09
#ssh_remote_path: /etc/snort/rules/
#ssh_user: fidius
@@ -0,0 +1,3 @@
alert tcp $EXTERNAL_NET any <> $HOME_NET 0 (msg:"BAD-TRAFFIC tcp port 0 traffic"; flow:stateless; classtype:misc-activity; sid:524; rev:8;)
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;)

@@ -99,4 +99,27 @@ def test_find_events_for_exploit
assert_equal 1,events.size

end

def test_rule_models
IdsRule.create(:rule_text=>"Wurst1")
IdsRule.create(:rule_text=>"Wurst2")

e = EnabledRules.create(:bitstring=>"00101")
e.attack_module = FIDIUS::EvasionDB::Knowledge::AttackModule.first
e.save
end

def test_ids_rule_helpers
IdsRule.create_if_not_exists("wurst",0)
IdsRule.create_if_not_exists("brot",1)
IdsRule.create_if_not_exists("hans",2)
IdsRule.create_if_not_exists("hans",2)

assert_equal 3, IdsRule.all.size

assert_equal 0, IdsRule.find_by_rule_text("wurst").sort
assert_equal 1, IdsRule.find_by_rule_text("brot").sort
assert_equal 2, IdsRule.find_by_rule_text("hans").sort
end

end
@@ -0,0 +1,17 @@
require 'helper'

class TestRuleFetchers < Test::Unit::TestCase
def test_rule_fetcher
FIDIUS::EvasionDB::Knowledge::EnabledRules.destroy_all
FIDIUS::EvasionDB::Knowledge::IdsRule.destroy_all

FIDIUS::EvasionDB.use_rule_fetcher "Snortrule-Fetcher"
FIDIUS::EvasionDB::current_rule_fetcher.fetch_rules(FIDIUS::EvasionDB::Knowledge::AttackModule.new)

# cant provide this for sqlite
#assert_equal 2, FIDIUS::EvasionDB::Knowledge::IdsRule.all.size
assert_equal 1, FIDIUS::EvasionDB::Knowledge::EnabledRules.all.size
enabled_rules = FIDIUS::EvasionDB::Knowledge::EnabledRules.first
assert_equal "11", enabled_rules.bitstring
end
end