module Arachni::Check::Auditor

Included by {Check::Base} and provides helper audit methods to all checks.

There are 3 main types of audit and analysis techniques available:

It should be noted that actual analysis takes place at the {Arachni::Element element} level.

It also provides:

@author Tasos “Zapotek” Laskos <tasos.laskos@arachni-scanner.com>

Constants

DOM_ELEMENTS_WITH_INPUTS

Auditable DOM elements.

ELEMENTS_WITH_INPUTS

Non-DOM auditable elements.

FILE_SIGNATURES
FILE_SIGNATURES_PER_PLATFORM
Format

Holds constant bitfields that describe the preferred formatting of injection strings.

SOURCE_CODE_SIGNATURES_PER_PLATFORM

Attributes

framework[R]

@return [Arachni::Framework]

page[R]

@return [Arachni::Page]

Page object to be audited.

Public Class Methods

check?( page, restrict_to_elements = nil, ignore_dom_depth = false ) click to toggle source

Determines whether or not to run the check against the given page depending on which elements exist in the page, which elements the check is configured to audit and user options.

@param [Page] page @param [Element::Base, Array<Element::Base>] restrict_to_elements

Element types to check for.

@return [Bool]

# File lib/arachni/check/auditor.rb, line 81
def self.check?( page, restrict_to_elements = nil, ignore_dom_depth = false )
    return false if issue_limit_reached?
    return true  if elements.empty?

    audit                = Arachni::Options.audit
    restrict_to_elements = [restrict_to_elements].flatten.compact

    # We use procs to make the decisions to avoid loading the page
    # element caches unless it's absolutely necessary.
    #
    # Also, it's better to audit Form & Cookie DOM elements only
    # after the page has gone through the browser, because then
    # we'll have some context in the metadata which can help us
    # optimize DOM audits.
    {
        Element::Link              =>
            proc { audit.links?     && !!page.links.find { |e| e.inputs.any? } },
        Element::Link::DOM         =>
            proc { audit.link_doms? && !!page.links.find(&:dom) },
        Element::Form              =>
            proc { audit.forms? && !!page.forms.find { |e| e.inputs.any? } },
        Element::Form::DOM         =>
            proc { (ignore_dom_depth || page.dom.depth > 0) &&
                audit.form_doms? && page.has_script? && !!page.forms.find(&:dom) },
        Element::Cookie            =>
            proc { audit.cookies? && page.cookies.any? },
        Element::NestedCookie            =>
            proc { audit.nested_cookies? && page.nested_cookies.any? },
        Element::Cookie::DOM       =>
            proc { (ignore_dom_depth || page.dom.depth > 0) &&
                audit.cookie_doms? && page.has_script? && page.cookies.any? },
        Element::Header            =>
            proc { audit.headers? && page.headers.any? },
        Element::LinkTemplate      =>
            proc { audit.link_templates? && page.link_templates.find { |e| e.inputs.any? } },
        Element::LinkTemplate::DOM =>
            proc { audit.link_template_doms? && !!page.link_templates.find(&:dom) },
        Element::JSON              =>
            proc { audit.jsons? && page.jsons.find { |e| e.inputs.any? } },
        Element::XML               =>
            proc { audit.xmls? && page.xmls.find { |e| e.inputs.any? } },
        Element::UIInput           => false,
        Element::UIInput::DOM      =>
            proc { audit.ui_inputs? && page.ui_inputs.any? },
        Element::UIForm            => false,
        Element::UIForm::DOM       =>
            proc { audit.ui_forms? && page.ui_forms.any? },
        Element::Body              => !page.body.empty?,
        Element::GenericDOM        => page.has_script?,
        Element::Path              => true,
        Element::Server            => true
    }.each do |type, decider|
        next if restrict_to_elements.any? && !restrict_to_elements.include?( type )

        return true if elements.include?( type ) &&
            (decider.is_a?( Proc ) ? decider.call : decider)
    end

    false
end
create_issue( options ) click to toggle source

Helper method for creating an issue.

@param [Hash] options

