arachni 1.1 → 1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +159 -0
- data/LICENSE.md +126 -196
- data/README.md +32 -24
- data/arachni.gemspec +7 -7
- data/components/checks/active/code_injection_timing.rb +3 -3
- data/components/checks/active/csrf.rb +2 -2
- data/components/checks/active/file_inclusion.rb +6 -7
- data/components/checks/active/os_cmd_injection.rb +3 -3
- data/components/checks/active/path_traversal.rb +7 -7
- data/components/checks/active/response_splitting.rb +9 -4
- data/components/checks/active/session_fixation.rb +7 -3
- data/components/checks/active/source_code_disclosure.rb +5 -5
- data/components/checks/active/unvalidated_redirect.rb +12 -3
- data/components/checks/active/unvalidated_redirect_dom.rb +3 -3
- data/components/checks/active/xss.rb +23 -10
- data/components/checks/active/xss_dom_inputs.rb +113 -11
- data/components/checks/active/xxe.rb +3 -3
- data/components/checks/passive/backdoors.rb +6 -5
- data/components/checks/passive/backup_directories.rb +6 -6
- data/components/checks/passive/backup_files.rb +6 -6
- data/components/checks/passive/common_admin_interfaces.rb +58 -0
- data/components/checks/passive/common_admin_interfaces/admin-panels.txt +49 -0
- data/components/checks/passive/common_directories/directories.txt +0 -16
- data/components/checks/passive/common_files.rb +6 -5
- data/components/checks/passive/common_files/filenames.txt +0 -2
- data/components/checks/passive/directory_listing.rb +6 -6
- data/components/checks/passive/grep/cookie_set_for_parent_domain.rb +3 -3
- data/components/checks/passive/grep/hsts.rb +6 -3
- data/components/checks/passive/grep/http_only_cookies.rb +3 -3
- data/components/checks/passive/grep/insecure_cookies.rb +2 -2
- data/components/checks/passive/grep/insecure_cors_policy.rb +6 -4
- data/components/checks/passive/grep/x_frame_options.rb +6 -4
- data/components/checks/passive/htaccess_limit.rb +6 -2
- data/components/checks/passive/http_put.rb +8 -4
- data/components/checks/passive/interesting_responses.rb +3 -2
- data/components/checks/passive/localstart_asp.rb +6 -2
- data/components/checks/passive/origin_spoof_access_restriction_bypass.rb +5 -1
- data/components/checks/passive/xst.rb +6 -2
- data/components/fingerprinters/frameworks/aspx_mvc.rb +43 -0
- data/components/fingerprinters/frameworks/cakephp.rb +28 -0
- data/components/fingerprinters/frameworks/cherrypy.rb +31 -0
- data/components/fingerprinters/frameworks/django.rb +33 -0
- data/components/fingerprinters/frameworks/jsf.rb +30 -0
- data/components/fingerprinters/frameworks/rack.rb +5 -7
- data/components/fingerprinters/frameworks/rails.rb +43 -0
- data/components/fingerprinters/languages/aspx.rb +11 -11
- data/components/fingerprinters/languages/{jsp.rb → java.rb} +11 -7
- data/components/fingerprinters/languages/php.rb +6 -6
- data/components/fingerprinters/languages/python.rb +14 -6
- data/components/fingerprinters/languages/ruby.rb +3 -5
- data/components/fingerprinters/servers/apache.rb +5 -4
- data/components/fingerprinters/servers/gunicorn.rb +33 -0
- data/components/fingerprinters/servers/jetty.rb +1 -1
- data/components/fingerprinters/servers/tomcat.rb +11 -4
- data/components/path_extractors/anchors.rb +5 -12
- data/components/path_extractors/areas.rb +5 -13
- data/components/path_extractors/comments.rb +5 -3
- data/components/path_extractors/data_url.rb +21 -0
- data/components/path_extractors/forms.rb +5 -13
- data/components/path_extractors/frames.rb +6 -13
- data/components/path_extractors/generic.rb +3 -12
- data/components/path_extractors/links.rb +5 -13
- data/components/path_extractors/meta_refresh.rb +5 -13
- data/components/path_extractors/scripts.rb +8 -14
- data/components/plugins/autologin.rb +17 -5
- data/components/plugins/defaults/meta/remedies/discovery.rb +11 -29
- data/components/plugins/login_script.rb +40 -10
- data/components/plugins/metrics.rb +235 -0
- data/components/plugins/proxy.rb +21 -4
- data/components/plugins/proxy/panel/page_accordion.html.erb +34 -2
- data/components/plugins/restrict_to_dom_state.rb +70 -0
- data/components/plugins/vector_feed.rb +38 -9
- data/components/reporters/plugin_formatters/html/metrics.rb +290 -0
- data/components/reporters/plugin_formatters/stdout/metrics.rb +80 -0
- data/components/reporters/plugin_formatters/xml/metrics.rb +29 -0
- data/components/reporters/stdout.rb +4 -2
- data/components/reporters/xml.rb +4 -4
- data/components/reporters/xml/schema.xsd +95 -0
- data/lib/arachni.rb +2 -0
- data/lib/arachni/browser.rb +132 -77
- data/lib/arachni/browser/javascript.rb +173 -45
- data/lib/arachni/browser/javascript/scripts/dom_monitor.js +81 -6
- data/lib/arachni/browser/javascript/scripts/taint_tracer.js +31 -3
- data/lib/arachni/browser_cluster.rb +41 -15
- data/lib/arachni/browser_cluster/job.rb +4 -0
- data/lib/arachni/browser_cluster/jobs/resource_exploration.rb +0 -9
- data/lib/arachni/browser_cluster/worker.rb +8 -5
- data/lib/arachni/check/auditor.rb +20 -8
- data/lib/arachni/check/base.rb +38 -6
- data/lib/arachni/element/base.rb +18 -1
- data/lib/arachni/element/capabilities/analyzable/differential.rb +0 -1
- data/lib/arachni/element/capabilities/analyzable/taint.rb +40 -10
- data/lib/arachni/element/capabilities/analyzable/timeout.rb +27 -23
- data/lib/arachni/element/capabilities/auditable/dom.rb +22 -0
- data/lib/arachni/element/capabilities/inputtable.rb +6 -2
- data/lib/arachni/element/capabilities/submittable.rb +1 -1
- data/lib/arachni/element/cookie.rb +37 -23
- data/lib/arachni/element/cookie/capabilities/mutable.rb +6 -6
- data/lib/arachni/element/cookie/dom.rb +0 -8
- data/lib/arachni/element/form.rb +28 -14
- data/lib/arachni/element/form/capabilities/auditable.rb +2 -2
- data/lib/arachni/element/form/capabilities/mutable.rb +5 -5
- data/lib/arachni/element/form/dom.rb +0 -8
- data/lib/arachni/element/generic_dom.rb +1 -1
- data/lib/arachni/element/json.rb +2 -1
- data/lib/arachni/element/json/capabilities/inputtable.rb +6 -6
- data/lib/arachni/element/json/capabilities/mutable.rb +1 -1
- data/lib/arachni/element/link.rb +13 -16
- data/lib/arachni/element/link/dom.rb +1 -14
- data/lib/arachni/element/link_template.rb +3 -2
- data/lib/arachni/element/link_template/dom.rb +0 -16
- data/lib/arachni/element/server.rb +51 -9
- data/lib/arachni/element/xml.rb +1 -0
- data/lib/arachni/ethon/easy.rb +4 -1
- data/lib/arachni/framework/parts/audit.rb +26 -77
- data/lib/arachni/framework/parts/browser.rb +50 -55
- data/lib/arachni/framework/parts/check.rb +4 -3
- data/lib/arachni/framework/parts/data.rb +41 -6
- data/lib/arachni/framework/parts/state.rb +16 -7
- data/lib/arachni/http/client.rb +66 -38
- data/lib/arachni/http/client/dynamic_404_handler.rb +46 -14
- data/lib/arachni/http/headers.rb +22 -10
- data/lib/arachni/http/proxy_server.rb +67 -22
- data/lib/arachni/http/proxy_server/ssl-interceptor-cacert.pem +34 -0
- data/lib/arachni/http/proxy_server/ssl-interceptor-cakey.pem +51 -0
- data/lib/arachni/http/request.rb +71 -18
- data/lib/arachni/issue.rb +17 -3
- data/lib/arachni/option_groups/browser_cluster.rb +34 -1
- data/lib/arachni/option_groups/http.rb +1 -1
- data/lib/arachni/page.rb +26 -13
- data/lib/arachni/page/dom/transition.rb +2 -2
- data/lib/arachni/parser.rb +28 -11
- data/lib/arachni/platform/fingerprinter.rb +5 -0
- data/lib/arachni/platform/manager.rb +65 -32
- data/lib/arachni/plugin/base.rb +8 -0
- data/lib/arachni/processes/instances.rb +25 -11
- data/lib/arachni/reporter/manager.rb +2 -2
- data/lib/arachni/rpc/client/instance.rb +4 -0
- data/lib/arachni/rpc/server/framework/master.rb +3 -3
- data/lib/arachni/rpc/server/framework/multi_instance.rb +0 -8
- data/lib/arachni/rpc/server/instance.rb +2 -1
- data/lib/arachni/ruby/array.rb +5 -0
- data/lib/arachni/ruby/hash.rb +5 -0
- data/lib/arachni/ruby/string.rb +2 -3
- data/lib/arachni/session.rb +32 -6
- data/lib/arachni/state/framework.rb +6 -2
- data/lib/arachni/support/cache.rb +1 -0
- data/lib/arachni/support/cache/base.rb +12 -8
- data/lib/arachni/support/cache/least_recently_pushed.rb +29 -0
- data/lib/arachni/support/cache/least_recently_used.rb +5 -8
- data/lib/arachni/support/cache/preference.rb +1 -1
- data/lib/arachni/support/cache/random_replacement.rb +1 -25
- data/lib/arachni/support/database/queue.rb +21 -8
- data/lib/arachni/support/lookup/base.rb +7 -1
- data/lib/arachni/support/mixins/observable.rb +3 -1
- data/lib/arachni/support/profiler.rb +51 -10
- data/lib/arachni/support/signature.rb +11 -2
- data/lib/arachni/trainer.rb +8 -2
- data/lib/arachni/uri.rb +28 -25
- data/lib/arachni/uri/scope.rb +1 -1
- data/lib/arachni/utilities.rb +8 -0
- data/lib/arachni/watir/element.rb +1 -1
- data/lib/version +1 -1
- data/spec/arachni/browser/javascript/dom_monitor_spec.rb +388 -53
- data/spec/arachni/browser/javascript/taint_tracer_spec.rb +41 -0
- data/spec/arachni/browser/javascript_spec.rb +235 -61
- data/spec/arachni/browser_cluster/jobs/resource_exploration_spec.rb +0 -9
- data/spec/arachni/browser_cluster_spec.rb +58 -10
- data/spec/arachni/browser_spec.rb +170 -26
- data/spec/arachni/check/auditor_spec.rb +22 -3
- data/spec/arachni/check/base_spec.rb +84 -0
- data/spec/arachni/element/body_spec.rb +1 -1
- data/spec/arachni/element/capabilities/analyzable/taint_spec.rb +3 -3
- data/spec/arachni/element/capabilities/analyzable/timeout_spec.rb +1 -1
- data/spec/arachni/element/cookie/dom_spec.rb +0 -9
- data/spec/arachni/element/cookie_spec.rb +85 -0
- data/spec/arachni/element/form/dom_spec.rb +0 -9
- data/spec/arachni/element/form_spec.rb +46 -3
- data/spec/arachni/element/json_spec.rb +20 -0
- data/spec/arachni/element/link/dom_spec.rb +0 -9
- data/spec/arachni/element/link_spec.rb +40 -15
- data/spec/arachni/element/link_template/dom_spec.rb +0 -8
- data/spec/arachni/element/link_template_spec.rb +2 -6
- data/spec/arachni/element/server_spec.rb +94 -8
- data/spec/arachni/element/xml_spec.rb +20 -0
- data/spec/arachni/framework/parts/audit_spec.rb +12 -14
- data/spec/arachni/framework/parts/browser_spec.rb +0 -171
- data/spec/arachni/framework/parts/platform_spec.rb +14 -8
- data/spec/arachni/framework/parts/report_spec.rb +1 -1
- data/spec/arachni/framework/parts/state_spec.rb +0 -9
- data/spec/arachni/http/client/dynamic_404_handlers_spec.rb +19 -0
- data/spec/arachni/http/client_spec.rb +169 -42
- data/spec/arachni/http/headers_spec.rb +18 -0
- data/spec/arachni/http/request_spec.rb +23 -0
- data/spec/arachni/issue_spec.rb +17 -6
- data/spec/arachni/page_spec.rb +22 -2
- data/spec/arachni/parser_spec.rb +5 -0
- data/spec/arachni/platform/manager_spec.rb +57 -25
- data/spec/arachni/reporter/manager_spec.rb +26 -0
- data/spec/arachni/rpc/server/active_options_spec.rb +9 -4
- data/spec/arachni/state/framework_spec.rb +2 -8
- data/spec/arachni/support/cache/least_recently_pushed_spec.rb +90 -0
- data/spec/arachni/support/cache/least_recently_used_spec.rb +5 -13
- data/spec/arachni/support/database/queue_spec.rb +7 -0
- data/spec/arachni/support/mixins/observable_spec.rb +15 -1
- data/spec/arachni/trainer_spec.rb +2 -2
- data/spec/components/checks/active/code_injection_timing_spec.rb +1 -1
- data/spec/components/checks/active/file_inclusion_spec.rb +6 -6
- data/spec/components/checks/active/path_traversal_spec.rb +2 -2
- data/spec/components/checks/active/source_code_disclosure_spec.rb +2 -2
- data/spec/components/checks/active/unvalidated_redirect_spec.rb +6 -6
- data/spec/components/checks/active/xss_dom_inputs_spec.rb +3 -5
- data/spec/components/checks/active/xss_dom_script_context_spec.rb +1 -1
- data/spec/components/checks/active/xss_spec.rb +5 -5
- data/spec/components/checks/passive/common_admin_interfaces_spec.rb +15 -0
- data/spec/components/checks/passive/interesting_responses_spec.rb +14 -1
- data/spec/components/fingerprinters/frameworks/aspx_mvc_spec.rb +31 -0
- data/spec/components/fingerprinters/frameworks/cakephp_spec.rb +22 -0
- data/spec/components/fingerprinters/frameworks/cherrypy_spec.rb +28 -0
- data/spec/components/fingerprinters/frameworks/django_spec.rb +37 -0
- data/spec/components/fingerprinters/frameworks/jsf_spec.rb +27 -0
- data/spec/components/fingerprinters/frameworks/rack_spec.rb +11 -14
- data/spec/components/fingerprinters/frameworks/rails_spec.rb +53 -0
- data/spec/components/fingerprinters/languages/asp_spec.rb +7 -9
- data/spec/components/fingerprinters/languages/aspx_spec.rb +10 -24
- data/spec/components/fingerprinters/languages/java_spec.rb +88 -0
- data/spec/components/fingerprinters/languages/php_spec.rb +19 -12
- data/spec/components/fingerprinters/languages/python_spec.rb +22 -9
- data/spec/components/fingerprinters/languages/ruby.rb +6 -4
- data/spec/components/fingerprinters/os/bsd_spec.rb +6 -4
- data/spec/components/fingerprinters/os/linux_spec.rb +6 -4
- data/spec/components/fingerprinters/os/solaris_spec.rb +6 -4
- data/spec/components/fingerprinters/os/unix_spec.rb +6 -4
- data/spec/components/fingerprinters/os/windows_spec.rb +6 -4
- data/spec/components/fingerprinters/servers/apache_spec.rb +15 -4
- data/spec/components/fingerprinters/servers/gunicorn_spec.rb +28 -0
- data/spec/components/fingerprinters/servers/iis_spec.rb +6 -6
- data/spec/components/fingerprinters/servers/jetty_spec.rb +6 -6
- data/spec/components/fingerprinters/servers/nginx_spec.rb +6 -4
- data/spec/components/fingerprinters/servers/tomcat_spec.rb +15 -6
- data/spec/components/path_extractors/data_url_spec.rb +19 -0
- data/spec/components/plugins/autologin_spec.rb +23 -0
- data/spec/components/plugins/login_script_spec.rb +112 -24
- data/spec/components/plugins/restrict_to_dom_state_spec.rb +16 -0
- data/spec/components/plugins/vector_feed_spec.rb +39 -1
- data/spec/support/factories/page/dom.rb +9 -4
- data/spec/support/factories/page/dom/transition.rb +31 -9
- data/spec/support/factories/scan_report.rb +8 -6
- data/spec/support/fixtures/empty/placeholder +0 -0
- data/spec/support/fixtures/report.afr +0 -0
- data/spec/support/fixtures/reporters/manager_spec/error.rb +18 -0
- data/spec/support/servers/arachni/browser.rb +117 -11
- data/spec/support/servers/arachni/browser/javascript/dom_monitor.rb +148 -4
- data/spec/support/servers/arachni/check/auditor.rb +4 -0
- data/spec/support/servers/arachni/element/cookie/cookie_dom.rb +1 -1
- data/spec/support/servers/arachni/http/client.rb +5 -0
- data/spec/support/servers/arachni/http/client/dynamic_404_handler.rb +13 -0
- data/spec/support/servers/checks/active/code_injection_timing.rb +1 -1
- data/spec/support/servers/checks/active/file_inclusion.rb +2 -2
- data/spec/support/servers/checks/active/path_traversal.rb +2 -2
- data/spec/support/servers/checks/active/source_code_disclosure.rb +40 -33
- data/spec/support/servers/checks/active/trainer_check.rb +9 -10
- data/spec/support/servers/checks/active/unvalidated_redirect_dom.rb +7 -4
- data/spec/support/servers/checks/active/xss.rb +35 -0
- data/spec/support/servers/checks/active/xss_dom.rb +1 -1
- data/spec/support/servers/checks/active/xss_dom_inputs.rb +24 -0
- data/spec/support/servers/checks/active/xss_dom_script_context.rb +1 -1
- data/spec/support/servers/checks/passive/common_admin_interfaces.rb +6 -0
- data/spec/support/servers/plugins/autologin.rb +9 -0
- data/spec/support/servers/plugins/restrict_to_dom_state.rb +4 -0
- data/spec/support/shared/element/base.rb +42 -0
- data/spec/support/shared/element/capabilities/auditable.rb +4 -4
- data/spec/support/shared/element/capabilities/auditable/dom.rb +26 -0
- data/spec/support/shared/element/capabilities/inputtable.rb +16 -11
- data/spec/support/shared/element/capabilities/submitable.rb +7 -2
- data/spec/support/shared/fingerprinter.rb +8 -0
- data/spec/support/shared/path_extractor.rb +1 -1
- data/ui/cli/framework.rb +3 -3
- data/ui/cli/framework/option_parser.rb +9 -0
- data/ui/cli/output.rb +9 -0
- data/ui/cli/reporter.rb +5 -2
- data/ui/cli/utilities.rb +4 -2
- metadata +76 -17
- data/lib/arachni/http/proxy_server/ssl-interceptor-cert.pem +0 -34
- data/lib/arachni/http/proxy_server/ssl-interceptor-pkey.pem +0 -51
- data/spec/components/fingerprinters/languages/jsp_spec.rb +0 -56
@@ -0,0 +1,29 @@
|
|
1
|
+
=begin
|
2
|
+
Copyright 2010-2015 Tasos Laskos <tasos.laskos@arachni-scanner.com>
|
3
|
+
|
4
|
+
This file is part of the Arachni Framework project and is subject to
|
5
|
+
redistribution and commercial restrictions. Please see the Arachni Framework
|
6
|
+
web site for more information on licensing and terms of use.
|
7
|
+
=end
|
8
|
+
|
9
|
+
class Arachni::Reporters::XML
|
10
|
+
|
11
|
+
# @author Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com>
|
12
|
+
class PluginFormatters::Metrics < Arachni::Plugin::Formatter
|
13
|
+
|
14
|
+
def run( xml )
|
15
|
+
results.each do |category, data|
|
16
|
+
xml.send( category ) {
|
17
|
+
data.each do |k, v|
|
18
|
+
if category == 'platforms'
|
19
|
+
v = v.join( ',' )
|
20
|
+
end
|
21
|
+
|
22
|
+
xml.send k, v
|
23
|
+
end
|
24
|
+
}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
@@ -10,7 +10,7 @@
|
|
10
10
|
# All UIs must have a default report.
|
11
11
|
#
|
12
12
|
# @author Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com>
|
13
|
-
# @version 0.3
|
13
|
+
# @version 0.3.1
|
14
14
|
class Arachni::Reporters::Stdout < Arachni::Reporter::Base
|
15
15
|
|
16
16
|
def run
|
@@ -46,6 +46,8 @@ class Arachni::Reporters::Stdout < Arachni::Reporter::Base
|
|
46
46
|
print_info '* Forms' if report.options[:audit][:forms]
|
47
47
|
print_info '* Cookies' if report.options[:audit][:cookies]
|
48
48
|
print_info '* Headers' if report.options[:audit][:headers]
|
49
|
+
print_info '* XMLs' if report.options[:audit][:xmls]
|
50
|
+
print_info '* JSONs' if report.options[:audit][:jsons]
|
49
51
|
print_line
|
50
52
|
print_status "Checks: #{report.options[:checks].join( ', ' )}"
|
51
53
|
|
@@ -223,7 +225,7 @@ class Arachni::Reporters::Stdout < Arachni::Reporter::Base
|
|
223
225
|
name: 'Stdout',
|
224
226
|
description: %q{Prints the results to standard output.},
|
225
227
|
author: 'Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com>',
|
226
|
-
version: '0.3'
|
228
|
+
version: '0.3.1'
|
227
229
|
}
|
228
230
|
end
|
229
231
|
|
data/components/reporters/xml.rb
CHANGED
@@ -11,7 +11,7 @@ require 'nokogiri'
|
|
11
11
|
# Creates an XML report of the audit.
|
12
12
|
#
|
13
13
|
# @author Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com>
|
14
|
-
# @version 0.3.
|
14
|
+
# @version 0.3.4
|
15
15
|
class Arachni::Reporters::XML < Arachni::Reporter::Base
|
16
16
|
|
17
17
|
LOCAL_SCHEMA = File.dirname( __FILE__ ) + '/xml/schema.xsd'
|
@@ -77,8 +77,8 @@ class Arachni::Reporters::XML < Arachni::Reporter::Base
|
|
77
77
|
xml.method_ vector.method
|
78
78
|
end
|
79
79
|
|
80
|
-
if vector.respond_to? :affected_input_name
|
81
|
-
xml.affected_input_name vector.affected_input_name
|
80
|
+
if issue.variations.first.vector.respond_to? :affected_input_name
|
81
|
+
xml.affected_input_name issue.variations.first.vector.affected_input_name
|
82
82
|
end
|
83
83
|
|
84
84
|
if vector.respond_to? :inputs
|
@@ -166,7 +166,7 @@ class Arachni::Reporters::XML < Arachni::Reporter::Base
|
|
166
166
|
description: %q{Exports the audit results as an XML (.xml) file.},
|
167
167
|
content_type: 'text/xml',
|
168
168
|
author: 'Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com>',
|
169
|
-
version: '0.3.
|
169
|
+
version: '0.3.4',
|
170
170
|
options: [ Options.outfile( '.xml' ), Options.skip_responses ]
|
171
171
|
}
|
172
172
|
end
|
@@ -35,9 +35,104 @@
|
|
35
35
|
<xs:element name="waf_detector" type="plugin_waf_detector" maxOccurs="1"/>
|
36
36
|
<xs:element name="vector_collector" type="plugin_vector_collector" maxOccurs="1"/>
|
37
37
|
<xs:element name="exec" type="plugin_exec" maxOccurs="1"/>
|
38
|
+
<xs:element name="metrics" type="plugin_metrics" maxOccurs="1"/>
|
38
39
|
</xs:choice>
|
39
40
|
</xs:complexType>
|
40
41
|
|
42
|
+
<xs:complexType name="plugin_metrics">
|
43
|
+
<xs:all>
|
44
|
+
<xs:element name="name" type="xs:string"/>
|
45
|
+
<xs:element name="description" type="xs:string"/>
|
46
|
+
<xs:element name="results" type="plugin_metrics_results"/>
|
47
|
+
</xs:all>
|
48
|
+
</xs:complexType>
|
49
|
+
|
50
|
+
<xs:complexType name="plugin_metrics_results">
|
51
|
+
<xs:all>
|
52
|
+
<xs:element name="general" type="plugin_metrics_results_general"/>
|
53
|
+
<xs:element name="scan" type="plugin_metrics_results_scan"/>
|
54
|
+
<xs:element name="http" type="plugin_metrics_results_http"/>
|
55
|
+
<xs:element name="resource" type="plugin_metrics_results_resource"/>
|
56
|
+
<xs:element name="element" type="plugin_metrics_results_element"/>
|
57
|
+
<xs:element name="dom" type="plugin_metrics_results_dom"/>
|
58
|
+
<xs:element name="platforms" type="plugin_metrics_results_platforms"/>
|
59
|
+
</xs:all>
|
60
|
+
</xs:complexType>
|
61
|
+
|
62
|
+
<xs:complexType name="plugin_metrics_results_general">
|
63
|
+
<xs:all>
|
64
|
+
<xs:element name="egress_traffic" type="xs:integer"/>
|
65
|
+
<xs:element name="ingress_traffic" type="xs:integer"/>
|
66
|
+
<xs:element name="uses_http" type="xs:boolean"/>
|
67
|
+
<xs:element name="uses_https" type="xs:boolean"/>
|
68
|
+
</xs:all>
|
69
|
+
</xs:complexType>
|
70
|
+
|
71
|
+
<xs:complexType name="plugin_metrics_results_scan">
|
72
|
+
<xs:all>
|
73
|
+
<xs:element name="duration" type="xs:float"/>
|
74
|
+
<xs:element name="authenticated" type="xs:boolean"/>
|
75
|
+
</xs:all>
|
76
|
+
</xs:complexType>
|
77
|
+
|
78
|
+
<xs:complexType name="plugin_metrics_results_http">
|
79
|
+
<xs:all>
|
80
|
+
<xs:element name="requests" type="xs:integer"/>
|
81
|
+
<xs:element name="response_time_min" type="xs:float"/>
|
82
|
+
<xs:element name="response_time_max" type="xs:float"/>
|
83
|
+
<xs:element name="response_time_average" type="xs:float"/>
|
84
|
+
|
85
|
+
<xs:element name="response_size_min" type="xs:float"/>
|
86
|
+
<xs:element name="response_size_max" type="xs:float"/>
|
87
|
+
<xs:element name="response_size_average" type="xs:float"/>
|
88
|
+
|
89
|
+
<xs:element name="request_size_min" type="xs:float"/>
|
90
|
+
<xs:element name="request_size_max" type="xs:float"/>
|
91
|
+
<xs:element name="request_size_average" type="xs:float"/>
|
92
|
+
</xs:all>
|
93
|
+
</xs:complexType>
|
94
|
+
|
95
|
+
<xs:complexType name="plugin_metrics_results_resource">
|
96
|
+
<xs:all>
|
97
|
+
<xs:element name="binary" type="xs:integer"/>
|
98
|
+
<xs:element name="without_parameters" type="xs:integer"/>
|
99
|
+
<xs:element name="with_parameters" type="xs:integer"/>
|
100
|
+
</xs:all>
|
101
|
+
</xs:complexType>
|
102
|
+
|
103
|
+
<xs:complexType name="plugin_metrics_results_element">
|
104
|
+
<xs:all>
|
105
|
+
<xs:element name="links" type="xs:integer"/>
|
106
|
+
<xs:element name="forms" type="xs:integer"/>
|
107
|
+
<xs:element name="has_forms_with_nonces" type="xs:boolean"/>
|
108
|
+
<xs:element name="has_forms_with_passwords" type="xs:boolean"/>
|
109
|
+
<xs:element name="cookies" type="xs:integer"/>
|
110
|
+
<xs:element name="headers" type="xs:integer"/>
|
111
|
+
<xs:element name="xmls" type="xs:integer"/>
|
112
|
+
<xs:element name="jsons" type="xs:integer"/>
|
113
|
+
<xs:element name="input_names_total" type="xs:integer"/>
|
114
|
+
<xs:element name="input_names_unique" type="xs:integer"/>
|
115
|
+
</xs:all>
|
116
|
+
</xs:complexType>
|
117
|
+
|
118
|
+
<xs:complexType name="plugin_metrics_results_dom">
|
119
|
+
<xs:all>
|
120
|
+
<xs:element name="event_listeners" type="xs:integer"/>
|
121
|
+
<xs:element name="swf_objects" type="xs:integer"/>
|
122
|
+
</xs:all>
|
123
|
+
</xs:complexType>
|
124
|
+
|
125
|
+
<xs:complexType name="plugin_metrics_results_platforms">
|
126
|
+
<xs:all>
|
127
|
+
<!-- CSV platform names for values in these fields. -->
|
128
|
+
<xs:element name="os" type="xs:string"/>
|
129
|
+
<xs:element name="db" type="xs:string"/>
|
130
|
+
<xs:element name="servers" type="xs:string"/>
|
131
|
+
<xs:element name="languages" type="xs:string"/>
|
132
|
+
<xs:element name="frameworks" type="xs:string"/>
|
133
|
+
</xs:all>
|
134
|
+
</xs:complexType>
|
135
|
+
|
41
136
|
<xs:complexType name="plugin_exec">
|
42
137
|
<xs:all>
|
43
138
|
<xs:element name="name" type="xs:string"/>
|
data/lib/arachni.rb
CHANGED
data/lib/arachni/browser.rb
CHANGED
@@ -70,7 +70,16 @@ class Browser
|
|
70
70
|
# Let the browser take as long as it needs to complete an operation.
|
71
71
|
WATIR_COM_TIMEOUT = 3600 # 1 hour.
|
72
72
|
|
73
|
-
|
73
|
+
ASSET_EXTENSIONS = Set.new(
|
74
|
+
['css', 'js', 'jpg', 'jpeg', 'png', 'gif', 'woff', 'json']
|
75
|
+
)
|
76
|
+
|
77
|
+
ASSET_EXTRACTORS = [
|
78
|
+
/<\s*link.*?href=['"](.*?)['"].*?>/im,
|
79
|
+
/<\s*script.*?src=['"](.*?)['"].*?>/im,
|
80
|
+
/<\s*img.*?src=['"](.*?)['"].*?>/im,
|
81
|
+
/<\s*input.*?src=['"](.*?)['"].*?>/im,
|
82
|
+
]
|
74
83
|
|
75
84
|
# @return [Array<Page::DOM::Transition>]
|
76
85
|
attr_reader :transitions
|
@@ -107,6 +116,10 @@ class Browser
|
|
107
116
|
# @return [Integer]
|
108
117
|
attr_reader :pid
|
109
118
|
|
119
|
+
attr_reader :last_url
|
120
|
+
|
121
|
+
attr_reader :last_dom_url
|
122
|
+
|
110
123
|
# @return [Bool]
|
111
124
|
# `true` if a supported browser is in the OS PATH, `false` otherwise.
|
112
125
|
def self.has_executable?
|
@@ -119,6 +132,19 @@ class Browser
|
|
119
132
|
Selenium::WebDriver::PhantomJS.path
|
120
133
|
end
|
121
134
|
|
135
|
+
def self.asset_domains
|
136
|
+
@asset_domains ||= Set.new
|
137
|
+
end
|
138
|
+
asset_domains
|
139
|
+
|
140
|
+
def self.add_asset_domain( url )
|
141
|
+
return if url.to_s.empty?
|
142
|
+
return if !(curl = Arachni::URI( url ))
|
143
|
+
return if !(domain = curl.domain)
|
144
|
+
|
145
|
+
asset_domains << domain
|
146
|
+
end
|
147
|
+
|
122
148
|
# @param [Hash] options
|
123
149
|
# @option options [Integer] :concurrency
|
124
150
|
# Maximum number of concurrent connections.
|
@@ -313,7 +339,8 @@ class Browser
|
|
313
339
|
@add_request_transitions = false
|
314
340
|
end
|
315
341
|
|
316
|
-
@last_url = url
|
342
|
+
@last_url = Arachni::URI( url ).to_s
|
343
|
+
self.class.add_asset_domain @last_url
|
317
344
|
|
318
345
|
ensure_open_window
|
319
346
|
|
@@ -326,9 +353,23 @@ class Browser
|
|
326
353
|
watir.goto url
|
327
354
|
|
328
355
|
@javascript.wait_till_ready
|
356
|
+
wait_for_pending_requests
|
329
357
|
wait_for_timers
|
330
358
|
|
331
|
-
|
359
|
+
url = watir.url
|
360
|
+
Options.browser_cluster.css_to_wait_for( url ).each do |css|
|
361
|
+
print_info "Waiting for #{css.inspect} to appear for: #{url}"
|
362
|
+
|
363
|
+
begin
|
364
|
+
watir.element( css: css ).
|
365
|
+
wait_until_present( Options.browser_cluster.job_timeout )
|
366
|
+
|
367
|
+
print_info "#{css.inspect} appeared for: #{url}"
|
368
|
+
rescue Watir::Wait::TimeoutError
|
369
|
+
print_bad "#{css.inspect} did not appeared for: #{url}"
|
370
|
+
end
|
371
|
+
|
372
|
+
end
|
332
373
|
|
333
374
|
javascript.set_element_ids
|
334
375
|
end
|
@@ -771,32 +812,35 @@ class Browser
|
|
771
812
|
# them if no events are associated with it.
|
772
813
|
#
|
773
814
|
# This can save **A LOT** of time during the audit.
|
774
|
-
if
|
775
|
-
|
776
|
-
|
815
|
+
if @javascript.supported?
|
816
|
+
if Options.audit.form_doms?
|
817
|
+
page.forms.each do |form|
|
818
|
+
next if !form.node || !form.dom
|
777
819
|
|
778
|
-
|
779
|
-
|
820
|
+
action = form.node['action'].to_s
|
821
|
+
form.dom.browser = self
|
780
822
|
|
781
|
-
|
782
|
-
|
823
|
+
next if action.downcase.start_with?( 'javascript:' ) ||
|
824
|
+
form.dom.locate.events.any?
|
825
|
+
|
826
|
+
form.skip_dom = true
|
827
|
+
end
|
783
828
|
|
784
|
-
|
829
|
+
page.update_metadata
|
830
|
+
page.clear_cache
|
785
831
|
end
|
786
832
|
|
787
|
-
|
788
|
-
|
833
|
+
if Options.audit.cookie_doms?
|
834
|
+
sinks = @javascript.taint_tracer.data_flow_sinks
|
835
|
+
page.cookies.each do |cookie|
|
836
|
+
next if sinks.include?( cookie.name ) ||
|
837
|
+
sinks.include?( cookie.value )
|
789
838
|
|
790
|
-
|
791
|
-
|
792
|
-
page.cookies.each do |cookie|
|
793
|
-
next if sinks.include?( cookie.name ) ||
|
794
|
-
sinks.include?( cookie.value )
|
839
|
+
cookie.skip_dom = true
|
840
|
+
end
|
795
841
|
|
796
|
-
|
842
|
+
page.update_metadata
|
797
843
|
end
|
798
|
-
|
799
|
-
page.update_metadata
|
800
844
|
end
|
801
845
|
|
802
846
|
page
|
@@ -890,7 +934,7 @@ class Browser
|
|
890
934
|
|
891
935
|
c[:path] = '/' if c[:path] == '//'
|
892
936
|
c[:name] = Cookie.decode( c[:name].to_s )
|
893
|
-
c[:value] = Cookie.
|
937
|
+
c[:value] = Cookie.value_to_v0( c[:value].to_s )
|
894
938
|
c[:httponly] = !js_cookies.include?( original_name )
|
895
939
|
|
896
940
|
Cookie.new c.merge( url: @last_url || url )
|
@@ -1090,11 +1134,12 @@ class Browser
|
|
1090
1134
|
buff = ''
|
1091
1135
|
# Wait for PhantomJS to initialize.
|
1092
1136
|
while !buff.include?( 'running on port' )
|
1093
|
-
#
|
1094
|
-
#
|
1095
|
-
buff << (out.
|
1137
|
+
# This can be problematic on something other than
|
1138
|
+
# MRI.
|
1139
|
+
buff << (out.readline rescue '').to_s
|
1096
1140
|
end
|
1097
1141
|
|
1142
|
+
buff = nil
|
1098
1143
|
print_debug 'Boot-up complete.'
|
1099
1144
|
done = true
|
1100
1145
|
end
|
@@ -1106,6 +1151,7 @@ class Browser
|
|
1106
1151
|
if @process.io.stdout
|
1107
1152
|
last_attempt_output = IO.read( @process.io.stdout )
|
1108
1153
|
print_debug last_attempt_output
|
1154
|
+
@process.io.stdout.close!
|
1109
1155
|
end
|
1110
1156
|
|
1111
1157
|
if done
|
@@ -1286,7 +1332,17 @@ class Browser
|
|
1286
1332
|
request.performer = self
|
1287
1333
|
|
1288
1334
|
return if request.headers['X-Arachni-Browser-Auth'] != auth_token
|
1289
|
-
request.headers.delete
|
1335
|
+
request.headers.delete 'X-Arachni-Browser-Auth'
|
1336
|
+
|
1337
|
+
# We can't have 304 page responses in the framework, we need full request
|
1338
|
+
# and response data, the browser cache doesn't help us here.
|
1339
|
+
#
|
1340
|
+
# Still, it's a nice feature to have when requesting assets or anything
|
1341
|
+
# else.
|
1342
|
+
if request.url == @last_url
|
1343
|
+
request.headers.delete 'If-None-Match'
|
1344
|
+
request.headers.delete 'If-Modified-Since'
|
1345
|
+
end
|
1290
1346
|
|
1291
1347
|
return if @javascript.serve( request, response )
|
1292
1348
|
|
@@ -1300,21 +1356,29 @@ class Browser
|
|
1300
1356
|
|
1301
1357
|
# Signal the proxy to not actually perform the request if we have a
|
1302
1358
|
# preloaded or cached response for it.
|
1303
|
-
|
1304
|
-
|
1305
|
-
|
1306
|
-
|
1307
|
-
# other browser requests and convert them into elements we can analyze
|
1308
|
-
# and audit.
|
1309
|
-
capture( request )
|
1310
|
-
rescue => e
|
1311
|
-
print_debug "Could not capture: #{request.url}"
|
1312
|
-
print_debug request.body.to_s
|
1313
|
-
print_debug_exception e
|
1359
|
+
if from_preloads( request, response ) || from_cache( request, response )
|
1360
|
+
# There may be taints or custom JS code that need to be updated.
|
1361
|
+
javascript.inject response
|
1362
|
+
return
|
1314
1363
|
end
|
1315
1364
|
|
1365
|
+
# Capture the request as elements of pages -- let's us grab AJAX and
|
1366
|
+
# other browser requests and convert them into elements we can analyze
|
1367
|
+
# and audit.
|
1368
|
+
capture( request )
|
1369
|
+
|
1316
1370
|
request.headers['user-agent'] = Options.http.user_agent
|
1317
1371
|
|
1372
|
+
# The proxy has an unlimited response_max_size so if we're not requesting
|
1373
|
+
# an asset remove the response_max_size option so that it'll end up using
|
1374
|
+
# the system settings.
|
1375
|
+
#
|
1376
|
+
# However, this is not foolproof, a lot of assets don't have the expected
|
1377
|
+
# extension.
|
1378
|
+
if !request_for_asset?( request )
|
1379
|
+
request.response_max_size = nil
|
1380
|
+
end
|
1381
|
+
|
1318
1382
|
# Signal the proxy to continue with its request to the origin server.
|
1319
1383
|
true
|
1320
1384
|
end
|
@@ -1327,63 +1391,50 @@ class Browser
|
|
1327
1391
|
transition.complete
|
1328
1392
|
end
|
1329
1393
|
|
1394
|
+
javascript.inject response
|
1395
|
+
|
1396
|
+
# Don't store assets, the browsers will cache them accordingly.
|
1397
|
+
return if request_for_asset?( request ) || !response.text?
|
1398
|
+
|
1330
1399
|
# No-matter the scope, don't store resources for external domains.
|
1331
1400
|
return if !response.scope.in_domain?
|
1332
1401
|
|
1333
1402
|
return if enforce_scope? && response.scope.out?
|
1334
1403
|
|
1335
|
-
|
1404
|
+
whitelist_asset_domains( response )
|
1336
1405
|
save_response response
|
1337
1406
|
|
1338
1407
|
nil
|
1339
1408
|
end
|
1340
1409
|
|
1341
|
-
def
|
1342
|
-
return if !
|
1343
|
-
@javascript.inject( response )
|
1344
|
-
end
|
1410
|
+
def ignore_request?( request )
|
1411
|
+
return if !enforce_scope?
|
1345
1412
|
|
1346
|
-
|
1347
|
-
return false if response.body.empty?
|
1413
|
+
return false if request_for_asset?( request )
|
1348
1414
|
|
1349
|
-
|
1350
|
-
return false if !response.headers.content_type.to_s.downcase.start_with?( 'text/html' )
|
1415
|
+
return true if !request.scope.follow_protocol?
|
1351
1416
|
|
1352
|
-
|
1353
|
-
|
1354
|
-
body = response.body.downcase
|
1355
|
-
return false if !HTML_IDENTIFIERS.find { |tag| body.include? tag.downcase }
|
1417
|
+
return true if !request.scope.in_domain? &&
|
1418
|
+
!self.class.asset_domains.include?( request.parsed_url.domain )
|
1356
1419
|
|
1357
|
-
|
1358
|
-
|
1359
|
-
|
1360
|
-
|
1361
|
-
return true if @last_url == response.url
|
1420
|
+
return true if request.scope.too_deep?
|
1421
|
+
return true if !request.scope.include?
|
1422
|
+
return true if request.scope.exclude?
|
1423
|
+
return true if request.scope.redundant?
|
1362
1424
|
|
1363
|
-
|
1364
|
-
# and that the previous checks weren't just flukes matching some other
|
1365
|
-
# kind of document.
|
1366
|
-
#
|
1367
|
-
# For example, it may have been JSON with the wrong content-type that
|
1368
|
-
# includes HTML -- it happens.
|
1369
|
-
begin
|
1370
|
-
return false if Nokogiri::XML( response.body ).children.empty?
|
1371
|
-
rescue => e
|
1372
|
-
print_debug "Javascript injection failed for: #{response.url}"
|
1373
|
-
print_debug "\n#{response.body}"
|
1374
|
-
print_debug_exception e
|
1375
|
-
return false
|
1376
|
-
end
|
1377
|
-
|
1378
|
-
true
|
1425
|
+
false
|
1379
1426
|
end
|
1380
1427
|
|
1381
|
-
def
|
1382
|
-
|
1428
|
+
def request_for_asset?( request )
|
1429
|
+
ASSET_EXTENSIONS.include?( request.parsed_url.resource_extension.to_s.downcase )
|
1430
|
+
end
|
1383
1431
|
|
1384
|
-
|
1385
|
-
|
1386
|
-
|
1432
|
+
def whitelist_asset_domains( response )
|
1433
|
+
ASSET_EXTRACTORS.each do |regexp|
|
1434
|
+
response.body.scan( regexp ).flatten.compact.each do |url|
|
1435
|
+
self.class.add_asset_domain url
|
1436
|
+
end
|
1437
|
+
end
|
1387
1438
|
end
|
1388
1439
|
|
1389
1440
|
def capture( request )
|
@@ -1452,6 +1503,10 @@ class Browser
|
|
1452
1503
|
|
1453
1504
|
@captured_pages << page if store_pages?
|
1454
1505
|
notify_on_new_page( page )
|
1506
|
+
rescue => e
|
1507
|
+
print_debug "Could not capture: #{request.url}"
|
1508
|
+
print_debug request.body.to_s
|
1509
|
+
print_debug_exception e
|
1455
1510
|
end
|
1456
1511
|
|
1457
1512
|
def from_preloads( request, response )
|
@@ -1478,7 +1533,7 @@ class Browser
|
|
1478
1533
|
destination.send "#{m}=", source.send( m )
|
1479
1534
|
end
|
1480
1535
|
|
1481
|
-
|
1536
|
+
javascript.inject destination
|
1482
1537
|
nil
|
1483
1538
|
end
|
1484
1539
|
|