Module: Arachni::Element::Capabilities::Auditable
- Included in:
- Base
- Defined in:
- lib/arachni/element/capabilities/auditable.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 }
Constants included from RDiff
Constants included from Taint
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
-
.restrict_to_elements(elements) ⇒ Object
Restricts the audit to a specific set of elements.
Instance Method Summary collapse
- #==(e) ⇒ Object (also: #eql?)
-
#[](k) ⇒ String
Shorthand #auditable reader.
-
#[]=(k, v) ⇒ Object
Shorthand #auditable writer.
-
#audit(injection_str, opts = { }, &block) ⇒ Object
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 avoid redundant audits or identify the element.
-
#auditable ⇒ Hash
Frozen Key=>value pairs of inputs.
- #auditable=(hash) ⇒ Object
-
#changes ⇒ Object
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
Returns the #auditor‘s HTTP interface or reverts to Arachni::HTTP.instance.
-
#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.
-
#info ⇒ Object
impersonate the auditor to the output methods.
-
#orphan? ⇒ Bool
True if it has no auditor.
-
#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
-
#reset ⇒ Object
Resets the auditable inputs to their original format/values.
- #reset_scope_override ⇒ Object
-
#scope_audit_id(opts = {}) ⇒ Object
Provides a more generalized audit ID which does not contain the auditor’s name, timeout value of injection string.
- #skip?(elem) ⇒ Boolean
- #skip_path?(url) ⇒ Boolean
-
#status_string ⇒ String
Returns a status string explaining what’s being audited.
-
#submit(opts = {}, &block) ⇒ Object
Submits self using #http_request.
-
#update(hash) ⇒ Auditable
Self.
Methods included from RDiff
Methods included from Timeout
add_timeout_audit_block, add_timeout_candidate, #call_on_timing_blocks, call_on_timing_blocks, current_timeout_audit_operations_cnt, included, on_timing_attacks, #responsive?, running_timeout_attacks?, #timeout_analysis, timeout_analysis_phase_2, timeout_audit_blocks, timeout_audit_operations_cnt, timeout_audit_run, timeout_loaded_modules
Methods included from Taint
Methods included from Mutable
#altered_value, #altered_value=, #immutables, #mutated?, #mutations, #mutations_for, #original?, #permutations, #permutations_for
Methods included from Utilities
#cookie_encode, #cookies_from_document, #cookies_from_file, #cookies_from_response, #exception_jail, #exclude_path?, #extract_domain, #form_decode, #form_encode, #form_parse_request_body, #forms_from_document, #forms_from_response, #get_path, #hash_keys_to_str, #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?, #remove_constants, #seed, #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.
62 63 64 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 62 def auditor @auditor end |
#opts ⇒ Hash (readonly)
Returns audit and general options for convenience’s sake.
75 76 77 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 75 def opts @opts end |
#orig ⇒ Hash (readonly) Also known as: original
Frozen version of #auditable, has all the original name/values
69 70 71 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 69 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.
50 51 52 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 50 def self.reset @@audited = BloomFilter.new end |
.reset_instance_scope ⇒ Object
234 235 236 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 234 def self.reset_instance_scope @@restrict_to_elements = BloomFilter.new end |
.restrict_to_elements(elements) ⇒ Object
Restricts the audit to a specific set of elements.
Caution: Each call overwrites the last.
265 266 267 268 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 265 def self.restrict_to_elements( elements ) self.reset_instance_scope elements.each { |elem| @@restrict_to_elements << elem } end |
Instance Method Details
#==(e) ⇒ Object Also known as: eql?
198 199 200 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 198 def ==( e ) hash == e.hash end |
#[](k) ⇒ String
Shorthand #auditable reader
181 182 183 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 181 def []( k ) self.auditable[k.to_s] end |
#[]=(k, v) ⇒ Object
Shorthand #auditable writer
193 194 195 196 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 193 def []=( k, v ) update( { k => v } ) [k] end |
#audit(injection_str, opts = { }, &block) ⇒ Object
Submits mutations of self and calls the block to handle the responses.
Requires an #auditor.
359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 359 def audit( injection_str, opts = { }, &block ) fail 'Block required.' if !block_given? if skip_path?( self.action ) print_debug "Element's action matches skip rule, bailing out (#{self.action})." return false end opts[:injected_orig] = injection_str # if we don't have any auditable elements just return if auditable.empty? print_debug "The element has no auditable inputs, returning." return false end @auditor ||= opts[:auditor] opts[:auditor] ||= @auditor audit_id = audit_id( injection_str, opts ) return false if !opts[:redundant] && audited?( audit_id ) # iterate through all variation and audit each one mutations( injection_str, opts ).each do |elem| if Options.exclude_vectors.include?( elem.altered ) print_info "Skipping audit of '#{elem.altered}' #{type} vector." next end if !orphan? && @auditor.skip?( elem ) mid = elem.audit_id( injection_str, opts ) print_debug "Auditor's #skip? method returned true for mutation, skipping: #{mid}" next end if skip?( elem ) mid = elem.audit_id( injection_str, opts ) print_debug "Self's #skip? method returned true for mutation, skipping: #{mid}" next end opts[:altered] = elem.altered.dup opts[:element] = type # inform the user about what we're auditing print_status( elem.status_string ) if !opts[:silent] if opts[:each_mutation] if elements = opts[:each_mutation].call( elem ) [elements].flatten.compact.each do |e| on_complete( e.submit( opts ), e, &block ) if e.is_a?( self.class ) end end end # submit the element with the injection values on_complete( elem.submit( opts ), elem, &block ) end audited( audit_id ) true end |
#audit_id(injection_str = '', opts = {}) ⇒ String
Returns an audit ID string used to avoid redundant audits or identify the element.
446 447 448 449 450 451 452 453 454 455 456 457 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 446 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 Key=>value pairs of 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.
114 115 116 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 114 def auditable @auditable.freeze end |
#auditable=(hash) ⇒ Object
124 125 126 127 128 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 124 def auditable=( hash ) @auditable = (hash || {}).inject({}) { |h, (k, v)| h[k.to_s] = v.to_s.freeze; h} rehash self.auditable end |
#changes ⇒ Object
Returns changes make to the auditable’s inputs.
165 166 167 168 169 170 171 172 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 165 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
481 482 483 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 481 def debug? @auditor.debug? rescue false end |
#has_inputs?(*args) ⇒ Bool
Checks whether or not the given inputs match the auditable ones.
137 138 139 140 141 142 143 144 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 137 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
203 204 205 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 203 def hash @hash ||= rehash end |
#http ⇒ Arachni::HTTP
Returns the #auditor‘s HTTP interface or reverts to Arachni::HTTP.instance
292 293 294 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 292 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.
284 285 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 284 def http_request( opts, &block ) end |
#info ⇒ Object
impersonate the auditor to the output methods
473 474 475 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 473 def info !orphan? ? @auditor.class.info : { name: '' } end |
#orphan? ⇒ Bool
Returns true if it has no auditor.
299 300 301 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 299 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.
217 218 219 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 217 def override_instance_scope @override_instance_scope = true end |
#override_instance_scope? ⇒ Boolean
Does this element override the instance scope?
230 231 232 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 230 def override_instance_scope? @override_instance_scope ||= false end |
#print_bad(str = '') ⇒ Object
505 506 507 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 505 def print_bad( str = '' ) @auditor.print_bad( str ) if !orphan? end |
#print_debug(str = '') ⇒ Object
509 510 511 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 509 def print_debug( str = '' ) @auditor.print_debug( str ) if !orphan? end |
#print_debug_backtrace(str = '') ⇒ Object
513 514 515 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 513 def print_debug_backtrace( str = '' ) @auditor.print_debug_backtrace( str ) if !orphan? end |
#print_error(str = '') ⇒ Object
485 486 487 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 485 def print_error( str = '' ) @auditor.print_error( str ) if !orphan? end |
#print_error_backtrace(str = '') ⇒ Object
517 518 519 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 517 def print_error_backtrace( str = '' ) @auditor.print_error_backtrace( str ) if !orphan? end |
#print_info(str = '') ⇒ Object
493 494 495 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 493 def print_info( str = '' ) @auditor.print_info( str ) if !orphan? end |
#print_line(str = '') ⇒ Object
497 498 499 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 497 def print_line( str = '' ) @auditor.print_line( str ) if !orphan? end |
#print_ok(str = '') ⇒ Object
501 502 503 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 501 def print_ok( str = '' ) @auditor.print_ok( str ) if !orphan? end |
#print_status(str = '') ⇒ Object
489 490 491 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 489 def print_status( str = '' ) @auditor.print_status( str ) if !orphan? end |
#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.
Mainly used by Module::Auditor#skip? to prevent redundant audits for elements/issues which have already been logged as vulnerable.
468 469 470 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 468 def provisioned_issue_id( auditor_fanxy_name = @auditor.fancy_name ) "#{auditor_fanxy_name}::#{type}::#{altered}::#{self.action.split( '?' ).first}" end |
#remove_auditor ⇒ Object
310 311 312 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 310 def remove_auditor @auditor = nil end |
#reset ⇒ Object
Resets the auditable inputs to their original format/values.
306 307 308 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 306 def reset self.auditable = @orig.dup end |
#reset_scope_override ⇒ Object
221 222 223 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 221 def reset_scope_override @override_instance_scope = false end |
#scope_audit_id(opts = {}) ⇒ Object
Provides a more generalized audit ID which does not contain the auditor’s name, timeout value of injection string.
Right now only used when in HPG mode to generate a white-list of element IDs that are allowed to be audited.
247 248 249 250 251 252 253 254 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 247 def scope_audit_id( opts = {} ) opts = {} if !opts audit_id( nil, opts.merge( no_auditor: true, no_timeout: true, no_injection_str: true )) end |
#skip?(elem) ⇒ Boolean
422 423 424 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 422 def skip?( elem ) false end |
#skip_path?(url) ⇒ Boolean
339 340 341 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 339 def skip_path?( url ) super || Options.redundant?( url ) end |
#status_string ⇒ String
Returns a 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…).
434 435 436 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 434 def status_string "Auditing #{self.type} variable '#{self.altered}' with action '#{self.action}'." end |
#submit(opts = {}, &block) ⇒ Object
Submits self using #http_request.
322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 322 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] opts.delete( :auditor ) http_request( opts, &block ) end |
#update(hash) ⇒ Auditable
Returns self.
155 156 157 158 |
# File 'lib/arachni/element/capabilities/auditable.rb', line 155 def update( hash ) self.auditable = self.auditable.merge( hash ) self end |