{Issue} options.
# File lib/arachni/check/auditor.rb, line 272
def self.create_issue( options )
    check_info = self.info.dup
    check_info.delete( :issue )
    check_info[:shortname] = self.shortname

    issue_data = self.info[:issue].merge( check: check_info ).merge( options )
    Issue.new( issue_data )
end
has_timeout_candidates?() click to toggle source
# File lib/arachni/check/auditor.rb, line 43
def self.has_timeout_candidates?
    Element::Capabilities::Analyzable.has_timeout_candidates?
end
included( m ) click to toggle source
# File lib/arachni/check/auditor.rb, line 69
def self.included( m )
    m.class_eval do

        # Determines whether or not to run the check against the given page
        # depending on which elements exist in the page, which elements the
        # check is configured to audit and user options.
        #
        # @param    [Page]    page
        # @param    [Element::Base, Array<Element::Base>]    restrict_to_elements
        #   Element types to check for.
        #
        # @return   [Bool]
        def self.check?( page, restrict_to_elements = nil, ignore_dom_depth = false )
            return false if issue_limit_reached?
            return true  if elements.empty?

            audit                = Arachni::Options.audit
            restrict_to_elements = [restrict_to_elements].flatten.compact

            # We use procs to make the decisions to avoid loading the page
            # element caches unless it's absolutely necessary.
            #
            # Also, it's better to audit Form & Cookie DOM elements only
            # after the page has gone through the browser, because then
            # we'll have some context in the metadata which can help us
            # optimize DOM audits.
            {
                Element::Link              =>
                    proc { audit.links?     && !!page.links.find { |e| e.inputs.any? } },
                Element::Link::DOM         =>
                    proc { audit.link_doms? && !!page.links.find(&:dom) },
                Element::Form              =>
                    proc { audit.forms? && !!page.forms.find { |e| e.inputs.any? } },
                Element::Form::DOM         =>
                    proc { (ignore_dom_depth || page.dom.depth > 0) &&
                        audit.form_doms? && page.has_script? && !!page.forms.find(&:dom) },
                Element::Cookie            =>
                    proc { audit.cookies? && page.cookies.any? },
                Element::NestedCookie            =>
                    proc { audit.nested_cookies? && page.nested_cookies.any? },
                Element::Cookie::DOM       =>
                    proc { (ignore_dom_depth || page.dom.depth > 0) &&
                        audit.cookie_doms? && page.has_script? && page.cookies.any? },
                Element::Header            =>
                    proc { audit.headers? && page.headers.any? },
                Element::LinkTemplate      =>
                    proc { audit.link_templates? && page.link_templates.find { |e| e.inputs.any? } },
                Element::LinkTemplate::DOM =>
                    proc { audit.link_template_doms? && !!page.link_templates.find(&:dom) },
                Element::JSON              =>
                    proc { audit.jsons? && page.jsons.find { |e| e.inputs.any? } },
                Element::XML               =>
                    proc { audit.xmls? && page.xmls.find { |e| e.inputs.any? } },
                Element::UIInput           => false,
                Element::UIInput::DOM      =>
                    proc { audit.ui_inputs? && page.ui_inputs.any? },
                Element::UIForm            => false,
                Element::UIForm::DOM       =>
                    proc { audit.ui_forms? && page.ui_forms.any? },
                Element::Body              => !page.body.empty?,
                Element::GenericDOM        => page.has_script?,
                Element::Path              => true,
                Element::Server            => true
            }.each do |type, decider|
                next if restrict_to_elements.any? && !restrict_to_elements.include?( type )

                return true if elements.include?( type ) &&
                    (decider.is_a?( Proc ) ? decider.call : decider)
            end

            false
        end

        def self.issue_counter
            @issue_counter ||= 0
        end

        def self.issue_counter=( int )
            @issue_counter = int
        end

        def increment_issue_counter
            self.class.issue_counter += 1
        end

        def issue_limit_reached?( count = max_issues )
            self.class.issue_limit_reached?( count )
        end

        def self.issue_limit_reached?( count = max_issues )
            issue_counter >= count if !count.nil?
        end

        def self.max_issues
            info[:max_issues]
        end

        # Populates and logs an {Arachni::Issue}.
        #
        # @param    [Hash]  options
        #   {Arachni::Issue} initialization options.
        #
        # @return   [Issue]
        def self.log( options )
            options       = options.dup
            vector        = options[:vector]
            audit_options = vector.respond_to?( :audit_options ) ?
                vector.audit_options : {}

            if options[:referring_page]
                referring_page = options[:referring_page]
            elsif vector.page
                referring_page = vector.page
            else
                fail ArgumentError, 'Missing :referring_page option.'
            end

            if options[:response]
                page = options.delete(:response).to_page
            elsif options[:page]
                page = options.delete(:page)
            else
                page = referring_page
            end

            # Don't check the page scope, the check may have exceeded the DOM depth
            # limit but the check is allowed to do that, only check for an out of
            # scope response.
            return if !page.response.parsed_url.seed_in_host? && page.response.scope.out?

            msg = "In #{vector.type}"

            active = vector.respond_to?( :affected_input_name ) && vector.affected_input_name

            if active
                msg << " input '#{vector.affected_input_name}'"
            elsif vector.respond_to?( :inputs )
                msg << " with inputs '#{vector.inputs.keys.join(', ')}'"
            end

            vector.print_ok "#{msg} with action #{vector.action}"

            if Arachni::UI::Output.verbose?
                if active
                    vector.print_verbose "Injected:  #{vector.affected_input_value.inspect}"
                end

                if options[:signature]
                    vector.print_verbose "Signature: #{options[:signature]}"
                end

                if options[:proof]
                    vector.print_verbose "Proof:     #{options[:proof]}"
                end

                if page.dom.transitions.any?
                    vector.print_verbose 'DOM transitions:'
                    page.dom.print_transitions( method(:print_verbose), '    ' )
                end

                if !(request_dump = page.request.to_s).empty?
                    vector.print_verbose "Request: \n#{request_dump}"
                end

                vector.print_verbose( '---------' ) if only_positives?
            end

            # Platform identification by vulnerability.
            platform_type = nil
            if (platform = (options.delete(:platform) || audit_options[:platform]))
                Platform::Manager[vector.action] << platform if Options.fingerprint?
                platform_type = Platform::Manager[vector.action].find_type( platform )
            end

            log_issue(options.merge(
                platform_name:  platform,
                platform_type:  platform_type,
                page:           page,
                referring_page: referring_page
            ))
        end

        # Helper method for issue logging.
        #
        # @param    [Hash]  options
        #   {Issue} options.
        #
        # @return   [Issue]
        #
        # @see .create_issue
        def self.log_issue( options )
            return if issue_limit_reached?
            self.issue_counter += 1

            issue = create_issue( options )
            Data.issues << issue
            issue
        end

        # Helper method for creating an issue.
        #
        # @param    [Hash]  options
        #   {Issue} options.
        def self.create_issue( options )
            check_info = self.info.dup
            check_info.delete( :issue )
            check_info[:shortname] = self.shortname

            issue_data = self.info[:issue].merge( check: check_info ).merge( options )
            Issue.new( issue_data )
        end
    end
