Class: Arachni::Checks::XssEvent

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

Overview

It injects a string and checks if it appears inside an event attribute of any HTML tag.

Defined Under Namespace

Classes: SAX

Constant Summary collapse

ATTRIBUTES =
[
    'onload',
    'onunload',
    'onblur',
    'onchange',
    'onfocus',
    'onreset',
    'onselect',
    'onsubmit',
    'onabort',
    'onkeydown',
    'onkeypress',
    'onkeyup',
    'onclick',
    'ondblclick',
    'onmousedown',
    'onmousemove',
    'onmouseout',
    'onmouseover',
    'onmouseup',

    # Not an event attribute so it gets special treatment by being checked
    # for a "script:" prefix.
    'src'
]

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, NestedCookie, 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

.attribute_nameObject



76
77
78
# File 'components/checks/active/xss_event.rb', line 76

def self.attribute_name
    'arachni_xss_in_element_event'
end

.infoObject



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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
# File 'components/checks/active/xss_event.rb', line 124

def self.info
    {
        name:        'XSS in HTML element event attribute',
        description: %q{Cross-Site Scripting in event tag of HTML element.},
        elements:    [Element::Form, Element::Link, Element::Cookie, Element::NestedCookie, Element::Header],
        author:      'Tasos "Zapotek" Laskos <[email protected]> ',
        version:     '0.1.10',

        issue:       {
            name:            %q{Cross-Site Scripting (XSS) in event tag of HTML element},
            description:     %q{
Client-side scripts are used extensively by modern web applications.
They perform from simple functions (such as the formatting of text) up to full
manipulation of client-side data and Operating System interaction.

Cross Site Scripting (XSS) allows clients to inject scripts into a request and
have the server return the script to the client in the response. This occurs
because the application is taking untrusted data (in this example, from the client)
and reusing it without performing any validation or sanitisation.

If the injected script is returned immediately this is known as reflected XSS.
If the injected script is stored by the server and returned to any client visiting
the affected page, then this is known as persistent XSS (also stored XSS).

Arachni has discovered that it is possible to insert script content directly into
an HTML event attribute. For example `<div onmouseover="x=INJECTION_HERE"</div>`,
where `INJECTION_HERE` represents the location where the Arachni payload was detected.
},
            references:  {
                'Secunia' => 'http://secunia.com/advisories/9716/',
                'WASC'    => 'http://projects.webappsec.org/w/page/13246920/Cross%20Site%20Scripting',
                'OWASP'   => 'https://www.owasp.org/index.php/XSS_%28Cross_Site_Scripting%29_Prevention_Cheat_Sheet'
            },
            tags:            %w(xss event injection dom attribute),
            cwe:             79,
            severity:        Severity::HIGH,
            remedy_guidance: %q{
To remedy XSS vulnerabilities, it is important to never use untrusted or unfiltered
data within the code of a HTML page.

Untrusted data can originate not only form the client but potentially a third
party or previously uploaded file etc.

Filtering of untrusted data typically involves converting special characters to
their HTML entity encoded counterparts (however, other methods do exist, see references).
These special characters include:

* `&`
* `<`
* `>`
* `"`
* `'`
* `/`

An example of HTML entity encoding is converting `<` to `&lt;`.

Although it is possible to filter untrusted input, there are five locations
within an HTML page where untrusted input (even if it has been filtered) should
never be placed:

1. Directly in a script.
2. Inside an HTML comment.
3. In an attribute name.
4. In a tag name.
5. Directly in CSS.

Each of these locations have their own form of escaping and filtering.

_Because many browsers attempt to implement XSS protection, any manual verification
of this finding should be conducted using multiple different browsers and browser
versions._
}
        }
    }
end

.optimization_cacheObject



92
93
94
# File 'components/checks/active/xss_event.rb', line 92

def self.optimization_cache
    @optimization_cache ||= {}
end

.optionsObject



88
89
90
# File 'components/checks/active/xss_event.rb', line 88

def self.options
    @options ||= { format: [ Format::APPEND ] }
end

.stringsObject



80
81
82
83
84
85
86
# File 'components/checks/active/xss_event.rb', line 80

def self.strings
    @strings ||= [
        ";#{attribute_name}=#{random_seed}//",
        "\";#{attribute_name}=#{random_seed}//",
        "';#{attribute_name}=#{random_seed}//"
    ].map { |s| [ " script:#{s}", " #{s}" ] }.flatten
end

Instance Method Details

#check_and_log(response, element) ⇒ Object



110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'components/checks/active/xss_event.rb', line 110

def check_and_log( response, element )
    body = response.body

    return :checked if !(body =~ /#{self.class.attribute_name}/i)
    return if element.seed.to_s.empty? || !(body =~ /#{element.seed}/i)

    handler = SAX.new( element.seed.split( ':', 2 ).last )
    Arachni::Parser.parse( body, handler: handler )

    return :checked if !handler.proof

    log vector: element, response: response, proof: handler.proof
end

#optimization_cacheObject



95
96
97
# File 'components/checks/active/xss_event.rb', line 95

def optimization_cache
    self.class.optimization_cache
end

#runObject



99
100
101
102
103
104
105
106
107
108
# File 'components/checks/active/xss_event.rb', line 99

def run
    audit self.class.strings, self.class.options do |response, element|
        next if !response.html?

        k = "#{response.url.hash}-#{response.body.hash}".hash
        next if optimization_cache[k] == :checked

        optimization_cache[k] = check_and_log( response, element )
    end
end