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
|
@@ -161,16 +161,14 @@ class Dynamic404Handler
|
|
|
161
161
|
current_signature = (preliminary_signatures_for( url )[i] ||= {})
|
|
162
162
|
|
|
163
163
|
PRECISION.times do
|
|
164
|
-
|
|
165
|
-
# This is important, helps us reduce waiting callers.
|
|
166
|
-
high_priority: true,
|
|
167
|
-
performer: self
|
|
168
|
-
) do |c_res|
|
|
164
|
+
request( generator.call ) do |c_res|
|
|
169
165
|
next if corrupted
|
|
170
166
|
|
|
167
|
+
print_debug "#{__method__} [gathering]: #{c_res.request.url} #{c_res.url} #{c_res.code} #{block}"
|
|
168
|
+
|
|
171
169
|
# Well, bad luck, bail out to avoid FPs.
|
|
172
|
-
if c_res
|
|
173
|
-
print_debug "#{__method__} [corrupted]: #{url} #{block}"
|
|
170
|
+
if corrupted_response?( c_res )
|
|
171
|
+
print_debug "#{__method__} [corrupted]: #{url} #{c_res.code} #{block}"
|
|
174
172
|
corrupted = true
|
|
175
173
|
next clear_data_for( url )
|
|
176
174
|
end
|
|
@@ -217,15 +215,13 @@ class Dynamic404Handler
|
|
|
217
215
|
current_signature = (advanced_signatures_for( url )[i] ||= {})
|
|
218
216
|
|
|
219
217
|
PRECISION.times do
|
|
220
|
-
|
|
221
|
-
# This is important, helps us reduce waiting callers.
|
|
222
|
-
high_priority: true,
|
|
223
|
-
performer: self
|
|
224
|
-
) do |c_res|
|
|
218
|
+
request( generator.call ) do |c_res|
|
|
225
219
|
next if corrupted
|
|
226
220
|
|
|
221
|
+
print_debug "#{__method__} [gathering]: #{c_res.request.url} #{c_res.url} #{c_res.code} #{block}"
|
|
222
|
+
|
|
227
223
|
# Well, bad luck, bail out to avoid FPs.
|
|
228
|
-
if c_res
|
|
224
|
+
if corrupted_response?( c_res )
|
|
229
225
|
print_debug "#{__method__} [corrupted]: #{url} #{block}"
|
|
230
226
|
corrupted = true
|
|
231
227
|
next clear_data_for( url )
|
|
@@ -305,7 +301,20 @@ class Dynamic404Handler
|
|
|
305
301
|
def needs_advanced_analysis?( url )
|
|
306
302
|
uri = uri_parse( url )
|
|
307
303
|
resource_name = uri.resource_name.to_s.split('.').tap(&:pop).join('.')
|
|
308
|
-
!!(
|
|
304
|
+
!!(
|
|
305
|
+
!resource_name.empty? ||
|
|
306
|
+
uri.resource_extension ||
|
|
307
|
+
uri.resource_name.to_s.include?( '~' )
|
|
308
|
+
)
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
# If this is neither a regular 404 nor a 202 the server probably freaked out
|
|
312
|
+
# -- 500 errors under stress and the like.
|
|
313
|
+
#
|
|
314
|
+
# In that case we should bail out to avoid corrupted signatures which can
|
|
315
|
+
# lead to FPs.
|
|
316
|
+
def corrupted_response?( response )
|
|
317
|
+
response.code != 404 && response.code != 200
|
|
309
318
|
end
|
|
310
319
|
|
|
311
320
|
def url_for( url )
|
|
@@ -387,9 +396,32 @@ class Dynamic404Handler
|
|
|
387
396
|
probes << proc { up_to_path + random_string + '.' + resource_extension }
|
|
388
397
|
end
|
|
389
398
|
|
|
399
|
+
if uri.resource_name.include?( '~' )
|
|
400
|
+
probes << proc {
|
|
401
|
+
up_to_path.sub(
|
|
402
|
+
uri.resource_name,
|
|
403
|
+
resource_name.gsub( '~', '~~' )
|
|
404
|
+
)
|
|
405
|
+
}
|
|
406
|
+
end
|
|
407
|
+
|
|
390
408
|
probes
|
|
391
409
|
end
|
|
392
410
|
|
|
411
|
+
def request( url, &block )
|
|
412
|
+
Client.get( url,
|
|
413
|
+
# This is important, helps us reduce waiting callers.
|
|
414
|
+
high_priority: true,
|
|
415
|
+
|
|
416
|
+
# We're going to be checking for a lot of non-existent resources,
|
|
417
|
+
# don't bother fingerprinting them
|
|
418
|
+
fingerprint: false,
|
|
419
|
+
|
|
420
|
+
performer: self,
|
|
421
|
+
&block
|
|
422
|
+
)
|
|
423
|
+
end
|
|
424
|
+
|
|
393
425
|
def data_for( url )
|
|
394
426
|
@signatures[url_for( url )] ||= signature_prototype
|
|
395
427
|
end
|
data/lib/arachni/http/headers.rb
CHANGED
|
@@ -18,13 +18,28 @@ module HTTP
|
|
|
18
18
|
# @author Tasos Laskos <tasos.laskos@arachni-scanner.com>
|
|
19
19
|
class Headers < Hash
|
|
20
20
|
|
|
21
|
+
FORMATTED_NAMES_CACHE = Support::Cache::LeastRecentlyPushed.new( 100 )
|
|
22
|
+
|
|
23
|
+
CONTENT_TYPE = 'content-type'
|
|
24
|
+
SET_COOKIE = 'set-cookie'
|
|
25
|
+
LOCATION = 'location'
|
|
26
|
+
|
|
21
27
|
# @param [Headers, Hash] headers
|
|
22
28
|
def initialize( headers = {} )
|
|
23
29
|
merge!( headers || {} )
|
|
24
30
|
end
|
|
25
31
|
|
|
26
32
|
def merge!( headers )
|
|
27
|
-
headers.each
|
|
33
|
+
headers.each do |k, v|
|
|
34
|
+
# Handle headers with identical normalized names, like a mixture of
|
|
35
|
+
# Set-Cookie and SET-COOKIE.
|
|
36
|
+
if include? k
|
|
37
|
+
self[k] = [self[k]].flatten
|
|
38
|
+
self[k] << v
|
|
39
|
+
else
|
|
40
|
+
self[k] = v
|
|
41
|
+
end
|
|
42
|
+
end
|
|
28
43
|
end
|
|
29
44
|
|
|
30
45
|
# @note `field` will be capitalized appropriately before storing.
|
|
@@ -77,20 +92,20 @@ class Headers < Hash
|
|
|
77
92
|
# @return [String, nil]
|
|
78
93
|
# Value of the `Content-Type` field.
|
|
79
94
|
def content_type
|
|
80
|
-
self[
|
|
95
|
+
self[CONTENT_TYPE]
|
|
81
96
|
end
|
|
82
97
|
|
|
83
98
|
# @return [String, nil]
|
|
84
99
|
# Value of the `Location` field.
|
|
85
100
|
def location
|
|
86
|
-
self[
|
|
101
|
+
self[LOCATION]
|
|
87
102
|
end
|
|
88
103
|
|
|
89
104
|
# @return [Array<String>]
|
|
90
105
|
# Set-cookie strings.
|
|
91
106
|
def set_cookie
|
|
92
|
-
return [] if self[
|
|
93
|
-
[self[
|
|
107
|
+
return [] if self[SET_COOKIE].to_s.empty?
|
|
108
|
+
[self[SET_COOKIE]].flatten
|
|
94
109
|
end
|
|
95
110
|
|
|
96
111
|
# @return [Array<Hash>]
|
|
@@ -119,15 +134,12 @@ class Headers < Hash
|
|
|
119
134
|
end
|
|
120
135
|
|
|
121
136
|
def self.format_field_name( field )
|
|
122
|
-
# return field
|
|
123
|
-
|
|
124
137
|
# If there's a '--' somewhere in there then skip it, it probably is an
|
|
125
138
|
# audit payload.
|
|
126
139
|
return field if field.include?( '--' )
|
|
127
140
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
field.to_s.split( '-' ).map( &:capitalize ).join( '-' )
|
|
141
|
+
FORMATTED_NAMES_CACHE[field] ||=
|
|
142
|
+
field.split( '-' ).map( &:capitalize ).join( '-' )
|
|
131
143
|
end
|
|
132
144
|
|
|
133
145
|
end
|
|
@@ -21,11 +21,17 @@ module HTTP
|
|
|
21
21
|
# @author Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com>
|
|
22
22
|
class ProxyServer < WEBrick::HTTPProxyServer
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
CACHE = {
|
|
25
|
+
format_field_name: Support::Cache::LeastRecentlyPushed.new( 100 )
|
|
26
|
+
}
|
|
26
27
|
|
|
27
|
-
|
|
28
|
-
|
|
28
|
+
SKIP_HEADERS = Set.new( HopByHop | ['content-encoding'] )
|
|
29
|
+
|
|
30
|
+
INTERCEPTOR_CA_CERTIFICATE =
|
|
31
|
+
File.dirname( __FILE__ ) + '/proxy_server/ssl-interceptor-cacert.pem'
|
|
32
|
+
|
|
33
|
+
INTERCEPTOR_CA_KEY =
|
|
34
|
+
File.dirname( __FILE__ ) + '/proxy_server/ssl-interceptor-cakey.pem'
|
|
29
35
|
|
|
30
36
|
# @param [Hash] options
|
|
31
37
|
# @option options [String] :address ('0.0.0.0')
|
|
@@ -168,8 +174,12 @@ class ProxyServer < WEBrick::HTTPProxyServer
|
|
|
168
174
|
# @see #service
|
|
169
175
|
# @see Webrick::HTTPProxyServer#service
|
|
170
176
|
def do_CONNECT( req, res )
|
|
177
|
+
host = req.unparsed_uri.split(':').first
|
|
178
|
+
|
|
171
179
|
req.instance_variable_set( :@unparsed_uri, "127.0.0.1:#{interceptor_port}" )
|
|
172
|
-
|
|
180
|
+
|
|
181
|
+
start_ssl_interceptor( host )
|
|
182
|
+
|
|
173
183
|
super( req, res )
|
|
174
184
|
end
|
|
175
185
|
|
|
@@ -177,8 +187,10 @@ class ProxyServer < WEBrick::HTTPProxyServer
|
|
|
177
187
|
# Merges the given HTTP options with some default ones.
|
|
178
188
|
def http_opts( options = {} )
|
|
179
189
|
options.merge(
|
|
190
|
+
performer: self,
|
|
191
|
+
|
|
180
192
|
# Don't follow redirects, the client should handle this.
|
|
181
|
-
follow_location:
|
|
193
|
+
follow_location: false,
|
|
182
194
|
|
|
183
195
|
# Set the HTTP request timeout.
|
|
184
196
|
timeout: @options[:timeout],
|
|
@@ -198,18 +210,54 @@ class ProxyServer < WEBrick::HTTPProxyServer
|
|
|
198
210
|
# Starts the SSL interceptor proxy server.
|
|
199
211
|
#
|
|
200
212
|
# The interceptor will listen on {#interceptor_port}.
|
|
201
|
-
def start_ssl_interceptor
|
|
213
|
+
def start_ssl_interceptor( host )
|
|
202
214
|
return @interceptor if @interceptor
|
|
203
215
|
|
|
216
|
+
ca = OpenSSL::X509::Certificate.new( File.read( INTERCEPTOR_CA_CERTIFICATE ) )
|
|
217
|
+
ca_key = OpenSSL::PKey::RSA.new( File.read( INTERCEPTOR_CA_KEY ) )
|
|
218
|
+
|
|
219
|
+
keypair = OpenSSL::PKey::RSA.new( 4096 )
|
|
220
|
+
|
|
221
|
+
req = OpenSSL::X509::Request.new
|
|
222
|
+
req.version = 0
|
|
223
|
+
req.subject = OpenSSL::X509::Name.parse(
|
|
224
|
+
"CN=#{host}/subjectAltName=#{host}/O=Arachni/OU=Proxy/L=Athens/ST=Attika/C=GR"
|
|
225
|
+
)
|
|
226
|
+
req.public_key = keypair.public_key
|
|
227
|
+
req.sign( keypair, OpenSSL::Digest::SHA1.new )
|
|
228
|
+
|
|
229
|
+
cert = OpenSSL::X509::Certificate.new
|
|
230
|
+
cert.version = 2
|
|
231
|
+
cert.serial = rand( 999999 )
|
|
232
|
+
cert.not_before = Time.new
|
|
233
|
+
cert.not_after = cert.not_before + (60 * 60 * 24 * 365)
|
|
234
|
+
cert.public_key = req.public_key
|
|
235
|
+
cert.subject = req.subject
|
|
236
|
+
cert.issuer = ca.subject
|
|
237
|
+
|
|
238
|
+
ef = OpenSSL::X509::ExtensionFactory.new
|
|
239
|
+
ef.subject_certificate = cert
|
|
240
|
+
ef.issuer_certificate = ca
|
|
241
|
+
|
|
242
|
+
cert.extensions = [
|
|
243
|
+
ef.create_extension( 'basicConstraints', 'CA:FALSE', true ),
|
|
244
|
+
ef.create_extension( 'extendedKeyUsage', 'serverAuth', false ),
|
|
245
|
+
ef.create_extension( 'subjectKeyIdentifier', 'hash' ),
|
|
246
|
+
ef.create_extension( 'authorityKeyIdentifier', 'keyid:always,issuer:always' ),
|
|
247
|
+
ef.create_extension( 'keyUsage',
|
|
248
|
+
'nonRepudiation,digitalSignature,keyEncipherment,dataEncipherment',
|
|
249
|
+
true
|
|
250
|
+
)
|
|
251
|
+
]
|
|
252
|
+
cert.sign( ca_key, OpenSSL::Digest::SHA1.new )
|
|
253
|
+
|
|
204
254
|
# The interceptor is only used for SSL decryption/encryption, the actual
|
|
205
255
|
# proxy functionality is forwarded to the plain proxy server.
|
|
206
256
|
@interceptor = self.class.new(
|
|
207
257
|
address: '127.0.0.1',
|
|
208
258
|
port: interceptor_port,
|
|
209
|
-
ssl_certificate:
|
|
210
|
-
|
|
211
|
-
ssl_private_key:
|
|
212
|
-
OpenSSL::PKey::RSA.new( File.read( INTERCEPTOR_PRIVATE_KEY ) ),
|
|
259
|
+
ssl_certificate: cert,
|
|
260
|
+
ssl_private_key: keypair,
|
|
213
261
|
service_handler: method( :proxy_service )
|
|
214
262
|
)
|
|
215
263
|
|
|
@@ -283,24 +331,21 @@ class ProxyServer < WEBrick::HTTPProxyServer
|
|
|
283
331
|
# @param [#[]=] dst
|
|
284
332
|
# Headers of the forwarded/proxy response.
|
|
285
333
|
def choose_header( src, dst )
|
|
286
|
-
connections = split_field( [src['connection']].flatten.first )
|
|
334
|
+
connections = Set.new( split_field( [src['connection']].flatten.first ) )
|
|
287
335
|
|
|
288
336
|
src.each do |key, value|
|
|
289
337
|
key = key.downcase
|
|
338
|
+
next if SKIP_HEADERS.include?( key ) || connections.include?( key )
|
|
290
339
|
|
|
291
|
-
|
|
292
|
-
connections.member?( key ) || # RFC2616: 14.10
|
|
293
|
-
key == 'content-encoding'
|
|
294
|
-
@logger.debug( "choose_header: `#{key}: #{value}'" )
|
|
295
|
-
next
|
|
296
|
-
end
|
|
297
|
-
|
|
298
|
-
field = key.to_s.split( /_|-/ ).
|
|
299
|
-
map { |segment| segment.capitalize }.join( '-' )
|
|
300
|
-
dst[field] = value
|
|
340
|
+
dst[self.class.format_field_name( key )] = value
|
|
301
341
|
end
|
|
302
342
|
end
|
|
303
343
|
|
|
344
|
+
def self.format_field_name( field )
|
|
345
|
+
CACHE[:format_field_name][field] ||=
|
|
346
|
+
field.split( /_|-/ ).map( &:capitalize ).join( '-' )
|
|
347
|
+
end
|
|
348
|
+
|
|
304
349
|
end
|
|
305
350
|
end
|
|
306
351
|
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
|
2
|
+
MIIF6zCCA9OgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBjzELMAkGA1UEBhMCR1Ix
|
|
3
|
+
DzANBgNVBAgMBkF0dGlrYTEPMA0GA1UEBwwGQXRoZW5zMRAwDgYDVQQKDAdBcmFj
|
|
4
|
+
aG5pMQ4wDAYDVQQLDAVQcm94eTEQMA4GA1UEAwwHQXJhY2huaTEqMCgGCSqGSIb3
|
|
5
|
+
DQEJARYbYXJhY2huaUBhcmFjaG5pLXNjYW5uZXIuY29tMB4XDTE1MDYxNDAyMDgz
|
|
6
|
+
MVoXDTI1MDYxMTAyMDgzMVowgY8xCzAJBgNVBAYTAkdSMQ8wDQYDVQQIDAZBdHRp
|
|
7
|
+
a2ExDzANBgNVBAcMBkF0aGVuczEQMA4GA1UECgwHQXJhY2huaTEOMAwGA1UECwwF
|
|
8
|
+
UHJveHkxEDAOBgNVBAMMB0FyYWNobmkxKjAoBgkqhkiG9w0BCQEWG2FyYWNobmlA
|
|
9
|
+
YXJhY2huaS1zY2FubmVyLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC
|
|
10
|
+
ggIBAKfH1iQiuG8zYS514F8zZLp8//00gPIML7+wcJn4cw2iN+yEix6RuZEIzqva
|
|
11
|
+
TfC4H6lZTyUhsoGZCeYAzzH9BMri/9uHJF+4worPfVKYIsm3TnMOVYoIC1kP1/Gj
|
|
12
|
+
Y1ih8KI/3baw0pddtJJeQ5/GjDaxx4+ynY4ZxrNcFmbTYXSrPcd62V/D4+edVnLi
|
|
13
|
+
uQsUezWYx7gNFiAuPRtlgJVBwzRoPV+Fh7Es2/SfmNSfGBCCYOpj4Fh0GOv7pSV0
|
|
14
|
+
9TeF1W/XqDoq/eZ7RzLXoFK0Rz70/22MnFWAIdEUHZqwh3ktndNEK2QHq9FRGUx8
|
|
15
|
+
cUlXVAJgYv8tTErYVBltKIi2qgbnkh0Rb+rT2OkgmSL9lg0PwpXChMeSo6o6riC7
|
|
16
|
+
5a8PQi6OmIseY742QYmBXApXDHtSzaY8onHUvqgxFrFpP0Bmca3AoF6kWQfXfRwS
|
|
17
|
+
ClMLwfBBDVeb+Tt97MO1G4m2VEW6c7o9H1t4td55LGslUzfJrmFe99vjAtdRTVqG
|
|
18
|
+
t3qDjbYi5VpE9kIyKcPHZkSKelMQ4VO1qB14CdaK/3ufqHTk7Ro2hKgstKDqnTCF
|
|
19
|
+
R7Qb9yXFsb1QyNtW8898T5mQm0HWQxdkaxcodizVjY5inHgqNwPa7A469EYFm5in
|
|
20
|
+
dLSOQtdPOV4q+y5lfhA2MkE3pRdSZPpnTqCEkSVVoKfdVlftAgMBAAGjUDBOMB0G
|
|
21
|
+
A1UdDgQWBBRvmR7gGqIfTQB0GygwgI22Kyr1bDAfBgNVHSMEGDAWgBRvmR7gGqIf
|
|
22
|
+
TQB0GygwgI22Kyr1bDAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4ICAQAx
|
|
23
|
+
g+ZjxJZXW1dYkc9ItXwAZba7oQJapLPu1iWCFy5cU13gck2MwDqfaDApNdr+erHg
|
|
24
|
+
WN7N+smMO+x3+lZZptzTfc6g/hBthBBAnetj8CUehjnWCo3aBGgVLE/mIEyHyFym
|
|
25
|
+
JX6xgcNYpvEzHT2o3Kmu/dAHCqY/3P9NtGJMhf7fy/Zz72tGY+ZTlthFSGWOjIEV
|
|
26
|
+
KXTtYnRUKmIRBLMacZmrJKIZCp/qGVSnFh9yjxHTWPNXXngGMxF9ItsFbdakjefn
|
|
27
|
+
hi2sHqns6/YbMaD2wK42dRQH1wH66DCGbyDPQO2j8iGK1q4Ggps+mGNYNBzMSAO/
|
|
28
|
+
ybdGRLQNq8ag7RXr/tNp/jYHopS/Ga0+3bOnCKf6MXNOolknSZhsOo16BWKDRd+d
|
|
29
|
+
m9ZTlro9AQr9+jdychG41IQNHXySrC5F1jLtzpEE5CJZIXkEFNYRcO9HMByJ3qwG
|
|
30
|
+
759oYcMklwhU+NSC5qXpD2Z9KGf5rc0HmoO6OyD4T8hnQXkuAqoIN/NBg6YSNisN
|
|
31
|
+
H2C2gbl+taRLt0/RVCiacylo5pl3XSZuQxtGaQl55gRXQDPnlfB2CtIrV44gHZOJ
|
|
32
|
+
88s+Ld9h44aoT2rWbLld6dU5ElZXWEJOim+aYKJewxX7PwEHn4iCpvMLu+4jXH3j
|
|
33
|
+
OkDTHheVJkxyhTDQ43ebg3/qi4yFaQyAHk3bQItwCw==
|
|
34
|
+
-----END CERTIFICATE-----
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
-----BEGIN RSA PRIVATE KEY-----
|
|
2
|
+
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
|
|
51
|
+
-----END RSA PRIVATE KEY-----
|
data/lib/arachni/http/request.rb
CHANGED
|
@@ -101,9 +101,6 @@ class Request < Message
|
|
|
101
101
|
# Maximum HTTP response size to accept, in bytes.
|
|
102
102
|
attr_accessor :response_max_size
|
|
103
103
|
|
|
104
|
-
# @private
|
|
105
|
-
attr_accessor :root_redirect_id
|
|
106
|
-
|
|
107
104
|
# @param [Hash] options
|
|
108
105
|
# Request options.
|
|
109
106
|
# @option options [String] :url
|
|
@@ -129,6 +126,7 @@ class Request < Message
|
|
|
129
126
|
super( options )
|
|
130
127
|
|
|
131
128
|
@train = false if @train.nil?
|
|
129
|
+
@fingerprint = true if @fingerprint.nil?
|
|
132
130
|
@update_cookies = false if @update_cookies.nil?
|
|
133
131
|
@follow_location = false if @follow_location.nil?
|
|
134
132
|
@max_redirects = (Options.http.request_redirect_limit || REDIRECT_LIMIT)
|
|
@@ -265,6 +263,13 @@ class Request < Message
|
|
|
265
263
|
!!@follow_location
|
|
266
264
|
end
|
|
267
265
|
|
|
266
|
+
# @return [Bool]
|
|
267
|
+
# `true` if the {Response} should be {Platform::Manager.fingerprint fingerprinted}
|
|
268
|
+
# for platforms, `false` otherwise.
|
|
269
|
+
def fingerprint?
|
|
270
|
+
@fingerprint
|
|
271
|
+
end
|
|
272
|
+
|
|
268
273
|
# @return [Bool]
|
|
269
274
|
# `true` if the {Response} should be analyzed by the {Trainer}
|
|
270
275
|
# for new elements, `false` otherwise.
|
|
@@ -343,6 +348,10 @@ class Request < Message
|
|
|
343
348
|
|
|
344
349
|
accept_encoding: 'gzip, deflate',
|
|
345
350
|
nosignal: true,
|
|
351
|
+
|
|
352
|
+
# If Content-Length is missing this option will have no effect, so
|
|
353
|
+
# we'll also stream the body to make sure that we can at least abort
|
|
354
|
+
# the reading of the response body if it exceeds this limit.
|
|
346
355
|
maxfilesize: max_size,
|
|
347
356
|
|
|
348
357
|
# Don't keep the socket alive if this is a blocking request because
|
|
@@ -384,17 +393,25 @@ class Request < Message
|
|
|
384
393
|
end
|
|
385
394
|
end
|
|
386
395
|
|
|
387
|
-
curl
|
|
388
|
-
|
|
396
|
+
curl = parsed_url.query ? url.gsub( "?#{parsed_url.query}", '' ) : url
|
|
397
|
+
typhoeus_request = Typhoeus::Request.new( curl, options )
|
|
389
398
|
|
|
390
399
|
if @on_complete.any?
|
|
391
|
-
|
|
400
|
+
response_body_buffer = ''
|
|
401
|
+
set_body_reader( typhoeus_request, response_body_buffer )
|
|
402
|
+
|
|
403
|
+
typhoeus_request.on_complete do |typhoeus_response|
|
|
404
|
+
if typhoeus_request.options[:maxfilesize]
|
|
405
|
+
typhoeus_response.options[:response_body] =
|
|
406
|
+
response_body_buffer
|
|
407
|
+
end
|
|
408
|
+
|
|
392
409
|
fill_in_data_from_typhoeus_response typhoeus_response
|
|
393
410
|
handle_response Response.from_typhoeus( typhoeus_response )
|
|
394
411
|
end
|
|
395
412
|
end
|
|
396
413
|
|
|
397
|
-
|
|
414
|
+
typhoeus_request
|
|
398
415
|
end
|
|
399
416
|
|
|
400
417
|
def to_h
|
|
@@ -480,33 +497,69 @@ class Request < Message
|
|
|
480
497
|
h
|
|
481
498
|
end
|
|
482
499
|
end
|
|
500
|
+
|
|
501
|
+
def encode( string )
|
|
502
|
+
@easy ||= Ethon::Easy.new( url: 'www.example.com' )
|
|
503
|
+
@easy.escape string
|
|
504
|
+
end
|
|
483
505
|
end
|
|
484
506
|
|
|
485
507
|
def prepare_headers
|
|
486
|
-
headers['Cookie'] = effective_cookies.
|
|
487
|
-
map { |k, v| "#{Cookie.encode( k )}=#{Cookie.encode( v )}" }.
|
|
488
|
-
join( ';' )
|
|
489
|
-
headers.delete( 'Cookie' ) if headers['Cookie'].empty?
|
|
490
|
-
|
|
491
508
|
headers['User-Agent'] ||= Options.http.user_agent
|
|
492
509
|
headers['Accept'] ||= 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'
|
|
493
510
|
headers['From'] ||= Options.authorized_by if Options.authorized_by
|
|
494
511
|
|
|
495
512
|
headers.each { |k, v| headers[k] = Header.encode( v ) if v }
|
|
513
|
+
|
|
514
|
+
headers['Cookie'] = effective_cookies.
|
|
515
|
+
map { |k, v| "#{Cookie.encode( k )}=#{Cookie.encode( v )}" }.
|
|
516
|
+
join( ';' )
|
|
517
|
+
headers.delete( 'Cookie' ) if headers['Cookie'].empty?
|
|
518
|
+
|
|
519
|
+
headers
|
|
496
520
|
end
|
|
497
521
|
|
|
498
522
|
private
|
|
499
523
|
|
|
524
|
+
def client_run
|
|
525
|
+
typhoeus_request = to_typhoeus
|
|
526
|
+
|
|
527
|
+
response_body_buffer = ''
|
|
528
|
+
set_body_reader( typhoeus_request, response_body_buffer )
|
|
529
|
+
|
|
530
|
+
typhoeus_response = typhoeus_request.run
|
|
531
|
+
|
|
532
|
+
if typhoeus_request.options[:maxfilesize]
|
|
533
|
+
typhoeus_response.options[:response_body] = response_body_buffer
|
|
534
|
+
end
|
|
535
|
+
|
|
536
|
+
fill_in_data_from_typhoeus_response typhoeus_response
|
|
537
|
+
|
|
538
|
+
Response.from_typhoeus( typhoeus_response )
|
|
539
|
+
end
|
|
540
|
+
|
|
500
541
|
def fill_in_data_from_typhoeus_response( response )
|
|
501
|
-
|
|
502
|
-
|
|
542
|
+
# Only grab the last data.
|
|
543
|
+
# In case of CONNECT calls for HTTPS via proxy the first data will be
|
|
544
|
+
# the proxy-related stuff.
|
|
545
|
+
@headers_string = response.debug_info.header_out.last
|
|
546
|
+
@effective_body = response.debug_info.data_out.last
|
|
503
547
|
end
|
|
504
548
|
|
|
505
|
-
def
|
|
506
|
-
|
|
507
|
-
fill_in_data_from_typhoeus_response response
|
|
549
|
+
def set_body_reader( typhoeus_request, buffer )
|
|
550
|
+
return if !typhoeus_request.options[:maxfilesize]
|
|
508
551
|
|
|
509
|
-
|
|
552
|
+
aborted = nil
|
|
553
|
+
typhoeus_request.on_body do |chunk|
|
|
554
|
+
next aborted if aborted
|
|
555
|
+
|
|
556
|
+
if buffer.size >= typhoeus_request.options[:maxfilesize]
|
|
557
|
+
buffer.clear
|
|
558
|
+
next aborted = :abort
|
|
559
|
+
end
|
|
560
|
+
|
|
561
|
+
buffer << chunk
|
|
562
|
+
end
|
|
510
563
|
end
|
|
511
564
|
|
|
512
565
|
end
|