end
issue_counter() click to toggle source
# File lib/arachni/check/auditor.rb, line 142
def self.issue_counter
    @issue_counter ||= 0
end
issue_counter=( int ) click to toggle source
# File lib/arachni/check/auditor.rb, line 146
def self.issue_counter=( int )
    @issue_counter = int
end
issue_limit_reached?( count = max_issues ) click to toggle source
# File lib/arachni/check/auditor.rb, line 158
def self.issue_limit_reached?( count = max_issues )
    issue_counter >= count if !count.nil?
end
log( options ) click to toggle source

Populates and logs an {Arachni::Issue}.

@param [Hash] options

{Arachni::Issue} initialization options.

@return [Issue]

# File lib/arachni/check/auditor.rb, line 172
def self.log( options )
    options       = options.dup
    vector        = options[:vector]
    audit_options = vector.respond_to?( :audit_options ) ?
        vector.audit_options : {}

    if options[:referring_page]
        referring_page = options[:referring_page]
    elsif vector.page
        referring_page = vector.page
    else
        fail ArgumentError, 'Missing :referring_page option.'
    end

    if options[:response]
        page = options.delete(:response).to_page
    elsif options[:page]
        page = options.delete(:page)
    else
        page = referring_page
    end

    # Don't check the page scope, the check may have exceeded the DOM depth
    # limit but the check is allowed to do that, only check for an out of
    # scope response.
    return if !page.response.parsed_url.seed_in_host? && page.response.scope.out?

    msg = "In #{vector.type}"

    active = vector.respond_to?( :affected_input_name ) && vector.affected_input_name

    if active
        msg << " input '#{vector.affected_input_name}'"
    elsif vector.respond_to?( :inputs )
        msg << " with inputs '#{vector.inputs.keys.join(', ')}'"
    end

    vector.print_ok "#{msg} with action #{vector.action}"

    if Arachni::UI::Output.verbose?
        if active
            vector.print_verbose "Injected:  #{vector.affected_input_value.inspect}"
        end

        if options[:signature]
            vector.print_verbose "Signature: #{options[:signature]}"
        end

        if options[:proof]
            vector.print_verbose "Proof:     #{options[:proof]}"
        end

        if page.dom.transitions.any?
            vector.print_verbose 'DOM transitions:'
            page.dom.print_transitions( method(:print_verbose), '    ' )
        end

        if !(request_dump = page.request.to_s).empty?
            vector.print_verbose "Request: \n#{request_dump}"
        end

        vector.print_verbose( '---------' ) if only_positives?
    end

    # Platform identification by vulnerability.
    platform_type = nil
    if (platform = (options.delete(:platform) || audit_options[:platform]))
        Platform::Manager[vector.action] << platform if Options.fingerprint?
        platform_type = Platform::Manager[vector.action].find_type( platform )
    end

    log_issue(options.merge(
        platform_name:  platform,
        platform_type:  platform_type,
        page:           page,
        referring_page: referring_page
    ))
