Class: Arachni::Checks::UnvalidatedRedirect

Inherits:
Arachni::Check::Base show all
Defined in:
components/checks/active/unvalidated_redirect.rb

Overview

Unvalidated redirect check.

It audits links, forms and cookies, injects URLs and checks the Location header field to determine whether the attack was successful.

Constant Summary collapse

BASE_URL =
"www.#{Utilities.random_seed}.com"

Constants included from Arachni::Check::Auditor

Arachni::Check::Auditor::DOM_ELEMENTS_WITH_INPUTS, Arachni::Check::Auditor::ELEMENTS_WITH_INPUTS, Arachni::Check::Auditor::FILE_SIGNATURES, Arachni::Check::Auditor::FILE_SIGNATURES_PER_PLATFORM, Arachni::Check::Auditor::Format, Arachni::Check::Auditor::SOURCE_CODE_SIGNATURES_PER_PLATFORM

Constants included from Arachni

BANNER, Arachni::Cookie, Form, Header, JSON, Link, LinkTemplate, Severity, UIForm, UIInput, VERSION, WEBSITE, WIKI, XML

Instance Attribute Summary

Attributes included from Arachni::Check::Auditor

#framework, #page

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Arachni::Check::Base

#browser_cluster, #clean_up, elements, exempt_platforms, has_exempt_platforms?, has_platforms?, #initialize, platforms, #plugins, prefer, #preferred, preferred, #prepare, #session, supports_platforms?

Methods included from Arachni::Check::Auditor

#audit, #audit_differential, #audit_signature, #audit_timeout, #audited, #audited?, #buffered_audit, #each_candidate_dom_element, #each_candidate_element, has_timeout_candidates?, #http, #initialize, #log, #log_issue, #log_remote_file, #log_remote_file_if_exists, #match_and_log, #max_issues, #preferred, reset, #skip?, timeout_audit_run, #trace_taint, #with_browser, #with_browser_cluster

Methods inherited from Arachni::Component::Base

author, description, fullname, #shortname, shortname, shortname=, version

Methods included from Arachni::Component::Output

#depersonalize_output, #depersonalize_output?, #intercept_print_message

Methods included from UI::Output

#caller_location, #debug?, #debug_level, #debug_level_1?, #debug_level_2?, #debug_level_3?, #debug_level_4?, #debug_off, #debug_on, #disable_only_positives, #error_buffer, #error_log_fd, #error_logfile, #has_error_log?, #included, #log_error, #mute, #muted?, #only_positives, #only_positives?, #print_bad, #print_debug, #print_debug_backtrace, #print_debug_exception, #print_debug_level_1, #print_debug_level_2, #print_debug_level_3, #print_debug_level_4, #print_error, #print_error_backtrace, #print_exception, #print_info, #print_line, #print_ok, #print_status, #print_verbose, #reroute_to_file, #reroute_to_file?, reset_output_options, #set_error_logfile, #unmute, #verbose?, #verbose_off, #verbose_on

Methods included from Arachni::Component::Utilities

#read_file

Methods included from Utilities

#available_port, available_port_mutex, #bytes_to_kilobytes, #bytes_to_megabytes, #caller_name, #caller_path, #cookie_decode, #cookie_encode, #cookies_from_file, #cookies_from_parser, #cookies_from_response, #exception_jail, #exclude_path?, #follow_protocol?, #form_decode, #form_encode, #forms_from_parser, #forms_from_response, #full_and_absolute_url?, #generate_token, #get_path, #hms_to_seconds, #html_decode, #html_encode, #include_path?, #links_from_parser, #links_from_response, #normalize_url, #page_from_response, #page_from_url, #parse_set_cookie, #path_in_domain?, #path_too_deep?, #port_available?, #rand_port, #random_seed, #redundant_path?, #regexp_array_match, #remove_constants, #request_parse_body, #seconds_to_hms, #skip_page?, #skip_path?, #skip_resource?, #skip_response?, #to_absolute, #uri_decode, #uri_encode, #uri_parse, #uri_parse_query, #uri_parser, #uri_rewrite

Methods included from Arachni

URI, collect_young_objects, #get_long_win32_filename, jruby?, null_device, profile?, windows?

Constructor Details

This class inherits a constructor from Arachni::Check::Base

Class Method Details

.check_browser_result(browser, element, response, referring_page) ⇒ Object


82
83
84
85
86
87
88
# File 'components/checks/active/unvalidated_redirect.rb', line 82

