lib/arachni/audit_store.rb in arachni-0.4.0.4 vs lib/arachni/audit_store.rb in arachni-0.4.1
- old
+ new
@@ -1,31 +1,33 @@
=begin
- Arachni
- Copyright (c) 2010-2012 Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
+ Copyright 2010-2012 Tasos Laskos <tasos.laskos@gmail.com>
- This is free software; you can copy and distribute and modify
- this program under the term of the GPL v2.0 License
- (See LICENSE file for details)
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
=end
require 'digest/md5'
module Arachni
-require Options.instance.dir['lib'] + 'issue'
+require Options.dir['lib'] + 'issue'
#
-# Arachni::AuditStore class
+# Represents a finished audit session.
#
-# Represents a finished audit session.<br/>
# It holds information about the runtime environment,
# the results of the audit etc...
#
-# @author: Tasos "Zapotek" Laskos
-# <tasos.laskos@gmail.com>
-# <zapotek@segfault.gr>
-# @version: 0.1.2
+# @author Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
#
class AuditStore
#
# @return [String] the version of the framework
@@ -73,38 +75,39 @@
attr_reader :delta_time
MODULE_NAMESPACE = ::Arachni::Modules
ORDER = [
- ::Arachni::Issue::Severity::HIGH,
- ::Arachni::Issue::Severity::MEDIUM,
- ::Arachni::Issue::Severity::LOW,
- ::Arachni::Issue::Severity::INFORMATIONAL
+ Severity::HIGH,
+ Severity::MEDIUM,
+ Severity::LOW,
+ Severity::INFORMATIONAL
]
- def initialize( audit = {} )
+ def initialize( opts = {} )
@plugins = {}
@sitemap = []
+ @issues ||= []
+ @options ||= Options
+
# set instance variables from audit opts
- audit.each {
- |k, v|
- self.instance_variable_set( '@' + k.to_s, v )
- }
+ opts.each { |k, v| self.instance_variable_set( '@' + k.to_s, v ) }
- @options = prepare_options( @options )
- @issues = sort( prepare_variations( @issues ) )
- if @options['start_datetime']
- @start_datetime = @options['start_datetime'].asctime
+ @options = prepare_options( @options )
+ @issues = sort( prepare_variations( @issues.deep_clone ) )
+
+ @start_datetime = if @options['start_datetime']
+ @options['start_datetime'].asctime
else
- @start_datetime = Time.now.asctime
+ Time.now.asctime
end
- if @options['finish_datetime']
- @finish_datetime = @options['finish_datetime'].asctime
+ @finish_datetime = if @options['finish_datetime']
+ @options['finish_datetime'].asctime
else
- @finish_datetime = Time.now.asctime
+ Time.now.asctime
end
@delta_time = secs_to_hms( @options['delta_time'] )
end
@@ -113,11 +116,11 @@
#
# @param [String] file the file to load
#
# @return [AuditStore]
#
- def AuditStore.load( file )
+ def self.load( file )
begin
r = YAML.load( IO.read( file ) )
r.version
r
rescue Exception => e
@@ -130,60 +133,58 @@
#
# @param [String] file
#
def save( file )
begin
- File.open( file, 'w' ) {
- |f|
- f.write( YAML.dump( self ) )
- }
+ File.open( file, 'w' ) { |f| f.write( YAML.dump( self ) ) }
rescue
- File.open( file, 'wb' ) {
- |f|
- f.write( Marshal.dump( self ) )
- }
+ File.open( file, 'wb' ) { |f| f.write( Marshal.dump( self ) ) }
end
end
#
# Returns 'self' and all objects in its instance vars as hashes
#
# @return [Hash]
#
- def to_h
- hash = obj_to_hash( self ).dup
+ def to_hash
+ hash = obj_to_hash( self ).deep_clone
- hash['issues'] = hash['issues'].map {
- |issue|
+ hash['issues'] = hash['issues'].map do |issue|
issue.variations = issue.variations.map { |var| obj_to_hash( var ) }
obj_to_hash( issue )
- }
+ end
- hash['plugins'].each {
- |plugin, results|
+ hash['plugins'].each do |plugin, results|
next if !results[:options]
- hash['plugins'][plugin][:options] = hash['plugins'][plugin][:options].map {
- |opt|
- opt.to_h
- }
- }
+ hash['plugins'][plugin][:options] =
+ hash['plugins'][plugin][:options].map { |opt| opt.to_h }
+ end
- return hash
+ hash
end
+ alias :to_h :to_hash
+ def ==( other )
+ to_hash == other.to_hash
+ end
+
+ def hash
+ to_hash.hash
+ end
+
private
def sort( issues )
sorted = []
- issues.each {
- |issue|
- sorted[ORDER.rindex( issue.severity )] ||= []
- sorted[ORDER.rindex( issue.severity )] << issue
- }
-
- return sorted.flatten.reject{ |issue| issue.nil? }
+ issues.each do |issue|
+ order = ORDER.rindex( issue.severity ) || ORDER.size
+ sorted[order] ||= []
+ sorted[order] << issue
+ end
+ sorted.flatten.compact
end
#
# Converts obj to hash
@@ -192,61 +193,53 @@
#
# @return [Hash]
#
def obj_to_hash( obj )
hash = {}
- obj.instance_variables.each {
- |var|
- key = var.to_s.gsub( /@/, '' )
- hash[key] = obj.instance_variable_get( var )
- }
- return hash
+ obj.instance_variables.each do |var|
+ hash[var.to_s.gsub( /@/, '' )] = obj.instance_variable_get( var )
+ end
+ hash
end
#
# Prepares the hash to be stored in {AuditStore#options}
#
- # The 'options' dimention of the array that initializes AuditObjects<br/>
+ # The value of the 'options' key of the hash that initializes AuditObjects
# needs some more processing before being saved in {AuditStore#options}.
#
- # @param [Hash]
+ # @param [Hash] options
#
# @return [Hash]
#
def prepare_options( options )
- options['url'] = options['url'].to_s
+ new_options = {}
- new_options = Hash.new
- options.each_pair {
- |key, val|
-
- new_options[key.to_s] = val
-
+ options = options.to_hash
+ options['url'] = options['url'].to_s
+ options.each_pair do |key, val|
case key
+ when 'redundant'
+ new_options[key.to_s] = {}
+ val.each do |regexp, counter|
+ new_options[key.to_s].merge!( regexp.to_s => counter )
+ end
- when 'redundant'
- new_options[key.to_s] = []
- val.each {
- |red|
- new_options[key.to_s] << {
- 'regexp' => red['regexp'].to_s,
- 'count' => red['count']
- }
- }
+ when 'exclude', 'include'
+ new_options[key.to_s] = []
+ val.each { |regexp| new_options[key.to_s] << regexp.to_s }
- when 'exclude', 'include'
- new_options[key.to_s] = []
- val.each {
- |regexp|
- new_options[key.to_s] << regexp.to_s
- }
+ when 'cookies'
+ next if !val
+ new_options[key.to_s] = val.inject( {} ){ |h, c| h.merge!( c.simple ) }
+ else
+ new_options[key.to_s] = val
end
+ end
- }
-
- return new_options
+ new_options
end
#
# Parses the issues in "issue" and aggregates them
# creating variations of the same attacks.
@@ -257,97 +250,72 @@
#
# @return [Array<Issue>] new array of Issue instances
# with populated {Issue#variations}
#
def prepare_variations( issues )
+ variation_keys = %w(injected id regexp regexp_match headers response opts)
- variation_keys = [
- 'injected',
- 'id',
- 'regexp',
- 'regexp_match',
- 'headers',
- 'response',
- 'opts'
- ]
-
new_issues = {}
- issues.each {
- |issue|
+ issues.each do |issue|
+ __id = issue.hash
+ new_issues[__id] ||= issue
+ new_issues[__id].variations ||= []
- var = issue.var || ''
-
- __id = issue.mod_name +
- '::' + issue.elem + '::' +
- var + '::' +
- issue.url.split( /\?/ )[0].gsub( '//', '/' )
-
- orig_url = issue.url
- issue.url = issue.url.split( /\?/ )[0]
-
- new_issues[__id] = issue if !new_issues[__id]
- new_issues[__id].variations = [] if !new_issues[__id].variations
-
issue.headers ||= {}
issue.headers['request'] ||= {}
- (issue.headers[:request] || {}).each {
- |k, v|
+ (issue.headers[:request] || {}).each do |k, v|
issue.headers['request'][k] = v.dup if v
- }
+ end
issue.headers['response'] ||= {}
issue.headers['response'] = (issue.headers[:response] || '').dup
issue.headers.delete( :request )
issue.headers.delete( :response )
- new_issues[__id]._hash = Digest::MD5.hexdigest( __id )
- new_issues[__id].internal_modname =
+ new_issues[__id].internal_modname ||=
get_internal_module_name( new_issues[__id].mod_name )
new_issues[__id].variations << issue.deep_clone
- variation_keys.each {
- |key|
- if( new_issues[__id].instance_variable_defined?( '@' + key ) )
+ variation_keys.each do |key|
+ if new_issues[__id].instance_variable_defined?( '@' + key )
new_issues[__id].remove_instance_var( '@' + key )
end
- }
+ end
+ end
- }
+ new_issues.values.each do |i|
+ next if !i.variations || !i.injected
+ i.variations.each do |v|
+ v.remove_instance_var( :@variations ) rescue next
+ end
+ end
issue_keys = new_issues.keys
new_issues = new_issues.to_a.flatten
- issue_keys.each {
- |key|
- new_issues.delete( key )
- }
-
+ issue_keys.each { |key| new_issues.delete( key ) }
new_issues
end
def get_internal_module_name( modname )
- MODULE_NAMESPACE.constants.each {
- |mod|
+ MODULE_NAMESPACE.constants.each do |mod|
klass = MODULE_NAMESPACE.const_get( mod )
return mod.to_s if klass.info[:name] == modname
- }
+ end
end
#
# Converts seconds to a (00:00:00) (hours:minutes:seconds) string
#
- # @param [String,Float,Integer] seconds
+ # @param [String,Float,Integer] secs seconds
#
# @return [String] hours:minutes:seconds
#
def secs_to_hms( secs )
secs = secs.to_i
- return [secs/3600, secs/60 % 60, secs % 60].map {
- |t|
- t.to_s.rjust( 2, '0' )
- }.join(':')
+ [secs/3600, secs/60 % 60, secs % 60].map { |t| t.to_s.rjust( 2, '0' ) }.join( ':' )
end
end
end