Class: Arachni::Checks::PathTraversal

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

Overview

Path Traversal check.

Constant Summary collapse

MINIMUM_TRAVERSALS =
0
MAXIMUM_TRAVERSALS =
8

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

.infoObject


91
92
93
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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'components/checks/active/path_traversal.rb', line 91

def self.info
    {
        name:        'Path Traversal',
        description: %q{
It injects paths of common files ( like `/etc/passwd` and `boot.ini`) and
evaluates the existence of a path traversal vulnerability based on the presence
of relevant content in the HTML responses.
},
        elements:    ELEMENTS_WITH_INPUTS,
        author:      'Tasos "Zapotek" Laskos <[email protected]> ',
        version:     '0.4.8',
        platforms:   payloads.keys,

        issue:       {
            name:            %q{Path Traversal},
            description:     %q{
Web applications occasionally use parameter values to store the location of a file
which will later be required by the server.

An example of this is often seen in error pages, where the actual file path for
the error page is stored in a parameter value -- for example `example.com/error.php?page=404.php`.

A path traversal occurs when the parameter value (ie. path to file being called
by the server) can be substituted with the relative path of another resource which
is located outside of the applications working directory. The server then loads
the resource and includes its contents in the response to the client.

Cyber-criminals will abuse this vulnerability to view files that should otherwise
not be accessible.

A very common example of this, on *nix servers, is gaining access to the `/etc/passwd`
file in order to retrieve a list of server users. This attack would look like:
`yoursite.com/error.php?page=../../../../etc/passwd`

As path traversal is based on the relative path, the payload must first traverse
to the file system's root directory, hence the string of `../../../../`.

Arachni discovered that it was possible to substitute a parameter value with a
relative path to a common operating system file and have the contents of the file
included in the response.
},
            references:  {
                'OWASP' => 'https://www.owasp.org/index.php/Path_Traversal',
                'WASC'  => 'http://projects.webappsec.org/Path-Traversal'
            },
            tags:            %w(path traversal injection regexp),
            cwe:             22,
            severity:        Severity::HIGH,
            remedy_guidance: %q{
It is recommended that untrusted data is never used to form a file location to
be included.

To validate data, the application should ensure that the supplied value for a file
is permitted. This can be achieved by performing whitelisting on the parameter
value, by matching it against a list of permitted files. If the supplied value
does not match any value in the whitelist, then the server should redirect to a
standard error page.

In some scenarios, where dynamic content is being requested, it may not be possible
to perform validation against a list of trusted resources, therefore the list must
also become dynamic (updated as the files change), or perform filtering to remove
extraneous user input (such as semicolons, periods etc.) and only permit `a-z0-9`.

It is also advised that sensitive files are not stored within the web root and
that the user permissions enforced by the directory are correct.
}
        }
    }
end

.optionsObject


21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'components/checks/active/path_traversal.rb', line 21

def self.options
    @options ||= {
        format:     [Format::STRAIGHT],
        signatures: FILE_SIGNATURES_PER_PLATFORM,

        # Add one more mutation (on the fly) which will include the extension
        # of the original value (if that value was a filename) after a null byte.
        each_mutation: proc do |mutation|
            next if !mutation.affected_input_value

            # Don't bother if the current element type can't carry nulls.
            next if !mutation.valid_input_value_data?( "\0" )

            m = mutation.dup

            # Figure out the extension of the default value, if it has one.
            ext = m.default_inputs[m.affected_input_name].to_s.split( '.' )
            ext = ext.size > 1 ? ext.last : nil

            # Null-terminate the injected value and append the ext.
            m.affected_input_value += "\0.#{ext}"

            # Pass our new element back to be audited.
            m
        end,

        skip_like: proc do |m|
            # Java payloads begin with a traversal which won't be preserved
            # via LinkTemplate injections so don't bother.
            m.is_a?( LinkTemplate ) && m.audit_options[:platform] == :java
        end
    }
end

.payloadsObject


55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'components/checks/active/path_traversal.rb', line 55

def self.payloads
    return @payloads if @payloads

    @payloads = {
        unix:    [
            '/proc/self/environ',
            '/etc/passwd'
        ],
        windows: [
            'boot.ini',
            'windows/win.ini',
            'winnt/win.ini'
        ].map { |payload| [payload, "#{payload}#{'.'* 700}"] }.flatten
    }.inject({}) do |h, (platform, payloads)|
        h[platform] = payloads.map do |payload|
            trv = '/'
            (MINIMUM_TRAVERSALS..MAXIMUM_TRAVERSALS).map do
                trv << '../'
                [ "#{trv}#{payload}", "file://#{trv}#{payload}" ]
            end
        end.flatten

        h
    end

    @payloads[:java] = [ '/../../', '../../', ].map do |trv|
         [ "#{trv}WEB-INF/web.xml", "file://#{trv}WEB-INF/web.xml" ]
    end.flatten

    @payloads
end

Instance Method Details

#runObject


87
88
89
# File 'components/checks/active/path_traversal.rb', line 87

def run
    audit self.class.payloads, self.class.options
end