def self.check_browser_result( browser, element, response, referring_page )
    browser.load( response )

    return if !payload? browser.url

    log vector: element, response: response, referring_page: referring_page
end

.check_browser_result_cbObject


90
91
92
# File 'components/checks/active/unvalidated_redirect.rb', line 90

def self.check_browser_result_cb
    @check_browser_result_cb ||= method(:check_browser_result)
end

.infoObject


94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'components/checks/active/unvalidated_redirect.rb', line 94

def self.info
    {
        name:        'Unvalidated redirect',
        description: %q{
Injects URLs and checks the `Location` HTTP response header field and/or browser
URL to determine whether the attack was successful.
},
        elements:    ELEMENTS_WITH_INPUTS - [Element::LinkTemplate],
        author:      'Tasos "Zapotek" Laskos <[email protected]>',
        version:     '0.2.5',

        issue:       {
            name:            %q{Unvalidated redirect},
            description:     %q{
Web applications occasionally use parameter values to store the address of the
page to which the client will be redirected -- for example:
`yoursite.com/page.asp?redirect=www.yoursite.com/404.asp`

An unvalidated redirect occurs when the client is able to modify the affected
parameter value in the request and thus control the location of the redirection.
For example, the following URL `yoursite.com/page.asp?redirect=www.anothersite.com`
will redirect to `www.anothersite.com`.

Cyber-criminals will abuse these vulnerabilities in social engineering attacks
to get users to unknowingly visit malicious web sites.

Arachni has discovered that the server does not validate the parameter value prior
to redirecting the client to the injected value.
},
            references:  {
                'OWASP Top 10 2010' => 'https://www.owasp.org/index.php/Top_10_2010-A10-Unvalidated_Redirects_and_Forwards'
            },
            tags:            %w(unvalidated redirect injection header location),
            cwe:             819,
            severity:        Severity::MEDIUM,
            remedy_guidance: %q{
The application should ensure that the supplied value for a redirect is permitted.
This can be achieved by performing whitelisting on the parameter value.

The whitelist should contain a list of pages or sites that the application is
permitted to redirect users to. If the supplied value does not match any value
in the whitelist then the server should redirect to a standard error page.
}
        }
    }
end

.optionsObject


35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'components/checks/active/unvalidated_redirect.rb', line 35

def self.options
    @options ||= {
        format: [ Format::STRAIGHT ],
        submit: {
            follow_location: false
        },

        # Add one more mutation (on the fly) which will include the original
        # value.
        each_mutation: proc do |mutation|
            next if !mutation.affected_input_value

            m = mutation.dup

            # Figure out the extension of the default value, if it has one.
            original_value = m.default_inputs[m.affected_input_name]

            # Null-terminate the injected value and append the ext.
            m.affected_input_value += "/?#{original_value}"

            # Pass our new mutation back to be audited.
            m
        end
    }
end

.payload?(url) ⇒ Boolean

Returns:

  • (Boolean)

28
29
30
# File 'components/checks/active/unvalidated_redirect.rb', line 28

def self.payload?( url )
    (@set_payloads ||= Set.new( payloads )).include? Arachni::URI( url ).to_s
end

.payloadsObject


20
21
22
23
24
25
26
# File 'components/checks/active/unvalidated_redirect.rb', line 20

def self.payloads
    @payloads ||= [
        BASE_URL,
        "https://#{BASE_URL}",
        "http://#{BASE_URL}"
    ].map { |url| Arachni::URI( url ).to_s }
end

Instance Method Details

#payload?(url) ⇒ Boolean

Returns:

  • (Boolean)

31
32
33
# File 'components/checks/active/unvalidated_redirect.rb', line 31

def payload?( url )
    self.class.payload? url.to_s.split( '?' ).first
end

#runObject


61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'components/checks/active/unvalidated_redirect.rb', line 61

def run
    audit( self.class.payloads, self.class.options ) do |response, element|
        # If this was a sample/default value submission ignore it, we only
        # care about our payloads.
        next if !payload? element.seed

        # Simple check for straight HTTP redirection first.
        if payload? response.headers.location
            log vector: element, response: response
            next
        end

        # HTTP redirection check failed but if our payload ended up in the
        # response body it's worth loading it with a browser in case there's
        # a JS redirect.
        next if !response.body.include?( element.seed )

        with_browser( element, response, page, self.class.check_browser_result_cb )
    end
end