end
log_issue( options ) click to toggle source

Helper method for issue logging.

@param [Hash] options

{Issue} options.

@return [Issue]

@see .create_issue

# File lib/arachni/check/auditor.rb, line 259
def self.log_issue( options )
    return if issue_limit_reached?
    self.issue_counter += 1

    issue = create_issue( options )
    Data.issues << issue
    issue
end
max_issues() click to toggle source
# File lib/arachni/check/auditor.rb, line 162
def self.max_issues
    info[:max_issues]
end
new( page, framework ) click to toggle source

@param [Page] page @param [Framework] framework

# File lib/arachni/check/auditor.rb, line 321
def initialize( page, framework )
    @page      = page
    @framework = framework
end
reset() click to toggle source
# File lib/arachni/check/auditor.rb, line 39
def self.reset
    audited.clear
end
timeout_audit_run() click to toggle source
# File lib/arachni/check/auditor.rb, line 46
def self.timeout_audit_run
    Element::Capabilities::Analyzable.timeout_audit_run
end

Private Class Methods

audited() click to toggle source

@return [State::Audit]

Keeps track of audit operations.

@see audited? @see audited

# File lib/arachni/check/auditor.rb, line 692
def self.audited
    State.audit
end

Public Instance Methods

audit( payloads, opts = {}, &block ) click to toggle source

