Commit c857ee18 authored by Sophie Brun's avatar Sophie Brun

Merge tag 'upstream/1.3'

Upstream version 1.3
parents acbd95d6 e342bcca
# ChangeLog
## 1.3 _(October 01, 2015)_
- `UI`
- `CLI`
- Options
- `--browser-cluster-local-storage` -- Sets `localStorage` data from JSON file.
- `Issue`
- `#variations` -- Removed, all issues now include full data.
- `#unique_id`, `#digest` -- In cases of passive issues, the associated
`#proof` is now taken into consideration.
- `Data`
- `Framework`
- `#update_sitemap` -- Don't push URLs that include the
`Utilities.random_seed` to the sitemap to keep noise down.
- `Element`
- `Cookie`
- `.encode` -- Updated list of reversed characters.
- `.decode` -- Handle broken encodings.
- `Form`
- `.decode` -- Handle broken encodings.
- `UIForm` -- Audits `<input>` and `<button>` groups which don't belong to
a `<form>` parent. Also covers cases of `<form>` submissions that occur
via elements other than a submit button.
- `UIInput` -- Audits individual `<input>` elements which have associated DOM events.
- `Capabilities` -- Refactored to allow for easier expansion of DOM capabilities.
- `Analyzable`
- `Differential` -- Updated to remove the injected seed from the response
bodies, echoed payloads can compromise the analysis.
- `Taint` => `Signature` -- Signature analysis better describes that
process and the "taint" terminology was overloaded by the browser's
taint tracing subsystems.
- `Browser`
- Use the faster, native `#click` event on `Watir` elements, instead of `fire_event`.
- Sets `localStorage` data from `Arachni::OptionGroups::BrowserCluster#local_storage`.
- `Javascript`
- `TaintTracer`
- Updated sanitization of traced `Event` arguments to extract only
certain properties instead of iterating through the whole object.
- Limited the depth of the recursive taint search in argument objects.
- `Components`
- Path extractors
- `comments`
- Small cleanup in acceptable paths.
- `script`
- Updated to not get fooled by comment strings (`/*Comment`, `//Comment`).
- Updated to require absolute paths to avoid processing junk.
- Reporters -- All reporters have been updated to remove `Issue#variations`.
- `xml` -- Updated schema to include the new `Element::UIForm::DOM` and
`Element::Input::DOM` elements.
- Plugins
- `proxy` -- Fixed bug causing the plugin to hang after proxy server shutdown.
- `login_script`
- Wait for the page to settle when using a JS login script.
- Catch script syntax errors.
- Checks
- Active
- Removed
`xss_dom_inputs` -- No longer necessary, covered by new DOM
element abstractions and `xss_dom`.
- `unvalidated_redirect` -- Updated to use `Utilities.random_seed`
in the injected URL.
- `unvalidated_redirect_dom` -- Updated to use `Utilities.random_seed`
in the injected URL.
- Passive -- Reworked proofs to remove dynamic content which can interfere
with issue uniqueness or removed proofs altogether when not necessary.
## 1.2.1 _(July 25, 2015)_
- HTTP
......
......@@ -10,7 +10,7 @@ end
group :spec do
gem 'simplecov', require: false, group: :test
gem 'rspec', '2.99'
gem 'rspec'
gem 'faker'
gem 'puma' if !Gem.win_platform? || RUBY_PLATFORM == 'java'
......
......@@ -3,7 +3,7 @@
<table>
<tr>
<th>Version</th>
<td>1.2.1</td>
<td>1.3</td>
</tr>
<tr>
<th>Homepage</th>
......@@ -196,6 +196,8 @@ Configuration options include:
- Ability to disable loading images.
- Adjustable screen width and height.
- Can be used to analyze responsive and mobile applications.
- Ability to wait until certain elements appear in the page.
- Configurable local storage data.
### Coverage
......@@ -211,7 +213,12 @@ By inspecting all possible pages and their states (when using client-side code)
Arachni is able to extract and audit the following elements and their inputs:
- Forms
- Along with ones that require interaction with a real browser due to DOM events.
- Along with ones that require interaction via a real browser due to DOM events.
- User-interface Forms
- Input and button groups which don't belong to an HTML `<form>` element but
are instead associated via JS code.
- User-interface Inputs
- Orphan `<input>` elements with associated DOM events.
- Links
- Along with ones that have client-side parameters in their fragment, i.e.:
`http://example.com/#/?param=val&param2=val2`
......@@ -222,7 +229,7 @@ Arachni is able to extract and audit the following elements and their inputs:
`http://example.com/#/param/val/param2/val2`
- Cookies
- Headers
- Generic client-side elements like `input`s which have associated DOM events.
- Generic client-side elements which have associated DOM events.
- AJAX-request parameters.
- JSON request data.
- XML request data.
......@@ -278,6 +285,11 @@ Arachni is able to extract and audit the following elements and their inputs:
- Forms
- Can automatically refresh nonce tokens.
- Can submit them via the integrated browser environment.
- User-interface Forms
- Input and button groups which don't belong to an HTML `<form>` element
but are instead associated via JS code.
- User-interface Inputs
- Orphan `<input>` elements with associated DOM events.
- Links
- Can load them via the integrated browser environment.
- LinkTemplates
......@@ -285,7 +297,7 @@ Arachni is able to extract and audit the following elements and their inputs:
- Cookies
- Can load them via the integrated browser environment.
- Headers
- Generic client-side DOM elements like `input`s.
- Generic client-side DOM elements.
- JSON request data.
- XML request data.
- Can ignore binary/non-text pages.
......@@ -433,7 +445,6 @@ Active checks engage the web application via its inputs.
- XSS in HTML tags (`xss_tag`).
- XSS in script context (`xss_script_context`).
- DOM XSS (`xss_dom`).
- DOM XSS inputs (`xss_dom_inputs`).
- DOM XSS script context (`xss_dom_script_context`).
- Source code disclosure (`source_code_disclosure`)
- XML External Entity (`xxe`).
......
supplied argument is not a valid ldap
javax.naming.NameNotFoundException
javax.naming.directory.InvalidSearchFilterException
LDAPException
com.sun.jndi.ldap
Search: Bad search filter
......
......@@ -108,7 +108,7 @@ class Arachni::Checks::SourceCodeDisclosure < Arachni::Check::Base
return if self.class.payloads.empty?
each_candidate_element do |element|
element.taint_analysis( self.class.payloads, self.class.options )
element.signature_analysis( self.class.payloads, self.class.options )
end
end
......
......@@ -12,16 +12,16 @@
# header field to determine whether the attack was successful.
#
# @author Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com>
# @version 0.2.3
#
# @see https://www.owasp.org/index.php/Top_10_2010-A10-Unvalidated_Redirects_and_Forwards
class Arachni::Checks::UnvalidatedRedirect < Arachni::Check::Base
BASE_URL = "www.#{Utilities.random_seed}.com"
def self.payloads
@payloads ||= [
'www.arachni-boogie-woogie.com',
'https://www.arachni-boogie-woogie.com',
'http://www.arachni-boogie-woogie.com'
BASE_URL,
"https://#{BASE_URL}",
"http://#{BASE_URL}"
].map { |url| Arachni::URI( url ).to_s }
end
......@@ -77,7 +77,7 @@ URL to determine whether the attack was successful.
},
elements: ELEMENTS_WITH_INPUTS - [Element::LinkTemplate],
author: 'Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com>',
version: '0.2.3',
version: '0.2.4',
issue: {
name: %q{Unvalidated redirect},
......
......@@ -9,16 +9,16 @@
# Unvalidated redirect DOM check.
#
# @author Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com>
# @version 0.1.1
#
# @see https://www.owasp.org/index.php/Top_10_2010-A10-Unvalidated_Redirects_and_Forwards
class Arachni::Checks::UnvalidatedRedirectDOM < Arachni::Check::Base
BASE_URL = "www.#{Utilities.random_seed}.com"
def self.payloads
@payloads ||= [
'www.arachni-boogie-woogie.com',
'https://www.arachni-boogie-woogie.com',
'http://www.arachni-boogie-woogie.com'
BASE_URL,
"https://#{BASE_URL}",
"http://#{BASE_URL}"
].map { |url| Arachni::URI( url ).to_s }
end
......@@ -54,9 +54,12 @@ class Arachni::Checks::UnvalidatedRedirectDOM < Arachni::Check::Base
description: %q{
Injects URLs and checks the browser URL to determine whether the attack was successful.
},
elements: DOM_ELEMENTS_WITH_INPUTS - [Element::LinkTemplate::DOM],
elements: DOM_ELEMENTS_WITH_INPUTS - [
Element::LinkTemplate::DOM,
Element::UIInput::DOM
],
author: 'Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com>',
version: '0.1.1',
version: '0.1.2',
issue: {
name: %q{Unvalidated DOM redirect},
......
=begin
Copyright 2010-2015 Tasos Laskos <tasos.laskos@arachni-scanner.com>
This file is part of the Arachni Framework project and is subject to
redistribution and commercial restrictions. Please see the Arachni Framework
web site for more information on licensing and terms of use.
=end
# @author Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com>
# @version 0.2
class Arachni::Checks::XssDomInputs < Arachni::Check::Base
INPUTS = Set.new([:input, :textarea])
def tag_name
"some_dangerous_input_#{random_seed}"
end
def tag
# The trailing space is important, keypress and keyup events are always
# one character short.
"<#{tag_name}></#{tag_name}> "
end
def run
return if !page.document
# Everything past this point requires inputs to be present.
return if !page.has_elements?( INPUTS.to_a )
# Fill in inputs and trigger their associated events.
trigger_inputs
return if !page.has_elements?( :button )
# Fill in inputs and hit buttons.
trigger_buttons
end
def trigger_inputs
with_browser do |browser|
browser.load( page ).each_element_with_events do |locator, events|
locator_id = "#{page.url}:#{locator.css}"
next if !INPUTS.include?( locator.tag_name ) || audited?( locator_id )
audited locator_id
filter_events( locator.tag_name, events ).each do |event, _|
print_status "Scheduling '#{event}' on '#{locator}'"
# Instead of working with the same browser we do it this way
# in order to distribute the workload via the browser cluster.
with_browser do |b|
print_status "Triggering '#{event}' on '#{locator}'"
b.javascript.taint = self.tag_name
b.load page
transition = b.fire_event( locator, event, value: self.tag )
if !transition
print_bad "Could not '#{event}' on '#{locator}'"
next
end
# Page may be out of scope, some sort of JS redirection.
if !(p = b.to_page)
print_bad "Could not capture page snapshot after '#{event}' on '#{locator}'"
end
p.dom.transitions << transition
check_and_log( p )
print_status "Finished '#{event}' on '#{locator}'"
end
end
end
end
end
def trigger_buttons
with_browser do |browser|
browser.load( page ).each_element_with_events do |locator, events|
locator_id = "#{page.url}:#{locator.css}"
next if locator.tag_name != :button || audited?( locator_id )
audited locator_id
events.each do |event, _|
print_status "Scheduling '#{event}' on '#{locator}' after filling in inputs"
with_browser do |b|
print_status "Triggering '#{event}' on '#{locator}' after filling in inputs"
b.javascript.taint = self.tag_name
b.load page
transitions = fill_in_inputs( b )
if transitions.empty?
print_bad "Could not fill in any inputs for '#{event}' on '#{locator}'"
next
end
transition = b.fire_event( locator, event )
if !transition
print_bad "Could not '#{event}' on '#{locator}'"
next
end
transitions << transition
# Page may be out of scope, some sort of JS redirection.
if !(p = b.to_page)
print_bad "Could not capture page snapshot after '#{event}' on '#{locator}'"
end
transitions.each do |t|
p.dom.transitions << t
end
check_and_log( p )
print_status "Finished '#{event}' on '#{locator}' after filling in inputs"
end
end
end
end
end
def fill_in_inputs( browser )
transitions = []
INPUTS.each do |tag|
browser.watir.send("#{tag}s").each do |locator|
print_status "Filling in '#{locator.opening_tag}'"
transitions << fill_in_input( browser, locator )
end
end
transitions.compact
end
def fill_in_input( browser, locator )
browser.fire_event( locator, :input, value: self.tag )
end
def check_and_log( page )
return if !(proof = find_proof( page ))
log(
vector: Element::GenericDOM.new(
url: page.url,
transition: page.dom.transitions.last
),
proof: proof,
page: page
)
end
def find_proof( page )
return if !page.has_elements?( self.tag_name )
proof = page.document.css( self.tag_name )
return if proof.empty?
proof.to_s
end
def filter_events( element, events )
supported = Set.new( Arachni::Browser::Javascript.events_for( element ) )
events.reject { |name, _| !supported.include? ('on' + name.to_s.gsub( /^on/, '' )).to_sym }
end
def self.info
{
name: 'DOM XSS via input field',
description: %q{
Injects an HTML element into page text fields, triggers their associated events
and inspects the DOM for proof of vulnerability.
},
author: 'Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com>',
version: '0.2',
elements: [Element::GenericDOM],
issue: {
name: %q{DOM-based Cross-Site Scripting (XSS) via input fields},
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.
Unlike traditional Cross-Site Scripting (XSS), where the client is able to inject
scripts into a request and have the server return the script to the client, DOM
XSS does not require that a request be sent to the server and may be abused entirely
within the loaded page.
This occurs when elements of the DOM (known as the sources) are able to be
manipulated to contain untrusted data, which the client-side scripts (known as the
sinks) use or execute an unsafe way.
Arachni has discovered that by inserting an HTML element into the pages DOM inputs
(sources) it was possible to then have the HTML element rendered as part of the
page by the sink.
},
references: {
'WASC' => 'http://projects.webappsec.org/w/page/13246920/Cross%20Site%20Scripting',
'OWASP' => 'https://www.owasp.org/index.php/DOM_Based_XSS',
'OWASP - Prevention' => 'https://www.owasp.org/index.php/DOM_based_XSS_Prevention_Cheat_Sheet'
},
tags: %w(xss dom injection script),
cwe: 79,
severity: Severity::HIGH,
remedy_guidance: %q{
Client-side document rewriting, redirection, or other sensitive action, using
untrusted data, should be avoided wherever possible, as these may not be inspected
by server side filtering.
To remedy DOM XSS vulnerabilities where these sensitive document actions must be
used, it is essential to:
1. Ensure any untrusted data is treated as text, as opposed to being interpreted
as code or mark-up within the page.
2. Escape untrusted data prior to being used within the page. Escaping methods
will vary depending on where the untrusted data is being used.
(See references for details.)
3. Use `document.createElement`, `element.setAttribute`, `element.appendChild`,
etc. to build dynamic interfaces as opposed to HTML rendering methods such as
`document.write`, `document.writeIn`, `element.innerHTML`, or `element.outerHTML `etc.
}
}
}
end
end
......@@ -7,10 +7,10 @@
=end
# @author Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com>
# @version 0.2
# @version 0.2.1
class Arachni::Checks::Captcha < Arachni::Check::Base
CAPTCHA_RX = /captcha/i
CAPTCHA_RX = /.*captcha.*/i
def run
return if !page.body =~ CAPTCHA_RX
......@@ -18,23 +18,32 @@ class Arachni::Checks::Captcha < Arachni::Check::Base
# since we only care about forms parse the HTML and match forms only
page.document.css( 'form' ).each do |form|
# pretty dumb way to do this but it's a pretty dumb issue anyways...
next if !((form_html = form.to_s) =~ CAPTCHA_RX)
next if !(proof = find_proof( form ))
log(
signature: CAPTCHA_RX,
proof: form_html,
proof: proof,
vector: Element::Form.from_document( page.url, form ).first
)
end
end
def find_proof( node )
node.css('input').each do |input|
html = input.to_html
return html if html =~ CAPTCHA_RX
end
nil
end
def self.info
{
name: 'CAPTCHA',
description: %q{Greps pages for forms with CAPTCHAs.},
elements: [ Element::Form ],
author: 'Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com>',
version: '0.2',
version: '0.2.1',
issue: {
name: %q{CAPTCHA protected form},
......
......@@ -10,14 +10,18 @@
#
# @author Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com>
#
# @version 0.2.1
# @version 0.2.2
class Arachni::Checks::FormUpload < Arachni::Check::Base
def run
page.forms.each do |form|
form.inputs.keys.each do |name|
next if form.details_for( name )[:type] != :file
log( proof: form.source, vector: form )
log(
proof: form.node.xpath('input[@type="file"]').to_html,
vector: form
)
end
end
end
......@@ -28,7 +32,7 @@ class Arachni::Checks::FormUpload < Arachni::Check::Base
description: 'Logs upload forms which require manual testing.',
elements: [ Element::Form ],
author: 'Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com>',
version: '0.2.1',