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
data/lib/arachni/issue.rb
CHANGED
|
@@ -15,7 +15,7 @@ require Options.paths.lib + 'issue/severity'
|
|
|
15
15
|
# @author Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com>
|
|
16
16
|
class Issue
|
|
17
17
|
|
|
18
|
-
# Attributes removed from a parent issue (i.e. an
|
|
18
|
+
# Attributes removed from a parent issue (i.e. an issue with variations)
|
|
19
19
|
# and solely populating variations.
|
|
20
20
|
VARIATION_ATTRIBUTES = Set.new([
|
|
21
21
|
:@page, :@referring_page, :@proof, :@signature, :@remarks, :@trusted
|
|
@@ -286,12 +286,23 @@ class Issue
|
|
|
286
286
|
end
|
|
287
287
|
end
|
|
288
288
|
|
|
289
|
-
[:name, :description, :remedy_guidance, :remedy_code, :proof
|
|
289
|
+
[:name, :description, :remedy_guidance, :remedy_code, :proof].each do |m|
|
|
290
290
|
define_method "#{m}=" do |s|
|
|
291
291
|
instance_variable_set( "@#{m}".to_sym, s ? s.to_s.freeze : nil )
|
|
292
292
|
end
|
|
293
293
|
end
|
|
294
294
|
|
|
295
|
+
def signature=( sig )
|
|
296
|
+
@signature = case sig
|
|
297
|
+
when Regexp
|
|
298
|
+
sig.source
|
|
299
|
+
when String, nil
|
|
300
|
+
sig
|
|
301
|
+
else
|
|
302
|
+
sig.to_s
|
|
303
|
+
end
|
|
304
|
+
end
|
|
305
|
+
|
|
295
306
|
# @return [Hash]
|
|
296
307
|
def to_h
|
|
297
308
|
h = {}
|
|
@@ -495,7 +506,10 @@ class Issue
|
|
|
495
506
|
data['variations'] = data['variations'].map(&:to_rpc_data)
|
|
496
507
|
end
|
|
497
508
|
|
|
498
|
-
|
|
509
|
+
if !variation?
|
|
510
|
+
data['digest'] = digest
|
|
511
|
+
end
|
|
512
|
+
|
|
499
513
|
data['severity'] = data['severity'].to_s
|
|
500
514
|
|
|
501
515
|
data
|
|
@@ -13,6 +13,11 @@ module Arachni::OptionGroups
|
|
|
13
13
|
# @author Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com>
|
|
14
14
|
class BrowserCluster < Arachni::OptionGroup
|
|
15
15
|
|
|
16
|
+
# @return [Hash<Regexp,String>]
|
|
17
|
+
# When the page URL matched the key `Regexp`, wait until the `String` CSS
|
|
18
|
+
# selector in the value matches an element.
|
|
19
|
+
attr_accessor :wait_for_elements
|
|
20
|
+
|
|
16
21
|
# @return [Integer]
|
|
17
22
|
# Amount of {BrowserCluster::Worker} to keep in the pool and put to work.
|
|
18
23
|
attr_accessor :pool_size
|
|
@@ -38,13 +43,41 @@ class BrowserCluster < Arachni::OptionGroup
|
|
|
38
43
|
attr_accessor :screen_height
|
|
39
44
|
|
|
40
45
|
set_defaults(
|
|
46
|
+
wait_for_elements: {},
|
|
41
47
|
pool_size: 6,
|
|
42
|
-
job_timeout:
|
|
48
|
+
job_timeout: 25,
|
|
43
49
|
worker_time_to_live: 100,
|
|
44
50
|
ignore_images: false,
|
|
45
51
|
screen_width: 1600,
|
|
46
52
|
screen_height: 1200
|
|
47
53
|
)
|
|
48
54
|
|
|
55
|
+
def css_to_wait_for( url )
|
|
56
|
+
wait_for_elements.map do |pattern, css|
|
|
57
|
+
next if !(url =~ pattern)
|
|
58
|
+
css
|
|
59
|
+
end.compact
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def wait_for_elements=( rules )
|
|
63
|
+
return @wait_for_elements = defaults[:wait_for_elements].dup if !rules
|
|
64
|
+
|
|
65
|
+
@wait_for_elements = rules.inject({}) do |h, (regexp, value)|
|
|
66
|
+
regexp = regexp.is_a?( Regexp ) ? regexp : Regexp.new( regexp.to_s )
|
|
67
|
+
h.merge!( regexp => value )
|
|
68
|
+
h
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def to_rpc_data
|
|
73
|
+
d = super
|
|
74
|
+
|
|
75
|
+
%w(wait_for_elements).each do |k|
|
|
76
|
+
d[k] = d[k].my_stringify
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
d
|
|
80
|
+
end
|
|
81
|
+
|
|
49
82
|
end
|
|
50
83
|
end
|
|
@@ -242,7 +242,7 @@ class HTTP < Arachni::OptionGroup
|
|
|
242
242
|
request_timeout: 10_000,
|
|
243
243
|
request_redirect_limit: 5,
|
|
244
244
|
request_concurrency: 20,
|
|
245
|
-
request_queue_size:
|
|
245
|
+
request_queue_size: 100,
|
|
246
246
|
request_headers: {},
|
|
247
247
|
response_max_size: 500_000,
|
|
248
248
|
cookies: {}
|
data/lib/arachni/page.rb
CHANGED
|
@@ -379,31 +379,44 @@ class Page
|
|
|
379
379
|
def has_script?
|
|
380
380
|
return @has_javascript if !@has_javascript.nil?
|
|
381
381
|
|
|
382
|
-
if !response.headers.content_type.to_s.start_with?( 'text/html' ) ||
|
|
383
|
-
!text? || !document
|
|
382
|
+
if !response.headers.content_type.to_s.start_with?( 'text/html' ) || !text?
|
|
384
383
|
return @has_javascript = false
|
|
385
384
|
end
|
|
386
385
|
|
|
386
|
+
dbody = body.downcase
|
|
387
|
+
|
|
387
388
|
# First check, quick and simple.
|
|
388
|
-
|
|
389
|
+
if dbody.include?( '<script' ) || dbody.include?( 'javascript:' )
|
|
390
|
+
return @has_javascript = true
|
|
391
|
+
end
|
|
389
392
|
|
|
390
393
|
# Check for event attributes, if there are any then there's JS to be
|
|
391
394
|
# executed.
|
|
392
395
|
Browser::Javascript.events.flatten.each do |event|
|
|
393
|
-
return @has_javascript = true if
|
|
396
|
+
return @has_javascript = true if dbody.include?( "#{event}=" )
|
|
394
397
|
end
|
|
395
398
|
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
399
|
+
@has_javascript = false
|
|
400
|
+
end
|
|
401
|
+
|
|
402
|
+
# @param [String, Symbol,Array<String, Symbol>] tags
|
|
403
|
+
# Element tag names.
|
|
404
|
+
#
|
|
405
|
+
# @return [Boolean]
|
|
406
|
+
# `true` if the page contains any of the given elements, `false` otherwise.
|
|
407
|
+
def has_elements?( *tags )
|
|
408
|
+
return if !text?
|
|
409
|
+
|
|
410
|
+
tags.flatten.each do |tag|
|
|
411
|
+
tag = tag.to_s
|
|
412
|
+
|
|
413
|
+
next if !(body =~ /<\s*#{tag}/i)
|
|
414
|
+
|
|
415
|
+
return false if !document
|
|
416
|
+
return true if document.css( tag ).any?
|
|
404
417
|
end
|
|
405
418
|
|
|
406
|
-
|
|
419
|
+
false
|
|
407
420
|
end
|
|
408
421
|
|
|
409
422
|
# @return [Boolean]
|
|
@@ -270,13 +270,13 @@ class Transition
|
|
|
270
270
|
|
|
271
271
|
when 'element'
|
|
272
272
|
if value.is_a? String
|
|
273
|
-
value.to_sym
|
|
273
|
+
data['event'].to_s == 'request' ? value : value.to_sym
|
|
274
274
|
else
|
|
275
275
|
Browser::ElementLocator.from_rpc_data( value )
|
|
276
276
|
end
|
|
277
277
|
|
|
278
278
|
when 'options'
|
|
279
|
-
value.my_symbolize_keys
|
|
279
|
+
value.my_symbolize_keys(false)
|
|
280
280
|
|
|
281
281
|
else
|
|
282
282
|
value
|
data/lib/arachni/parser.rb
CHANGED
|
@@ -31,14 +31,26 @@ class Parser
|
|
|
31
31
|
# @abstract
|
|
32
32
|
class Base
|
|
33
33
|
|
|
34
|
+
attr_reader :html
|
|
35
|
+
attr_reader :document
|
|
36
|
+
attr_reader :downcased_html
|
|
37
|
+
|
|
38
|
+
def initialize( options = {} )
|
|
39
|
+
@html = options[:html]
|
|
40
|
+
@downcased_html = @html.downcase
|
|
41
|
+
@document = options[:document]
|
|
42
|
+
end
|
|
43
|
+
|
|
34
44
|
# This method must be implemented by all checks and must return an
|
|
35
45
|
# array of paths as plain strings
|
|
36
46
|
#
|
|
37
|
-
# @param [Nokogiri] document Nokogiri document
|
|
38
|
-
#
|
|
39
47
|
# @return [Array<String>] paths
|
|
40
48
|
# @abstract
|
|
41
|
-
def run
|
|
49
|
+
def run
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def includes?( string_or_regexp )
|
|
53
|
+
!!@downcased_html[string_or_regexp]
|
|
42
54
|
end
|
|
43
55
|
|
|
44
56
|
end
|
|
@@ -125,9 +137,8 @@ class Parser
|
|
|
125
137
|
@document = Nokogiri::HTML( body ) if text? rescue nil
|
|
126
138
|
end
|
|
127
139
|
|
|
128
|
-
# @note It
|
|
129
|
-
#
|
|
130
|
-
# than sorry.
|
|
140
|
+
# @note It will include common request headers as well headers from the HTTP
|
|
141
|
+
# request.
|
|
131
142
|
#
|
|
132
143
|
# @return [Hash]
|
|
133
144
|
# List of valid auditable HTTP header fields.
|
|
@@ -141,14 +152,15 @@ class Parser
|
|
|
141
152
|
'User-Agent' => @options.http.user_agent || '',
|
|
142
153
|
'Referer' => @url,
|
|
143
154
|
'Pragma' => 'no-cache'
|
|
144
|
-
}.
|
|
155
|
+
}.merge( response.request.headers ).
|
|
156
|
+
map { |k, v| Header.new( url: @url, inputs: { k => v } ) }.freeze
|
|
145
157
|
end
|
|
146
158
|
|
|
147
159
|
# @return [Array<Element::Form>]
|
|
148
160
|
# Forms from {#document}.
|
|
149
161
|
def forms
|
|
150
162
|
return @forms.freeze if @forms
|
|
151
|
-
return [] if !text?
|
|
163
|
+
return [] if !text? || !(body =~ /<\s*form/i)
|
|
152
164
|
|
|
153
165
|
f = Form.from_document( @url, document )
|
|
154
166
|
return f if !@secondary_responses
|
|
@@ -199,7 +211,7 @@ class Parser
|
|
|
199
211
|
# Links in {#document}.
|
|
200
212
|
def links
|
|
201
213
|
return @links.freeze if @links
|
|
202
|
-
return @links = [link].compact if !text?
|
|
214
|
+
return @links = [link].compact if !text? || !(body =~ /\?.*=/)
|
|
203
215
|
|
|
204
216
|
@links = [link].compact | Link.from_document( @url, document )
|
|
205
217
|
end
|
|
@@ -227,7 +239,7 @@ class Parser
|
|
|
227
239
|
# @return [Hash]
|
|
228
240
|
# Parameters found in {#url}.
|
|
229
241
|
def link_vars
|
|
230
|
-
return {} if (
|
|
242
|
+
return {} if !(parsed = uri_parse( @url ))
|
|
231
243
|
|
|
232
244
|
@link_vars ||= parsed.rewrite.query_parameters.freeze
|
|
233
245
|
end
|
|
@@ -309,7 +321,12 @@ class Parser
|
|
|
309
321
|
def run_extractors
|
|
310
322
|
begin
|
|
311
323
|
self.class.extractors.available.map do |name|
|
|
312
|
-
exception_jail
|
|
324
|
+
exception_jail false do
|
|
325
|
+
self.class.extractors[name].new(
|
|
326
|
+
document: document,
|
|
327
|
+
html: body
|
|
328
|
+
).run
|
|
329
|
+
end
|
|
313
330
|
end.flatten.uniq.compact.
|
|
314
331
|
map { |path| to_absolute( path ) }.compact.uniq.
|
|
315
332
|
reject { |path| skip?( path ) }
|
|
@@ -89,12 +89,13 @@ class Manager
|
|
|
89
89
|
:nginx,
|
|
90
90
|
:tomcat,
|
|
91
91
|
:iis,
|
|
92
|
-
:jetty
|
|
92
|
+
:jetty,
|
|
93
|
+
:gunicorn
|
|
93
94
|
]
|
|
94
95
|
|
|
95
96
|
LANGUAGES = [
|
|
96
97
|
:php,
|
|
97
|
-
:
|
|
98
|
+
:java,
|
|
98
99
|
:python,
|
|
99
100
|
:ruby,
|
|
100
101
|
:asp,
|
|
@@ -104,7 +105,13 @@ class Manager
|
|
|
104
105
|
|
|
105
106
|
# WebApp frameworks.
|
|
106
107
|
FRAMEWORKS = [
|
|
107
|
-
:rack
|
|
108
|
+
:rack,
|
|
109
|
+
:rails,
|
|
110
|
+
:cakephp,
|
|
111
|
+
:django,
|
|
112
|
+
:aspx_mvc,
|
|
113
|
+
:jsf,
|
|
114
|
+
:cherrypy
|
|
108
115
|
]
|
|
109
116
|
|
|
110
117
|
PLATFORM_NAMES = {
|
|
@@ -143,10 +150,11 @@ class Manager
|
|
|
143
150
|
tomcat: 'TomCat',
|
|
144
151
|
iis: 'IIS',
|
|
145
152
|
jetty: 'Jetty',
|
|
153
|
+
gunicorn: 'Gunicorn',
|
|
146
154
|
|
|
147
155
|
# Programming languages
|
|
148
156
|
php: 'PHP',
|
|
149
|
-
|
|
157
|
+
java: 'Java',
|
|
150
158
|
python: 'Python',
|
|
151
159
|
ruby: 'Ruby',
|
|
152
160
|
asp: 'ASP',
|
|
@@ -154,7 +162,13 @@ class Manager
|
|
|
154
162
|
perl: 'Perl',
|
|
155
163
|
|
|
156
164
|
# Web frameworks
|
|
157
|
-
rack:
|
|
165
|
+
rack: 'Rack',
|
|
166
|
+
django: 'Django',
|
|
167
|
+
cakephp: 'CakePHP',
|
|
168
|
+
rails: 'Ruby on Rails',
|
|
169
|
+
aspx_mvc: 'ASP.NET MVC',
|
|
170
|
+
jsf: 'JavaServer Faces',
|
|
171
|
+
cherrypy: 'CherryPy'
|
|
158
172
|
}
|
|
159
173
|
|
|
160
174
|
# Amount of
|
|
@@ -194,7 +208,7 @@ class Manager
|
|
|
194
208
|
# Sets global platforms fingerprints
|
|
195
209
|
# @private
|
|
196
210
|
def self.set( platforms )
|
|
197
|
-
@platforms = Support::Cache::
|
|
211
|
+
@platforms = Support::Cache::LeastRecentlyPushed.new( PLATFORM_CACHE_SIZE )
|
|
198
212
|
platforms.each { |k, v| @platforms[k] = v }
|
|
199
213
|
@platforms
|
|
200
214
|
end
|
|
@@ -228,8 +242,8 @@ class Manager
|
|
|
228
242
|
# @return [Bool]
|
|
229
243
|
# `true` if the resource should be fingerprinted, `false` otherwise.
|
|
230
244
|
def self.fingerprint?( resource )
|
|
231
|
-
!(!Options.fingerprint? || !resource.text? ||
|
|
232
|
-
|
|
245
|
+
!(!Options.fingerprint? || resource.code != 200 || !resource.text? ||
|
|
246
|
+
include?( resource.url ) || resource.scope.out?)
|
|
233
247
|
end
|
|
234
248
|
|
|
235
249
|
# Runs all fingerprinters against the given `page`.
|
|
@@ -240,14 +254,40 @@ class Manager
|
|
|
240
254
|
# @return [Manager]
|
|
241
255
|
# Updated `self`.
|
|
242
256
|
def self.fingerprint( page )
|
|
243
|
-
|
|
257
|
+
synchronize do
|
|
258
|
+
return page if !fingerprint? page
|
|
244
259
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
260
|
+
fingerprinters.available.each do |name|
|
|
261
|
+
exception_jail( false ) do
|
|
262
|
+
fingerprinters[name].new( page ).run
|
|
263
|
+
end
|
|
248
264
|
end
|
|
265
|
+
|
|
266
|
+
# We do this to flag the resource as checked even if no platforms
|
|
267
|
+
# were identified. We don't want to keep checking a resource that
|
|
268
|
+
# yields nothing over and over.
|
|
269
|
+
update( page.url, [] )
|
|
249
270
|
end
|
|
250
|
-
|
|
271
|
+
|
|
272
|
+
# Fingerprinting will have resulted in element parsing, clear the element
|
|
273
|
+
# caches to keep RAM consumption down.
|
|
274
|
+
page.clear_cache
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
# @param [String, URI] uri
|
|
278
|
+
#
|
|
279
|
+
# @return [Manager]
|
|
280
|
+
# Platform for the given `uri`
|
|
281
|
+
def self.[]( uri )
|
|
282
|
+
# If fingerprinting is disabled there's no point in filling the cache
|
|
283
|
+
# with the same object over and over, create an identical one for all
|
|
284
|
+
# URLs and return that always.
|
|
285
|
+
if !Options.fingerprint?
|
|
286
|
+
return @default ||= new_from_options
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
return new_from_options if !(key = make_key( uri ))
|
|
290
|
+
synchronize { @platforms[key] ||= new_from_options }
|
|
251
291
|
end
|
|
252
292
|
|
|
253
293
|
# Sets platform manager for the given `uri`.
|
|
@@ -260,11 +300,16 @@ class Manager
|
|
|
260
300
|
# @raise [Error::Invalid]
|
|
261
301
|
# On {#invalid?} platforms.
|
|
262
302
|
def self.[]=( uri, platforms )
|
|
263
|
-
|
|
303
|
+
# For some reason we failed to make a key, try to salvage the situation.
|
|
304
|
+
if !(key = make_key( uri ))
|
|
305
|
+
return new_from_options( platforms )
|
|
306
|
+
end
|
|
264
307
|
|
|
265
308
|
synchronize do
|
|
266
309
|
@platforms[key] =
|
|
267
|
-
platforms.is_a?( self ) ?
|
|
310
|
+
platforms.is_a?( self ) ?
|
|
311
|
+
platforms :
|
|
312
|
+
new_from_options( platforms )
|
|
268
313
|
end
|
|
269
314
|
end
|
|
270
315
|
|
|
@@ -293,22 +338,6 @@ class Manager
|
|
|
293
338
|
end
|
|
294
339
|
end
|
|
295
340
|
|
|
296
|
-
# @param [String, URI] uri
|
|
297
|
-
#
|
|
298
|
-
# @return [Manager]
|
|
299
|
-
# Platform for the given `uri`
|
|
300
|
-
def self.[]( uri )
|
|
301
|
-
# If fingerprinting is disabled there's no point in filling the cache
|
|
302
|
-
# with the same object over and over, create an identical one for all
|
|
303
|
-
# URLs and return that always.
|
|
304
|
-
if !Options.fingerprint?
|
|
305
|
-
return @default ||= new( Options.platforms )
|
|
306
|
-
end
|
|
307
|
-
|
|
308
|
-
return new if !(key = make_key( uri ))
|
|
309
|
-
synchronize { @platforms[key] ||= new }
|
|
310
|
-
end
|
|
311
|
-
|
|
312
341
|
# @return [Boolean]
|
|
313
342
|
# `true` if there are no platforms fingerprints, `false` otherwise.
|
|
314
343
|
def self.empty?
|
|
@@ -326,6 +355,10 @@ class Manager
|
|
|
326
355
|
parsed.without_query
|
|
327
356
|
end
|
|
328
357
|
|
|
358
|
+
def self.new_from_options( platforms = [] )
|
|
359
|
+
new( platforms | Options.platforms )
|
|
360
|
+
end
|
|
361
|
+
|
|
329
362
|
# @param [Array<String, Symbol>] platforms
|
|
330
363
|
# Platforms with which to initialize the lists.
|
|
331
364
|
def initialize( platforms = [] )
|
|
@@ -335,7 +368,7 @@ class Manager
|
|
|
335
368
|
List.new( self.class.const_get( type.to_s.upcase.to_sym ) )
|
|
336
369
|
end
|
|
337
370
|
|
|
338
|
-
update
|
|
371
|
+
update platforms
|
|
339
372
|
end
|
|
340
373
|
|
|
341
374
|
# @!method os
|