If a block has been provided it calls {Arachni::Element::Capabilities::Auditable#audit} for every element, otherwise, it defaults to {#audit_signature}.

Uses {#each_candidate_element} to decide which elements to audit.

@see Arachni::Element::Capabilities::Auditable#audit @see audit_signature

# File lib/arachni/check/auditor.rb, line 566
def audit( payloads, opts = {}, &block )
    if !block_given?
        audit_signature( payloads, opts )
    else
        each_candidate_element do |e|
            e.audit( payloads, opts, &block )
            audited( e.coverage_id )
        end
    end
end
audit_differential( opts = {}, &block ) click to toggle source

Audits elements using differential analysis and automatically logs results.

Uses {#each_candidate_element} to decide which elements to audit.

@see Arachni::Element::Capabilities::Analyzable::Differential

# File lib/arachni/check/auditor.rb, line 608
def audit_differential( opts = {}, &block )
    each_candidate_element do |e|
        e.differential_analysis( opts, &block )
        audited( e.coverage_id )
    end
end
audit_signature( payloads, opts = {} ) click to toggle source

Provides easy access to element auditing using simple signature analysis and automatically logs results.

Uses {#each_candidate_element} to decide which elements to audit.

@see Arachni::Element::Capabilities::Analyzable::Signature

# File lib/arachni/check/auditor.rb, line 596
def audit_signature( payloads, opts = {} )
    each_candidate_element do |e|
        e.signature_analysis( payloads, opts )
        audited( e.coverage_id )
    end
end
audit_timeout( payloads, opts = {} ) click to toggle source

Audits elements using timing attacks and automatically logs results.

Uses {#each_candidate_element} to decide which elements to audit.

@see Arachni::Element::Capabilities::Analyzable::Timeout

# File lib/arachni/check/auditor.rb, line 620
def audit_timeout( payloads, opts = {} )
    each_candidate_element do |e|
        e.timeout_analysis( payloads, opts )
        audited( e.coverage_id )
    end
end
audited( id ) click to toggle source

@param [#to_s] id

Identifier of the object to be marked as audited.

@see audited?

# File lib/arachni/check/auditor.rb, line 54
def audited( id )
    Auditor.audited << "#{self.class}-#{id}"
end
audited?( id ) click to toggle source

@param [#to_s] id

Identifier of the object to be checked.

@return [Bool]

`true` if audited, `false` otherwise.

@see audited

# File lib/arachni/check/auditor.rb, line 65
def audited?( id )
    Auditor.audited.include?( "#{self.class}-#{id}" )
end
buffered_audit( payloads, opts = {}, &block ) click to toggle source

Calls {Arachni::Element::Capabilities::Auditable#buffered_audit} for every element.

Uses {#each_candidate_element} to decide which elements to audit.

@see Arachni::Element::Capabilities::Auditable#buffered_audit

# File lib/arachni/check/auditor.rb, line 583
def buffered_audit( payloads, opts = {}, &block )
    each_candidate_element do |e|
        e.buffered_audit( payloads, opts, &block )
        audited( e.coverage_id )
    end
end
each_candidate_dom_element( &block ) click to toggle source

Passes each element prepared for audit to the block.

It will use the elements from the check’s {Base.info} hash. If no elements have been specified it will use {DOM_ELEMENTS_WITH_INPUTS}.

@yield [element]

Each candidate element.

@yieldparam [Arachni::Element::DOM]

# File lib/arachni/check/auditor.rb, line 525
def each_candidate_dom_element( &block )
    types = self.class.elements
    types = DOM_ELEMENTS_WITH_INPUTS if types.empty?

    types.each do |elem|
        elem = elem.type

        next if !Options.audit.elements?( elem.to_s.gsub( '_dom', '' ) )

        case elem
            when Element::Link::DOM.type
                prepare_each_dom_element( page.links, &block )

            when Element::Form::DOM.type
                prepare_each_dom_element( page.forms, &block )

            when Element::Cookie::DOM.type
                prepare_each_dom_element( page.cookies, &block )

            when Element::LinkTemplate::DOM.type
                prepare_each_dom_element( page.link_templates, &block )

            when Element::UIInput::DOM.type
                prepare_each_dom_element( page.ui_inputs, &block )

            when Element::UIForm::DOM.type
                prepare_each_dom_element( page.ui_forms, &block )

            else
                fail ArgumentError, "Unknown DOM element: #{elem}"
        end
    end
end
each_candidate_element( &block ) click to toggle source

Passes each element prepared for audit to the block.

It will use the elements from the check’s {Base.info} hash. If no elements have been specified it will use {ELEMENTS_WITH_INPUTS}.

@yield [element]

Each candidate element.

@yieldparam [Arachni::Element]

# File lib/arachni/check/auditor.rb, line 477
def each_candidate_element( &block )
    types = self.class.elements
    types = ELEMENTS_WITH_INPUTS if types.empty?

    types.each do |elem|
        elem = elem.type

        next if !Options.audit.elements?( elem )

        case elem
            when Element::Link.type
                prepare_each_element( page.links, &block )

            when Element::Form.type
                prepare_each_element( page.forms, &block )

            when Element::Cookie.type
                prepare_each_element(page.cookies, &block )

            when Element::NestedCookie.type
                prepare_each_element(page.nested_cookies, &block )

            when Element::Header.type
                prepare_each_element( page.headers, &block )

            when Element::LinkTemplate.type
                prepare_each_element( page.link_templates, &block )

            when Element::JSON.type
                prepare_each_element( page.jsons, &block )

            when Element::XML.type
                prepare_each_element( page.xmls, &block )

            else
                fail ArgumentError, "Unknown element: #{elem}"
        end
    end
end
http() click to toggle source

@return [HTTP::Client]

# File lib/arachni/check/auditor.rb, line 327
def http
    HTTP::Client
end
increment_issue_counter() click to toggle source
# File lib/arachni/check/auditor.rb, line 150
def increment_issue_counter
    self.class.issue_counter += 1
end
issue_limit_reached?( count = max_issues ) click to toggle source
# File lib/arachni/check/auditor.rb, line 154
def issue_limit_reached?( count = max_issues )
    self.class.issue_limit_reached?( count )
end
log( options ) click to toggle source

Populates and logs an {Arachni::Issue}.

@param [Hash] options

{Arachni::Issue} initialization options.

@return [Issue]

# File lib/arachni/check/auditor.rb, line 420
def log( options )
    self.class.log( options.merge( referring_page: @page ) )
end
log_issue( options ) click to toggle source

Helper method for issue logging.

@param [Hash] options

{Issue} options.

@return [Issue]

@see .create_issue

# File lib/arachni/check/auditor.rb, line 410
def log_issue( options )
    self.class.log_issue( options.merge( referring_page: @page ) )
end
log_remote_directory( page_or_response, silent = false, options = {} )
Alias for: log_remote_file
log_remote_directory_if_exists( url, silent = false, options = {}, &block )
log_remote_file( page_or_response, silent = false, options = {} ) click to toggle source

Logs the existence of a remote file as an issue.

@overload log_remote_file( response, silent = false )

@param    [HTTP::Response]    response
@param    [Bool]      silent
    If `false`, a message will be printed to stdout containing the status of
    the operation.

@overload log_remote_file( page, silent = false )

@param    [Page]    page
@param    [Bool]    silent
    If `false`, a message will be printed to stdout containing the status of
    the operation.

@return [Issue]

@see log_issue

# File lib/arachni/check/auditor.rb, line 386
def log_remote_file( page_or_response, silent = false, options = {} )
    page = page_or_response.is_a?( Page ) ?
        page_or_response : page_or_response.to_page

    issue = log_issue({
        vector: Element::Server.new( page.url ),
        proof:  page.response.status_line,
        page:   page
    }.merge( options ))

    print_ok( "Found #{page.url}" ) if !silent

    issue
end
Also aliased as: log_remote_directory
log_remote_file_if_exists( url, silent = false, options = {}, &block ) click to toggle source

@note Ignores custom 404 responses.

Logs a remote file or directory if it exists.

@param [String] url Resource to check. @param [Bool] silent

If `false`, a message will be printed to stdout containing the status of
the operation.

@param [Proc] block

Called if the file exists, just before logging the issue, and is passed
the HTTP response.

@return [Object]

* `nil` if no URL was provided.
* `false` if the request couldn't be fired.
* `true` if everything went fine.

@see Element::Server#remote_file_exist?

# File lib/arachni/check/auditor.rb, line 349
def log_remote_file_if_exists( url, silent = false, options = {}, &block )
    @server ||= Element::Server.new( page.url ).tap { |s| s.auditor = self }
    @server.log_remote_file_if_exists( url, silent, options, &block )
end
match_and_log( patterns, &block ) click to toggle source

Matches an array of regular expressions against a string and logs the result as an issue.

@param [Array<Regexp>] patterns

Array of regular expressions to be tested.

@param [Block] block

Block to verify matches before logging, must return `true`/`false`.

@see Element::Body#match_and_log

# File lib/arachni/check/auditor.rb, line 364
def match_and_log( patterns, &block )
    @body ||= Element::Body.new( self.page.url ).tap { |b| b.auditor = self }
    @body.match_and_log( patterns, &block )
end
max_issues() click to toggle source
# File lib/arachni/check/auditor.rb, line 283
def max_issues
    self.class.max_issues
end
preferred() click to toggle source

@see Arachni::Check::Base#preferred @see Arachni::Check::Base.prefer @abstract

# File lib/arachni/check/auditor.rb, line 427
def preferred
    []
end
skip?( element ) click to toggle source

This is called right before an {Arachni::Element} is audited and is used to determine whether to skip it or not.

Running checks can override this as they wish but at their own peril.

@param [Arachni::Element] element

@return [Boolean]

`true` if the element should be skipped, `false` otherwise.

@see Page#audit?

# File lib/arachni/check/auditor.rb, line 442
def skip?( element )
    # This method also gets called from Auditable#audit to check mutations,
    # don't touch these, we're filtering at a higher level here, otherwise
    # we might mess up the audit.
    return true if !element.mutation? && audited?( element.coverage_id )
    return true if !page.audit_element?( element )

    # Don't audit elements which have been already logged as vulnerable
    # either by us or preferred checks.
    (preferred | [shortname]).each do |check|
        next if !framework.checks.include?( check )

        klass = framework.checks[check]
        next if !klass.info.include?(:issue)

        # No point in doing the following heavy deduplication check if there
        # are no issues logged to begin with.
        next if klass.issue_counter == 0

        if Data.issues.include?( klass.create_issue( vector: element ) )
            return true
        end
    end

    false
end
trace_taint( resource, options = {}, &block ) click to toggle source

Traces the taint in the given ‘resource` and passes each page to the `block`.

@param [Page, String, HTTP::Response] resource

Resource to load and whose environment to trace, if given a `String` it
will be treated it as a URL and will be loaded.

@param [Hash] options

See {BrowserCluster::Jobs::TaintTrace} accessors.

@param [Block] block

Block to handle each page snapshot. If the `block` returns a `true` value,
further analysis will be aborted.
# File lib/arachni/check/auditor.rb, line 638
def trace_taint( resource, options = {}, &block )
    with_browser_cluster do |cluster|
        cluster.trace_taint( resource, options ) do |result|
            block.call( result.page )
        end
    end
end
with_browser( *args, &block ) click to toggle source

@note Operates in non-blocking mode.

@param [Block] block

Block to passed a {BrowserCluster::Worker}, if/when one is available.

@see BrowserCluster::Worker#with_browser

# File lib/arachni/check/auditor.rb, line 660
def with_browser( *args, &block )
    with_browser_cluster { |cluster| cluster.with_browser( *args, &block ) }
    true
end
with_browser_cluster( &block ) click to toggle source

@param [Block] block

Block to passed a {BrowserCluster}, if one is available.
# File lib/arachni/check/auditor.rb, line 648
def with_browser_cluster( &block )
    return if !browser_cluster
    block.call browser_cluster
    true
end

Private Instance Methods

prepare_each_dom_element( elements, &block ) click to toggle source
# File lib/arachni/check/auditor.rb, line 677
def prepare_each_dom_element( elements, &block )
    elements.each do |e|
        next if !e.dom || e.dom.inputs.empty? || skip?( e.dom )

        d = e.dup.dom
        d.auditor = self
        block.call d
    end
end
prepare_each_element( elements, &block ) click to toggle source
# File lib/arachni/check/auditor.rb, line 667
def prepare_each_element( elements, &block )
    elements.each do |e|
        next if skip?( e ) || e.inputs.empty?

        d = e.dup
        d.auditor = self
        block.call d
    end
end