Module: Arachni::Element::Capabilities::Auditable
- Included in:
- Base
- Defined in:
- lib/arachni/element/capabilities/auditable.rb,
lib/arachni/element/capabilities/auditable/rdiff.rb,
lib/arachni/element/capabilities/auditable/timeout.rb
Overview
Provides audit functionality to Mutable elements.
Defined Under Namespace
Modules: RDiff, Taint, Timeout
Constant Summary collapse
- OPTIONS =
Default audit options.
{ # Enable skipping of already audited inputs. redundant: false, # Make requests asynchronously. async: true, # Block to be passed each mutation right before being submitted. # # Allows for last minute changes. each_mutation: nil, # Block to be passed each mutation to determine if it should be skipped. skip_like: nil }
Constants included from RDiff
Constants included from Taint
Taint::REMARK, Taint::TAINT_OPTIONS
Constants included from Mutable
Instance Attribute Summary collapse
-
#auditor ⇒ Arachni::Module::Auditor
Sets the auditor for this element.
-
#opts ⇒ Hash
readonly
Audit and general options for convenience’s sake.
-
#orig ⇒ Hash
(also: #original)
readonly
Frozen version of #auditable, has all the original name/values.
Attributes included from Mutable
Class Method Summary collapse
-
.reset ⇒ Object
Empties the de-duplication/uniqueness look-up table.
-
.reset_instance_scope ⇒ Object
Removes workload restrictions and allows all elements to be audited.
-
.restrict_to_elements(elements) ⇒ Object
Restricts the audit to a specific set of elements.
-
.skip_like(&block) ⇒ Auditable
‘self`.
Instance Method Summary collapse
- #==(e) ⇒ Object (also: #eql?)
-
#[](k) ⇒ String
Shorthand #auditable reader.
-
#[]=(k, v) ⇒ Object
Shorthand #auditable writer.
-
#audit(payloads, opts = { }, &block) ⇒ Boolean?
Submits mutations of self and calls the block to handle the responses.
-
#audit_id(injection_str = '', opts = {}) ⇒ String
Returns an audit ID string used to identify the audit of ‘self` by its #auditor.
-
#auditable ⇒ Hash
Frozen inputs.
- #auditable=(hash) ⇒ Object
-
#changes ⇒ Hash
Returns changes make to the #auditable‘s inputs.
-
#debug? ⇒ Boolean
Delegate output related methods to the auditor.
-
#has_inputs?(*args) ⇒ Bool
Checks whether or not the given inputs match the auditable ones.
- #hash ⇒ Object
- #http ⇒ Arachni::HTTP
-
#http_request(opts, &block) ⇒ Typhoeus::Request
abstract
Must be implemented by the including class and perform the appropriate HTTP request (get/post/whatever) for the current element.
-
#matches_skip_like_blocks? ⇒ Boolean
‘true` if the element matches one or more Auditable.skip_like_blocks, `false` otherwise.
-
#orphan? ⇒ Bool
‘true` if it has no auditor, `false` otherwise.
-
#override_instance_scope ⇒ Object
When working in High Performance Grid mode the instances have a very specific list of elements which they are allowed to audit.
-
#override_instance_scope? ⇒ Boolean
Does this element override the instance scope?.
- #print_bad(str = '') ⇒ Object
- #print_debug(str = '') ⇒ Object
- #print_debug_backtrace(str = '') ⇒ Object
- #print_error(str = '') ⇒ Object
- #print_error_backtrace(str = '') ⇒ Object
- #print_info(str = '') ⇒ Object
- #print_line(str = '') ⇒ Object
- #print_ok(str = '') ⇒ Object
- #print_status(str = '') ⇒ Object
-
#provisioned_issue_id(auditor_fanxy_name = @auditor.fancy_name) ⇒ String
Predicts what the Issue#unique_id of an issue would look like, should ‘self` be vulnerable.
-
#remove_auditor ⇒ Object
Removes the #auditor from this element.
-
#reset ⇒ Object
Resets the auditable inputs to their original format/values.
- #reset_scope_override ⇒ Object
-
#scope_audit_id(opts = {}) ⇒ Integer
Provides a more generalized audit ID which does not take into account the auditor’s name nor timeout value of injection string.
-
#skip?(elem) ⇒ Boolean
abstract
‘true` if `self` should be audited, `false` otherwise.
-
#status_string ⇒ String
Status string explaining what’s being audited.
-
#submit(opts = {}, &block) ⇒ Object
Submits self using #http_request.
-
#update(hash) ⇒ Auditable
Self.
-
#use_anonymous_auditor ⇒ Object
Assigns an anonymous auditor as an #auditor.
Methods included from RDiff
Methods included from Timeout
add_timeout_candidate, add_timeout_phase3_candidate, call_on_timing_blocks, #call_on_timing_blocks, current_timeout_audit_operations_cnt, deduplicate?, #deduplicate?, disable_deduplication, #disable_deduplication, #enable_deduplication, enable_deduplication, included, on_timing_attacks, #responsive?, running_timeout_attacks?, #timeout_analysis, timeout_analysis_phase_2, timeout_analysis_phase_3, timeout_audit_operations_cnt, timeout_audit_run, timeout_candidates, timeout_loaded_modules
Methods included from Taint
Methods included from Mutable
#altered_value, #altered_value=, #each_mutation, #immutables, #mutated?, #mutations, #mutations_for, #original?, #permutations, #permutations_for, #switch_method
Methods included from Utilities
#available_port, #cookie_encode, #cookies_from_document, #cookies_from_file, #cookies_from_response, #exception_jail, #exclude_path?, #extract_domain, #follow_protocol?, #form_decode, #form_encode, #form_parse_request_body, #forms_from_document, #forms_from_response, #generate_token, #get_path, #html_decode, #html_encode, #include_path?, #links_from_document, #links_from_response, #normalize_url, #page_from_response, #page_from_url, #parse_query, #parse_set_cookie, #parse_url_vars, #path_in_domain?, #path_too_deep?, #port_available?, #rand_port, #redundant_path?, #remove_constants, #seed, #skip_page?, #skip_resource?, #to_absolute, #uri_decode, #uri_encode, #uri_parse, #uri_parser, #url_sanitize
Instance Attribute Details
#auditor ⇒ Arachni::Module::Auditor
Sets the auditor for this element.
The auditor provides its output, HTTP and issue logging interfaces.
49 50 51 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 49 def auditor @auditor end |
#opts ⇒ Hash (readonly)
Returns Audit and general options for convenience’s sake.
62 63 64 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 62 def opts @opts end |
#orig ⇒ Hash (readonly) Also known as: original
Frozen version of #auditable, has all the original name/values.
56 57 58 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 56 def orig @orig end |
Class Method Details
.reset ⇒ Object
Empties the de-duplication/uniqueness look-up table.
Unless you’re sure you need this, set the :redundant flag to true when calling audit methods to bypass it.
89 90 91 92 93 94 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 89 def self.reset @@audited = Support::LookUp::HashSet.new @@skip_like_blocks = [] Timeout.reset end |
.reset_instance_scope ⇒ Object
Removes workload restrictions and allows all elements to be audited.
98 99 100 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 98 def self.reset_instance_scope @@restrict_to_elements = Support::LookUp::HashSet.new( hasher: :to_i ) end |
.restrict_to_elements(elements) ⇒ Object
Restricts the audit to a specific set of elements.
Caution: Each call overwrites the last.
113 114 115 116 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 113 def self.restrict_to_elements( elements ) self.reset_instance_scope elements.each { |elem| @@restrict_to_elements << elem } end |
.skip_like(&block) ⇒ Auditable
Returns ‘self`.
122 123 124 125 126 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 122 def self.skip_like( &block ) fail 'Missing block.' if !block_given? skip_like_blocks << block self end |
Instance Method Details
#==(e) ⇒ Object Also known as: eql?
263 264 265 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 263 def ==( e ) hash == e.hash end |
#[](k) ⇒ String
Shorthand #auditable reader.
246 247 248 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 246 def []( k ) self.auditable[k.to_s] end |
#[]=(k, v) ⇒ Object
Shorthand #auditable writer.
258 259 260 261 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 258 def []=( k, v ) update( { k => v } ) [k] end |
#audit(payloads, opts = { }, &block) ⇒ Boolean?
427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 427 def audit( payloads, opts = { }, &block ) fail ArgumentError, 'Missing block.' if !block_given? return false if self.auditable.empty? case payloads when String audit_single( payloads, opts, &block ) when Array return if payloads.empty? payloads.each do |payload| audit_single( payload, opts, &block ) end when Hash platform_payloads = platforms.any? ? platforms.pick( payloads ) : payloads return if platform_payloads.empty? payload_platforms = Set.new( payloads.keys ) platform_payloads.each do |platform, payloads_for_platform| audit( [payloads_for_platform].flatten.compact, opts.merge( platform: platform, payload_platforms: payload_platforms ), &block ) end else raise ArgumentError, "Unsupported payload type '#{payloads.class}'. " << 'Expected one of: String, Array, Hash' end end |
#audit_id(injection_str = '', opts = {}) ⇒ String
Mostly used to keep track of what audits have been perform in order to prevent redundancies.
Returns an audit ID string used to identify the audit of ‘self` by its #auditor.
496 497 498 499 500 501 502 503 504 505 506 507 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 496 def audit_id( injection_str = '', opts = {} ) vars = auditable.keys.sort.to_s str = '' str << "#{@auditor.fancy_name}:" if !opts[:no_auditor] && !orphan? str << "#{@action}:#{type}:#{vars}" str << "=#{injection_str}" if !opts[:no_injection_str] str << ":timeout=#{opts[:timeout]}" if !opts[:no_timeout] str end |
#auditable ⇒ Hash
Frozen inputs.
If you want to change it you’ll either have to use #update or the #auditable= attr_writer and pass a new hash – the new hash will also be frozen.
181 182 183 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 181 def auditable @auditable.freeze end |
#auditable=(hash) ⇒ Object
Will convert keys and values to strings.
192 193 194 195 196 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 192 def auditable=( hash ) @auditable = (hash || {}).inject({}) { |h, (k, v)| h[k.to_s] = v.to_s.freeze; h} rehash self.auditable end |
#changes ⇒ Hash
Returns changes make to the #auditable‘s inputs.
230 231 232 233 234 235 236 237 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 230 def changes (self.orig.keys | self.auditable.keys).inject( {} ) do |h, k| if self.orig[k] != self.auditable[k] h[k] = self.auditable[k] end h end end |
#debug? ⇒ Boolean
Delegate output related methods to the auditor
532 533 534 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 532 def debug? @auditor.debug? rescue false end |
#has_inputs?(*args) ⇒ Bool
Checks whether or not the given inputs match the auditable ones.
206 207 208 209 210 211 212 213 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 206 def has_inputs?( *args ) if (h = args.first).is_a?( Hash ) h.each { |k, v| return false if self[k] != v } else keys = args.flatten.compact.map { |a| [a].map( &:to_s ) }.flatten (self.auditable.keys & keys).size == keys.size end end |
#hash ⇒ Object
268 269 270 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 268 def hash @hash ||= rehash end |
#http ⇒ Arachni::HTTP
338 339 340 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 338 def http HTTP end |
#http_request(opts, &block) ⇒ Typhoeus::Request
Must be implemented by the including class and perform the appropriate HTTP request (get/post/whatever) for the current element.
Invoked by #submit to submit the object.
334 335 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 334 def http_request( opts, &block ) end |
#matches_skip_like_blocks? ⇒ Boolean
Returns ‘true` if the element matches one or more skip_like_blocks, `false` otherwise.
524 525 526 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 524 def matches_skip_like_blocks? Arachni::Element::Capabilities::Auditable.matches_skip_like_blocks?( self ) end |
#orphan? ⇒ Bool
Returns ‘true` if it has no auditor, `false` otherwise.
343 344 345 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 343 def orphan? !@auditor end |
#override_instance_scope ⇒ Object
When working in High Performance Grid mode the instances have a very specific list of elements which they are allowed to audit.
Elements which do not fit the scope are ignored.
When called, the element will override the scope and be audited no-matter what.
This is mainly used on elements discovered during audit-time by the trainer.
283 284 285 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 283 def override_instance_scope @override_instance_scope = true end |
#override_instance_scope? ⇒ Boolean
Does this element override the instance scope?
296 297 298 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 296 def override_instance_scope? @override_instance_scope ||= false end |
#print_bad(str = '') ⇒ Object
556 557 558 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 556 def print_bad( str = '' ) @auditor.print_bad( str ) if !orphan? end |
#print_debug(str = '') ⇒ Object
560 561 562 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 560 def print_debug( str = '' ) @auditor.print_debug( str ) if !orphan? end |
#print_debug_backtrace(str = '') ⇒ Object
564 565 566 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 564 def print_debug_backtrace( str = '' ) @auditor.print_debug_backtrace( str ) if !orphan? end |
#print_error(str = '') ⇒ Object
536 537 538 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 536 def print_error( str = '' ) @auditor.print_error( str ) if !orphan? end |
#print_error_backtrace(str = '') ⇒ Object
568 569 570 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 568 def print_error_backtrace( str = '' ) @auditor.print_error_backtrace( str ) if !orphan? end |
#print_info(str = '') ⇒ Object
544 545 546 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 544 def print_info( str = '' ) @auditor.print_info( str ) if !orphan? end |
#print_line(str = '') ⇒ Object
548 549 550 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 548 def print_line( str = '' ) @auditor.print_line( str ) if !orphan? end |
#print_ok(str = '') ⇒ Object
552 553 554 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 552 def print_ok( str = '' ) @auditor.print_ok( str ) if !orphan? end |
#print_status(str = '') ⇒ Object
540 541 542 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 540 def print_status( str = '' ) @auditor.print_status( str ) if !orphan? end |
#provisioned_issue_id(auditor_fanxy_name = @auditor.fancy_name) ⇒ String
Mainly used by Module::Auditor#skip? to prevent redundant audits for elements/issues which have already been logged as vulnerable.
Returns Predicts what the Issue#unique_id of an issue would look like, should ‘self` be vulnerable.
515 516 517 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 515 def provisioned_issue_id( auditor_fanxy_name = @auditor.fancy_name ) "#{auditor_fanxy_name}::#{type}::#{altered}::#{self.action.split( '?' ).first}" end |
#remove_auditor ⇒ Object
Removes the #auditor from this element.
353 354 355 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 353 def remove_auditor @auditor = nil end |
#reset ⇒ Object
Resets the auditable inputs to their original format/values.
348 349 350 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 348 def reset self.auditable = @orig.dup end |
#reset_scope_override ⇒ Object
287 288 289 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 287 def reset_scope_override @override_instance_scope = false end |
#scope_audit_id(opts = {}) ⇒ Integer
Provides a more generalized audit ID which does not take into account the auditor’s name nor timeout value of injection string.
Right now only used when in multi-Instance mode to generate a white-list of element IDs that are allowed to be audited.
311 312 313 314 315 316 317 318 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 311 def scope_audit_id( opts = {} ) opts = {} if !opts audit_id( nil, opts.merge( no_auditor: true, no_timeout: true, no_injection_str: true )).persistent_hash end |
#skip?(elem) ⇒ Boolean
To be overridden by auditable element implementations for more fine-grained audit control.
Returns ‘true` if `self` should be audited, `false` otherwise.
470 471 472 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 470 def skip?( elem ) false end |
#status_string ⇒ String
Returns Status string explaining what’s being audited.
The string contains the name of the input that is being audited, the url and the type of the input (form, link, cookie…).
480 481 482 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 480 def status_string "Auditing #{self.type} variable '#{self.altered}' with action '#{self.action}'." end |
#submit(opts = {}, &block) ⇒ Object
Submits self using #http_request.
365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 365 def submit( opts = {}, &block ) opts = OPTIONS.merge( opts ) opts[:params] = @auditable.dup opts[:follow_location] = true if !opts.include?( :follow_location ) @opts ||= {} opts = @opts.merge( opts ) @opts = opts @auditor ||= opts[:auditor] if opts[:auditor] use_anonymous_auditor if !@auditor opts.delete( :auditor ) http_request( opts, &block ) end |
#update(hash) ⇒ Auditable
Returns self.
224 225 226 227 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 224 def update( hash ) self.auditable = self.auditable.merge( hash ) self end |
#use_anonymous_auditor ⇒ Object
Assigns an anonymous auditor as an #auditor.
Alleviates the need to assign a custom auditor for simple stuff when scripting.
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 134 def use_anonymous_auditor self.auditor = Class.new do include Arachni::Module::Auditor def initialize @framework = Arachni::Framework.new end # # @return [Array<Issue>] Unfiltered logged issues. # # @see Arachni::Module::Manager.results # def raw_issues Arachni::Module::Manager.results end # # @return [Array<Issue>] Deduplicated issues. # # @see AuditStore#issues # def issues auditstore.issues end # @return [AuditStore] def auditstore AuditStore.new( options: Options.instance.to_h, issues: raw_issues ) end alias :audit_store :auditstore def self.info { name: 'Anonymous auditor' } end end.new end |