Module: Arachni::Element::Capabilities::Analyzable::Signature

Included in:
Arachni::Element::Capabilities::Analyzable
Defined in:
lib/arachni/element/capabilities/analyzable/signature.rb

Overview

Looks for specific substrings or patterns in response bodies.

Author:

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

Constant Summary collapse

SIGNATURE_CACHE =
{
    match: Support::Cache::LeastRecentlyPushed.new( 10_000 )
}
SIGNATURE_OPTIONS =
{
    # The signatures to look for in each line of the response body,
    # if `Regexp` it will be matched against it, if `String` it'll be used
    # as a needle.
    #
    # Multi-line Regexp is not supported.
    signatures: [],

    # Array of signatures to ignore.
    #
    # Useful when needing to narrow down what to log without having to
    # construct overly complex signatures.
    ignore:     []
}
FILE_SIGNATURES =
{
    'environ'  => proc do |response|
        next if !response.body.include?( 'DOCUMENT_ROOT=' )
        /DOCUMENT_ROOT=.*HTTP_USER_AGENT=/
    end,
    'passwd'   => proc do |response|
        if response.body.include?( 'bin/' )
            /:.+:\d+:\d+:.+:[0-9a-zA-Z\/]+/

        # Response may have encoded chars as HTML entities.
        elsif response.body.include?( 'bin&#x2f;' ) && response.body.include?( '&#x3a;' )
            /&#x3a;.+&#x3a;\d+&#x3a;\d+&#x3a;.+&#x3a;[0-9a-zA-Z&#;]+/
        end
    end,
    'boot.ini' => '[boot loader]',
    'win.ini'  => '[extensions]',
    'web.xml'  => '<web-app'
}
FILE_SIGNATURES_PER_PLATFORM =
{
    unix:   [
        FILE_SIGNATURES['environ'],
        FILE_SIGNATURES['passwd']
    ],
    windows: [
        FILE_SIGNATURES['boot.ini'],
        FILE_SIGNATURES['win.ini']
    ],
    java:    [
        FILE_SIGNATURES['web.xml']
    ]
}
SOURCE_CODE_SIGNATURES_PER_PLATFORM =
{
    php:  [
        '<?php'
    ],

    # No need to optimize the following with procs, OR'ed Regexps perform
    # better than multiple substring checks, so long as the Regexp parts are
    # fairly simple.

    java: [
        /<%|<%=|<%@\s+page|<%@\s+include|<%--|import\s+javax.servlet|
            import\s+java.io|import=['"]java.io|request\.getParameterValues\(|
            response\.setHeader|response\.setIntHeader\(/
    ],
    asp:  [
        /<%|Response\.Write|Request\.Form|Request\.QueryString|
            Response\.Flush|Session\.SessionID|Session\.Timeout|
            Server\.CreateObject|Server\.MapPath/
    ]
}
LINE_BUFFER_SIZE =
1_000

Instance Method Summary collapse

Instance Method Details

#get_matches(response) ⇒ Object

Tries to identify an issue through pattern matching.

If a issue is found a message will be printed and the issue will be logged.

Parameters:



145
146
147
148
149
150
151
152
153
154
155
156
# File 'lib/arachni/element/capabilities/analyzable/signature.rb', line 145

def get_matches( response )
    vector = response.request.performer
    opts   = vector.audit_options.dup

    if !opts[:signatures].is_a?( Array ) && !opts[:signatures].is_a?( Hash )
        opts[:signatures] = [opts[:signatures]]
    end

    opts[:signatures] = [vector.seed] if opts[:signatures].empty?

    find_signatures( opts[:signatures], response, opts.dup )
end

#signature_analysis(payloads, opts = { }) ⇒ Bool

Performs signatures analysis and logs an issue, should there be one.

It logs an issue when:

  • `:match` == nil AND `:regexp` matches the response body

  • `:match` != nil AND `:regexp` match == `:match`

  • `:substring` exists in the response body

Parameters:

  • payloads (String, Array<String>, Hash{Symbol => <String, Array<String>>})

    Payloads to inject, if given:

    • String – Will inject the single payload.

    • Array – Will iterate over all payloads and inject them.

    • Hash – Expects Platform (as `Symbol`s ) for keys and Array of

      `payloads` for values. The applicable `payloads` will be
      {Platform::Manager#pick picked} from the hash based on
      {Element::Capabilities::Submittable#platforms applicable platforms}
      for the {Element::Capabilities::Submittable#action resource} to be audited.
      
  • opts (Hash) (defaults to: { })

    Options as described in Auditable::OPTIONS and SIGNATURE_OPTIONS.

Returns:

  • (Bool)

    `true` if the audit was scheduled successfully, `false` otherwise (like if the resource is out of scope).



118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/arachni/element/capabilities/analyzable/signature.rb', line 118

def signature_analysis( payloads, opts = { } )
    return false if self.inputs.empty?

    if scope.out?
        print_debug 'Signature analysis: Element is out of scope,' <<
                        " skipping: #{audit_id}"
        return false
    end

    # Buffer possible issues, we'll only register them with the system once
    # we've evaluated our control response.
    @candidate_issues = []

    opts = self.class::OPTIONS.merge( SIGNATURE_OPTIONS.merge( opts ) )

    fail_if_signatures_invalid( opts[:signatures] )

    audit( payloads, opts ) { |response| get_matches( response ) }
end