arachni 1.1 → 1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
|