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