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.
Files changed (287) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +159 -0
  3. data/LICENSE.md +126 -196
  4. data/README.md +32 -24
  5. data/arachni.gemspec +7 -7
  6. data/components/checks/active/code_injection_timing.rb +3 -3
  7. data/components/checks/active/csrf.rb +2 -2
  8. data/components/checks/active/file_inclusion.rb +6 -7
  9. data/components/checks/active/os_cmd_injection.rb +3 -3
  10. data/components/checks/active/path_traversal.rb +7 -7
  11. data/components/checks/active/response_splitting.rb +9 -4
  12. data/components/checks/active/session_fixation.rb +7 -3
  13. data/components/checks/active/source_code_disclosure.rb +5 -5
  14. data/components/checks/active/unvalidated_redirect.rb +12 -3
  15. data/components/checks/active/unvalidated_redirect_dom.rb +3 -3
  16. data/components/checks/active/xss.rb +23 -10
  17. data/components/checks/active/xss_dom_inputs.rb +113 -11
  18. data/components/checks/active/xxe.rb +3 -3
  19. data/components/checks/passive/backdoors.rb +6 -5
  20. data/components/checks/passive/backup_directories.rb +6 -6
  21. data/components/checks/passive/backup_files.rb +6 -6
  22. data/components/checks/passive/common_admin_interfaces.rb +58 -0
  23. data/components/checks/passive/common_admin_interfaces/admin-panels.txt +49 -0
  24. data/components/checks/passive/common_directories/directories.txt +0 -16
  25. data/components/checks/passive/common_files.rb +6 -5
  26. data/components/checks/passive/common_files/filenames.txt +0 -2
  27. data/components/checks/passive/directory_listing.rb +6 -6
  28. data/components/checks/passive/grep/cookie_set_for_parent_domain.rb +3 -3
  29. data/components/checks/passive/grep/hsts.rb +6 -3
  30. data/components/checks/passive/grep/http_only_cookies.rb +3 -3
  31. data/components/checks/passive/grep/insecure_cookies.rb +2 -2
  32. data/components/checks/passive/grep/insecure_cors_policy.rb +6 -4
  33. data/components/checks/passive/grep/x_frame_options.rb +6 -4
  34. data/components/checks/passive/htaccess_limit.rb +6 -2
  35. data/components/checks/passive/http_put.rb +8 -4
  36. data/components/checks/passive/interesting_responses.rb +3 -2
  37. data/components/checks/passive/localstart_asp.rb +6 -2
  38. data/components/checks/passive/origin_spoof_access_restriction_bypass.rb +5 -1
  39. data/components/checks/passive/xst.rb +6 -2
  40. data/components/fingerprinters/frameworks/aspx_mvc.rb +43 -0
  41. data/components/fingerprinters/frameworks/cakephp.rb +28 -0
  42. data/components/fingerprinters/frameworks/cherrypy.rb +31 -0
  43. data/components/fingerprinters/frameworks/django.rb +33 -0
  44. data/components/fingerprinters/frameworks/jsf.rb +30 -0
  45. data/components/fingerprinters/frameworks/rack.rb +5 -7
  46. data/components/fingerprinters/frameworks/rails.rb +43 -0
  47. data/components/fingerprinters/languages/aspx.rb +11 -11
  48. data/components/fingerprinters/languages/{jsp.rb → java.rb} +11 -7
  49. data/components/fingerprinters/languages/php.rb +6 -6
  50. data/components/fingerprinters/languages/python.rb +14 -6
  51. data/components/fingerprinters/languages/ruby.rb +3 -5
  52. data/components/fingerprinters/servers/apache.rb +5 -4
  53. data/components/fingerprinters/servers/gunicorn.rb +33 -0
  54. data/components/fingerprinters/servers/jetty.rb +1 -1
  55. data/components/fingerprinters/servers/tomcat.rb +11 -4
  56. data/components/path_extractors/anchors.rb +5 -12
  57. data/components/path_extractors/areas.rb +5 -13
  58. data/components/path_extractors/comments.rb +5 -3
  59. data/components/path_extractors/data_url.rb +21 -0
  60. data/components/path_extractors/forms.rb +5 -13
  61. data/components/path_extractors/frames.rb +6 -13
  62. data/components/path_extractors/generic.rb +3 -12
  63. data/components/path_extractors/links.rb +5 -13
  64. data/components/path_extractors/meta_refresh.rb +5 -13
  65. data/components/path_extractors/scripts.rb +8 -14
  66. data/components/plugins/autologin.rb +17 -5
  67. data/components/plugins/defaults/meta/remedies/discovery.rb +11 -29
  68. data/components/plugins/login_script.rb +40 -10
  69. data/components/plugins/metrics.rb +235 -0
  70. data/components/plugins/proxy.rb +21 -4
  71. data/components/plugins/proxy/panel/page_accordion.html.erb +34 -2
  72. data/components/plugins/restrict_to_dom_state.rb +70 -0
  73. data/components/plugins/vector_feed.rb +38 -9
  74. data/components/reporters/plugin_formatters/html/metrics.rb +290 -0
  75. data/components/reporters/plugin_formatters/stdout/metrics.rb +80 -0
  76. data/components/reporters/plugin_formatters/xml/metrics.rb +29 -0
  77. data/components/reporters/stdout.rb +4 -2
  78. data/components/reporters/xml.rb +4 -4
  79. data/components/reporters/xml/schema.xsd +95 -0
  80. data/lib/arachni.rb +2 -0
  81. data/lib/arachni/browser.rb +132 -77
  82. data/lib/arachni/browser/javascript.rb +173 -45
  83. data/lib/arachni/browser/javascript/scripts/dom_monitor.js +81 -6
  84. data/lib/arachni/browser/javascript/scripts/taint_tracer.js +31 -3
  85. data/lib/arachni/browser_cluster.rb +41 -15
  86. data/lib/arachni/browser_cluster/job.rb +4 -0
  87. data/lib/arachni/browser_cluster/jobs/resource_exploration.rb +0 -9
  88. data/lib/arachni/browser_cluster/worker.rb +8 -5
  89. data/lib/arachni/check/auditor.rb +20 -8
  90. data/lib/arachni/check/base.rb +38 -6
  91. data/lib/arachni/element/base.rb +18 -1
  92. data/lib/arachni/element/capabilities/analyzable/differential.rb +0 -1
  93. data/lib/arachni/element/capabilities/analyzable/taint.rb +40 -10
  94. data/lib/arachni/element/capabilities/analyzable/timeout.rb +27 -23
  95. data/lib/arachni/element/capabilities/auditable/dom.rb +22 -0
  96. data/lib/arachni/element/capabilities/inputtable.rb +6 -2
  97. data/lib/arachni/element/capabilities/submittable.rb +1 -1
  98. data/lib/arachni/element/cookie.rb +37 -23
  99. data/lib/arachni/element/cookie/capabilities/mutable.rb +6 -6
  100. data/lib/arachni/element/cookie/dom.rb +0 -8
  101. data/lib/arachni/element/form.rb +28 -14
  102. data/lib/arachni/element/form/capabilities/auditable.rb +2 -2
  103. data/lib/arachni/element/form/capabilities/mutable.rb +5 -5
  104. data/lib/arachni/element/form/dom.rb +0 -8
  105. data/lib/arachni/element/generic_dom.rb +1 -1
  106. data/lib/arachni/element/json.rb +2 -1
  107. data/lib/arachni/element/json/capabilities/inputtable.rb +6 -6
  108. data/lib/arachni/element/json/capabilities/mutable.rb +1 -1
  109. data/lib/arachni/element/link.rb +13 -16
  110. data/lib/arachni/element/link/dom.rb +1 -14
  111. data/lib/arachni/element/link_template.rb +3 -2
  112. data/lib/arachni/element/link_template/dom.rb +0 -16
  113. data/lib/arachni/element/server.rb +51 -9
  114. data/lib/arachni/element/xml.rb +1 -0
  115. data/lib/arachni/ethon/easy.rb +4 -1
  116. data/lib/arachni/framework/parts/audit.rb +26 -77
  117. data/lib/arachni/framework/parts/browser.rb +50 -55
  118. data/lib/arachni/framework/parts/check.rb +4 -3
  119. data/lib/arachni/framework/parts/data.rb +41 -6
  120. data/lib/arachni/framework/parts/state.rb +16 -7
  121. data/lib/arachni/http/client.rb +66 -38
  122. data/lib/arachni/http/client/dynamic_404_handler.rb +46 -14
  123. data/lib/arachni/http/headers.rb +22 -10
  124. data/lib/arachni/http/proxy_server.rb +67 -22
  125. data/lib/arachni/http/proxy_server/ssl-interceptor-cacert.pem +34 -0
  126. data/lib/arachni/http/proxy_server/ssl-interceptor-cakey.pem +51 -0
  127. data/lib/arachni/http/request.rb +71 -18
  128. data/lib/arachni/issue.rb +17 -3
  129. data/lib/arachni/option_groups/browser_cluster.rb +34 -1
  130. data/lib/arachni/option_groups/http.rb +1 -1
  131. data/lib/arachni/page.rb +26 -13
  132. data/lib/arachni/page/dom/transition.rb +2 -2
  133. data/lib/arachni/parser.rb +28 -11
  134. data/lib/arachni/platform/fingerprinter.rb +5 -0
  135. data/lib/arachni/platform/manager.rb +65 -32
  136. data/lib/arachni/plugin/base.rb +8 -0
  137. data/lib/arachni/processes/instances.rb +25 -11
  138. data/lib/arachni/reporter/manager.rb +2 -2
  139. data/lib/arachni/rpc/client/instance.rb +4 -0
  140. data/lib/arachni/rpc/server/framework/master.rb +3 -3
  141. data/lib/arachni/rpc/server/framework/multi_instance.rb +0 -8
  142. data/lib/arachni/rpc/server/instance.rb +2 -1
  143. data/lib/arachni/ruby/array.rb +5 -0
  144. data/lib/arachni/ruby/hash.rb +5 -0
  145. data/lib/arachni/ruby/string.rb +2 -3
  146. data/lib/arachni/session.rb +32 -6
  147. data/lib/arachni/state/framework.rb +6 -2
  148. data/lib/arachni/support/cache.rb +1 -0
  149. data/lib/arachni/support/cache/base.rb +12 -8
  150. data/lib/arachni/support/cache/least_recently_pushed.rb +29 -0
  151. data/lib/arachni/support/cache/least_recently_used.rb +5 -8
  152. data/lib/arachni/support/cache/preference.rb +1 -1
  153. data/lib/arachni/support/cache/random_replacement.rb +1 -25
  154. data/lib/arachni/support/database/queue.rb +21 -8
  155. data/lib/arachni/support/lookup/base.rb +7 -1
  156. data/lib/arachni/support/mixins/observable.rb +3 -1
  157. data/lib/arachni/support/profiler.rb +51 -10
  158. data/lib/arachni/support/signature.rb +11 -2
  159. data/lib/arachni/trainer.rb +8 -2
  160. data/lib/arachni/uri.rb +28 -25
  161. data/lib/arachni/uri/scope.rb +1 -1
  162. data/lib/arachni/utilities.rb +8 -0
  163. data/lib/arachni/watir/element.rb +1 -1
  164. data/lib/version +1 -1
  165. data/spec/arachni/browser/javascript/dom_monitor_spec.rb +388 -53
  166. data/spec/arachni/browser/javascript/taint_tracer_spec.rb +41 -0
  167. data/spec/arachni/browser/javascript_spec.rb +235 -61
  168. data/spec/arachni/browser_cluster/jobs/resource_exploration_spec.rb +0 -9
  169. data/spec/arachni/browser_cluster_spec.rb +58 -10
  170. data/spec/arachni/browser_spec.rb +170 -26
  171. data/spec/arachni/check/auditor_spec.rb +22 -3
  172. data/spec/arachni/check/base_spec.rb +84 -0
  173. data/spec/arachni/element/body_spec.rb +1 -1
  174. data/spec/arachni/element/capabilities/analyzable/taint_spec.rb +3 -3
  175. data/spec/arachni/element/capabilities/analyzable/timeout_spec.rb +1 -1
  176. data/spec/arachni/element/cookie/dom_spec.rb +0 -9
  177. data/spec/arachni/element/cookie_spec.rb +85 -0
  178. data/spec/arachni/element/form/dom_spec.rb +0 -9
  179. data/spec/arachni/element/form_spec.rb +46 -3
  180. data/spec/arachni/element/json_spec.rb +20 -0
  181. data/spec/arachni/element/link/dom_spec.rb +0 -9
  182. data/spec/arachni/element/link_spec.rb +40 -15
  183. data/spec/arachni/element/link_template/dom_spec.rb +0 -8
  184. data/spec/arachni/element/link_template_spec.rb +2 -6
  185. data/spec/arachni/element/server_spec.rb +94 -8
  186. data/spec/arachni/element/xml_spec.rb +20 -0
  187. data/spec/arachni/framework/parts/audit_spec.rb +12 -14
  188. data/spec/arachni/framework/parts/browser_spec.rb +0 -171
  189. data/spec/arachni/framework/parts/platform_spec.rb +14 -8
  190. data/spec/arachni/framework/parts/report_spec.rb +1 -1
  191. data/spec/arachni/framework/parts/state_spec.rb +0 -9
  192. data/spec/arachni/http/client/dynamic_404_handlers_spec.rb +19 -0
  193. data/spec/arachni/http/client_spec.rb +169 -42
  194. data/spec/arachni/http/headers_spec.rb +18 -0
  195. data/spec/arachni/http/request_spec.rb +23 -0
  196. data/spec/arachni/issue_spec.rb +17 -6
  197. data/spec/arachni/page_spec.rb +22 -2
  198. data/spec/arachni/parser_spec.rb +5 -0
  199. data/spec/arachni/platform/manager_spec.rb +57 -25
  200. data/spec/arachni/reporter/manager_spec.rb +26 -0
  201. data/spec/arachni/rpc/server/active_options_spec.rb +9 -4
  202. data/spec/arachni/state/framework_spec.rb +2 -8
  203. data/spec/arachni/support/cache/least_recently_pushed_spec.rb +90 -0
  204. data/spec/arachni/support/cache/least_recently_used_spec.rb +5 -13
  205. data/spec/arachni/support/database/queue_spec.rb +7 -0
  206. data/spec/arachni/support/mixins/observable_spec.rb +15 -1
  207. data/spec/arachni/trainer_spec.rb +2 -2
  208. data/spec/components/checks/active/code_injection_timing_spec.rb +1 -1
  209. data/spec/components/checks/active/file_inclusion_spec.rb +6 -6
  210. data/spec/components/checks/active/path_traversal_spec.rb +2 -2
  211. data/spec/components/checks/active/source_code_disclosure_spec.rb +2 -2
  212. data/spec/components/checks/active/unvalidated_redirect_spec.rb +6 -6
  213. data/spec/components/checks/active/xss_dom_inputs_spec.rb +3 -5
  214. data/spec/components/checks/active/xss_dom_script_context_spec.rb +1 -1
  215. data/spec/components/checks/active/xss_spec.rb +5 -5
  216. data/spec/components/checks/passive/common_admin_interfaces_spec.rb +15 -0
  217. data/spec/components/checks/passive/interesting_responses_spec.rb +14 -1
  218. data/spec/components/fingerprinters/frameworks/aspx_mvc_spec.rb +31 -0
  219. data/spec/components/fingerprinters/frameworks/cakephp_spec.rb +22 -0
  220. data/spec/components/fingerprinters/frameworks/cherrypy_spec.rb +28 -0
  221. data/spec/components/fingerprinters/frameworks/django_spec.rb +37 -0
  222. data/spec/components/fingerprinters/frameworks/jsf_spec.rb +27 -0
  223. data/spec/components/fingerprinters/frameworks/rack_spec.rb +11 -14
  224. data/spec/components/fingerprinters/frameworks/rails_spec.rb +53 -0
  225. data/spec/components/fingerprinters/languages/asp_spec.rb +7 -9
  226. data/spec/components/fingerprinters/languages/aspx_spec.rb +10 -24
  227. data/spec/components/fingerprinters/languages/java_spec.rb +88 -0
  228. data/spec/components/fingerprinters/languages/php_spec.rb +19 -12
  229. data/spec/components/fingerprinters/languages/python_spec.rb +22 -9
  230. data/spec/components/fingerprinters/languages/ruby.rb +6 -4
  231. data/spec/components/fingerprinters/os/bsd_spec.rb +6 -4
  232. data/spec/components/fingerprinters/os/linux_spec.rb +6 -4
  233. data/spec/components/fingerprinters/os/solaris_spec.rb +6 -4
  234. data/spec/components/fingerprinters/os/unix_spec.rb +6 -4
  235. data/spec/components/fingerprinters/os/windows_spec.rb +6 -4
  236. data/spec/components/fingerprinters/servers/apache_spec.rb +15 -4
  237. data/spec/components/fingerprinters/servers/gunicorn_spec.rb +28 -0
  238. data/spec/components/fingerprinters/servers/iis_spec.rb +6 -6
  239. data/spec/components/fingerprinters/servers/jetty_spec.rb +6 -6
  240. data/spec/components/fingerprinters/servers/nginx_spec.rb +6 -4
  241. data/spec/components/fingerprinters/servers/tomcat_spec.rb +15 -6
  242. data/spec/components/path_extractors/data_url_spec.rb +19 -0
  243. data/spec/components/plugins/autologin_spec.rb +23 -0
  244. data/spec/components/plugins/login_script_spec.rb +112 -24
  245. data/spec/components/plugins/restrict_to_dom_state_spec.rb +16 -0
  246. data/spec/components/plugins/vector_feed_spec.rb +39 -1
  247. data/spec/support/factories/page/dom.rb +9 -4
  248. data/spec/support/factories/page/dom/transition.rb +31 -9
  249. data/spec/support/factories/scan_report.rb +8 -6
  250. data/spec/support/fixtures/empty/placeholder +0 -0
  251. data/spec/support/fixtures/report.afr +0 -0
  252. data/spec/support/fixtures/reporters/manager_spec/error.rb +18 -0
  253. data/spec/support/servers/arachni/browser.rb +117 -11
  254. data/spec/support/servers/arachni/browser/javascript/dom_monitor.rb +148 -4
  255. data/spec/support/servers/arachni/check/auditor.rb +4 -0
  256. data/spec/support/servers/arachni/element/cookie/cookie_dom.rb +1 -1
  257. data/spec/support/servers/arachni/http/client.rb +5 -0
  258. data/spec/support/servers/arachni/http/client/dynamic_404_handler.rb +13 -0
  259. data/spec/support/servers/checks/active/code_injection_timing.rb +1 -1
  260. data/spec/support/servers/checks/active/file_inclusion.rb +2 -2
  261. data/spec/support/servers/checks/active/path_traversal.rb +2 -2
  262. data/spec/support/servers/checks/active/source_code_disclosure.rb +40 -33
  263. data/spec/support/servers/checks/active/trainer_check.rb +9 -10
  264. data/spec/support/servers/checks/active/unvalidated_redirect_dom.rb +7 -4
  265. data/spec/support/servers/checks/active/xss.rb +35 -0
  266. data/spec/support/servers/checks/active/xss_dom.rb +1 -1
  267. data/spec/support/servers/checks/active/xss_dom_inputs.rb +24 -0
  268. data/spec/support/servers/checks/active/xss_dom_script_context.rb +1 -1
  269. data/spec/support/servers/checks/passive/common_admin_interfaces.rb +6 -0
  270. data/spec/support/servers/plugins/autologin.rb +9 -0
  271. data/spec/support/servers/plugins/restrict_to_dom_state.rb +4 -0
  272. data/spec/support/shared/element/base.rb +42 -0
  273. data/spec/support/shared/element/capabilities/auditable.rb +4 -4
  274. data/spec/support/shared/element/capabilities/auditable/dom.rb +26 -0
  275. data/spec/support/shared/element/capabilities/inputtable.rb +16 -11
  276. data/spec/support/shared/element/capabilities/submitable.rb +7 -2
  277. data/spec/support/shared/fingerprinter.rb +8 -0
  278. data/spec/support/shared/path_extractor.rb +1 -1
  279. data/ui/cli/framework.rb +3 -3
  280. data/ui/cli/framework/option_parser.rb +9 -0
  281. data/ui/cli/output.rb +9 -0
  282. data/ui/cli/reporter.rb +5 -2
  283. data/ui/cli/utilities.rb +4 -2
  284. metadata +76 -17
  285. data/lib/arachni/http/proxy_server/ssl-interceptor-cert.pem +0 -34
  286. data/lib/arachni/http/proxy_server/ssl-interceptor-pkey.pem +0 -51
  287. data/spec/components/fingerprinters/languages/jsp_spec.rb +0 -56
@@ -47,7 +47,7 @@ describe Arachni::Element::Capabilities::Analyzable::Timeout do
47
47
  context 'when #timing_attack_remark_data is' do
48
48
  context 'not nil' do
49
49
  it 'duplicates it' do
50
- h = { stuff: 1 }
50
+ h = { stuff: [1] }
51
51
 
52
52
  subject.timing_attack_remark_data = h
53
53
 
@@ -62,15 +62,6 @@ describe Arachni::Element::Cookie::DOM do
62
62
  end
63
63
  end
64
64
 
65
- %w(encode decode).each do |m|
66
- describe "##{m}" do
67
- it "delegates to #{Arachni::Element::Cookie}.#{m}" do
68
- Arachni::Element::Cookie.stub(m) { |arg| "#{arg}1" }
69
- subject.send( m, 'blah' ).should == 'blah1'
70
- end
71
- end
72
- end
73
-
74
65
  describe '#type' do
75
66
  it 'returns :cookie_dom' do
76
67
  subject.type.should == :cookie_dom
@@ -2,6 +2,7 @@ require 'spec_helper'
2
2
 
3
3
  describe Arachni::Element::Cookie do
4
4
  it_should_behave_like 'element'
5
+ it_should_behave_like 'with_source'
5
6
  it_should_behave_like 'with_dom'
6
7
  it_should_behave_like 'auditable', single_input: true
7
8
 
@@ -452,6 +453,7 @@ describe Arachni::Element::Cookie do
452
453
  cookie.name.should == 'coo@ki e2'
453
454
  cookie.value.should == 'blah val2@'
454
455
  cookie.path.should == '/stuff'
456
+ cookie.source.should == sc3
455
457
  end
456
458
 
457
459
  context 'when there is no path' do
@@ -465,6 +467,44 @@ describe Arachni::Element::Cookie do
465
467
  cookie.path.should == '/'
466
468
  end
467
469
  end
470
+
471
+ context 'when its value is' do
472
+ let(:value) { 'a' * size }
473
+ let(:cookie) { "cookie=#{value}; Expires=Thu, 01 Jan 1970 00:00:01 GMT; Domain=.foo.com; HttpOnly" }
474
+
475
+ context "equal to #{described_class::MAX_SIZE}" do
476
+ let(:size) { described_class::MAX_SIZE }
477
+
478
+ it 'returns empty array' do
479
+ described_class.from_set_cookie(
480
+ 'http://test.com/stuff',
481
+ cookie
482
+ ).first.value.should be_empty
483
+ end
484
+ end
485
+
486
+ context "larger than #{described_class::MAX_SIZE}" do
487
+ let(:size) { described_class::MAX_SIZE + 1 }
488
+
489
+ it 'sets empty value' do
490
+ described_class.from_set_cookie(
491
+ 'http://test.com/stuff',
492
+ cookie
493
+ ).first.value.should be_empty
494
+ end
495
+ end
496
+
497
+ context "smaller than #{described_class::MAX_SIZE}" do
498
+ let(:size) { described_class::MAX_SIZE - 1 }
499
+
500
+ it 'leaves the values alone' do
501
+ described_class.from_set_cookie(
502
+ 'http://test.com/stuff',
503
+ cookie
504
+ ).first.value.should == value
505
+ end
506
+ end
507
+ end
468
508
  end
469
509
 
470
510
  describe '.from_string' do
@@ -485,6 +525,51 @@ describe Arachni::Element::Cookie do
485
525
  c.name.should == 'name2'
486
526
  c.value.should == 'value2'
487
527
  end
528
+
529
+ it 'can handle v1 values' do
530
+ described_class.from_string(
531
+ 'http://owner-url.com',
532
+ 'cookie="blah stuff"'
533
+ ).first.value.should == 'blah stuff'
534
+ end
535
+
536
+ context 'when its value is' do
537
+ let(:value) { 'a' * size }
538
+ let(:cookie) { "cookie=#{value}" }
539
+
540
+ context "equal to #{described_class::MAX_SIZE}" do
541
+ let(:size) { described_class::MAX_SIZE }
542
+
543
+ it 'sets empty value' do
544
+ described_class.from_string(
545
+ 'http://owner-url.com',
546
+ cookie
547
+ ).first.value.should be_empty
548
+ end
549
+ end
550
+
551
+ context "larger than #{described_class::MAX_SIZE}" do
552
+ let(:size) { described_class::MAX_SIZE + 1 }
553
+
554
+ it 'sets empty value' do
555
+ described_class.from_string(
556
+ 'http://owner-url.com',
557
+ cookie
558
+ ).first.value.should be_empty
559
+ end
560
+ end
561
+
562
+ context "smaller than #{described_class::MAX_SIZE}" do
563
+ let(:size) { described_class::MAX_SIZE - 1 }
564
+
565
+ it 'leaves the values alone' do
566
+ described_class.from_string(
567
+ 'http://owner-url.com',
568
+ cookie
569
+ ).first.value.should == value
570
+ end
571
+ end
572
+ end
488
573
  end
489
574
 
490
575
  end
@@ -43,15 +43,6 @@ describe Arachni::Element::Form::DOM do
43
43
  end
44
44
  end
45
45
 
46
- %w(encode decode).each do |m|
47
- describe "##{m}" do
48
- it "delegates to #{Arachni::Element::Form}.#{m}" do
49
- Arachni::Element::Form.stub(m) { |arg| "#{arg}1" }
50
- subject.send( m, 'blah' ).should == 'blah1'
51
- end
52
- end
53
- end
54
-
55
46
  describe '#parent' do
56
47
  it 'returns the parent element' do
57
48
  subject.parent.should be_kind_of Arachni::Element::Form
@@ -1076,12 +1076,55 @@ EOHTML
1076
1076
  }
1077
1077
  end
1078
1078
  end
1079
+
1080
+ context 'when its value is' do
1081
+ let(:form) { described_class.from_document( url, form_html ).first }
1082
+ let(:value) { 'a' * size }
1083
+ let(:form_html) do
1084
+ '<html>
1085
+ <body>
1086
+ <form method="post" action="/form" name="my_form">
1087
+ <input type="text" name="input_1" value="' + value + '">
1088
+ <input type="text" name="input_2" value="val_2">
1089
+ <input type="submit">
1090
+ </form>
1091
+ </body>
1092
+ </html>'
1093
+ end
1094
+
1095
+ context "equal to #{described_class::MAX_SIZE}" do
1096
+ let(:size) { described_class::MAX_SIZE }
1097
+
1098
+ it 'returns empty array' do
1099
+ form.inputs['input_1'].should be_empty
1100
+ form.inputs['input_2'].should == 'val_2'
1101
+ end
1102
+ end
1103
+
1104
+ context "larger than #{described_class::MAX_SIZE}" do
1105
+ let(:size) { described_class::MAX_SIZE + 1 }
1106
+
1107
+ it 'sets empty value' do
1108
+ form.inputs['input_1'].should be_empty
1109
+ form.inputs['input_2'].should == 'val_2'
1110
+ end
1111
+ end
1112
+
1113
+ context "smaller than #{described_class::MAX_SIZE}" do
1114
+ let(:size) { described_class::MAX_SIZE - 1 }
1115
+
1116
+ it 'leaves the values alone' do
1117
+ form.inputs['input_1'].should == value
1118
+ form.inputs['input_2'].should == 'val_2'
1119
+ end
1120
+ end
1121
+ end
1079
1122
  end
1080
1123
  end
1081
1124
 
1082
1125
  describe '.encode' do
1083
1126
  it 'form-encodes the passed string' do
1084
- described_class.encode( '% value\ +=&;' ).should == '%25+value%5C+%2B%3D%26%3B'
1127
+ described_class.encode( '% value\ +=&;' ).should == '%25%20value%5C%20%2B%3D%26%3B'
1085
1128
  end
1086
1129
  end
1087
1130
  describe '#encode' do
@@ -1093,12 +1136,12 @@ EOHTML
1093
1136
 
1094
1137
  describe '.decode' do
1095
1138
  it 'form-decodes the passed string' do
1096
- described_class.decode( '%25+value%5C+%2B%3D%26%3B' ).should == '% value\ +=&;'
1139
+ described_class.decode( '%25%20value%5C%20%2B%3D%26%3B' ).should == '% value\ +=&;'
1097
1140
  end
1098
1141
  end
1099
1142
  describe '#decode' do
1100
1143
  it 'form-decodes the passed string' do
1101
- v = '%25+value%5C+%2B%3D%26%3B'
1144
+ v = '%25%20value%5C%20%2B%3D%26%3B'
1102
1145
  subject.decode( v ).should == described_class.decode( v )
1103
1146
  end
1104
1147
  end
@@ -517,6 +517,26 @@ describe Arachni::Element::JSON do
517
517
  context 'when there are no inputs' do
518
518
  it 'returns nil'
519
519
  end
520
+
521
+ context 'when it is' do
522
+ context "equal to #{described_class::MAX_SIZE}" do
523
+ let(:size) { described_class::MAX_SIZE }
524
+
525
+ it 'returns nil'
526
+ end
527
+
528
+ context "larger than #{described_class::MAX_SIZE}" do
529
+ let(:size) { described_class::MAX_SIZE + 1 }
530
+
531
+ it 'returns nil'
532
+ end
533
+
534
+ context "smaller than #{described_class::MAX_SIZE}" do
535
+ let(:size) { described_class::MAX_SIZE - 1 }
536
+
537
+ it 'leaves parses it'
538
+ end
539
+ end
520
540
  end
521
541
 
522
542
  end
@@ -43,15 +43,6 @@ describe Arachni::Element::Link::DOM do
43
43
  end
44
44
  end
45
45
 
46
- %w(encode decode).each do |m|
47
- describe "##{m}" do
48
- it "delegates to #{Arachni::Element::Link}.#{m}" do
49
- Arachni::Element::Link.stub(m) { |arg| "#{arg}1" }
50
- subject.send( m, 'blah' ).should == 'blah1'
51
- end
52
- end
53
- end
54
-
55
46
  describe '#parent' do
56
47
  it 'returns the parent element' do
57
48
  subject.parent.should be_kind_of Arachni::Element::Link
@@ -254,26 +254,51 @@ describe Arachni::Element::Link do
254
254
  end
255
255
  end
256
256
  end
257
- end
258
257
 
259
- describe '.encode_query_params' do
260
- it "encodes '='" do
261
- v = 'stuff='
262
- described_class.encode_query_params( v ).should == 'stuff%3D'
263
- end
264
- end
265
- describe '#encode_query_params' do
266
- it "encodes '='" do
267
- v = 'stuff='
268
- subject.encode_query_params( v ).should ==
269
- described_class.encode_query_params( v )
258
+ context 'when its value is' do
259
+ let(:link) { described_class.from_document( url, link_html ).first }
260
+ let(:value) { 'a' * size }
261
+ let(:href) { "test?param=#{value}" }
262
+ let(:link_html) do
263
+ tpl = '<html>
264
+ <body>
265
+ <a href="%s"></a>
266
+ </body>
267
+ </html>'
268
+
269
+ tpl % href[0...size]
270
+ end
271
+
272
+ context "equal to #{described_class::MAX_SIZE}" do
273
+ let(:size) { described_class::MAX_SIZE }
274
+
275
+ it 'returns empty array' do
276
+ link.should be_nil
277
+ end
278
+ end
279
+
280
+ context "larger than #{described_class::MAX_SIZE}" do
281
+ let(:size) { described_class::MAX_SIZE + 1 }
282
+
283
+ it 'sets empty value' do
284
+ link.should be_nil
285
+ end
286
+ end
287
+
288
+ context "smaller than #{described_class::MAX_SIZE}" do
289
+ let(:size) { described_class::MAX_SIZE - 1 }
290
+
291
+ it 'leaves the values alone' do
292
+ link.inputs['param'].should_not be_empty
293
+ end
294
+ end
270
295
  end
271
296
  end
272
297
 
273
298
  describe '.encode' do
274
299
  it 'URL-encodes the passed string' do
275
300
  v = '% value\ +=&;'
276
- described_class.encode( v ).should == URI.encode( v )
301
+ described_class.encode( v ).should == '%25%20value%5C%20%2B%3D%26%3B'
277
302
  end
278
303
  end
279
304
  describe '#encode' do
@@ -285,13 +310,13 @@ describe Arachni::Element::Link do
285
310
 
286
311
  describe '.decode' do
287
312
  it 'URL-decodes the passed string' do
288
- v = '%25+value%5C+%2B%3D%26%3B'
313
+ v = '%25%20value%5C%20%2B%3D%26%3B'
289
314
  described_class.decode( v ).should == URI.decode( v )
290
315
  end
291
316
  end
292
317
  describe '#decode' do
293
318
  it 'URL-decodes the passed string' do
294
- v = '%25+value%5C+%2B%3D%26%3B'
319
+ v = '%25%20value%5C%20%2B%3D%26%3B'
295
320
  subject.decode( v ).should == described_class.decode( v )
296
321
  end
297
322
  end
@@ -60,14 +60,6 @@ describe Arachni::Element::LinkTemplate::DOM do
60
60
  end
61
61
  end
62
62
 
63
- %w(encode decode).each do |m|
64
- describe "##{m}" do
65
- it 'returns the string as is' do
66
- subject.send( m, 'blah' ).should == 'blah'
67
- end
68
- end
69
- end
70
-
71
63
  describe '#parent' do
72
64
  it 'returns the parent element' do
73
65
  subject.parent.should be_kind_of Arachni::Element::LinkTemplate
@@ -215,12 +215,8 @@ describe Arachni::Element::LinkTemplate do
215
215
  end
216
216
 
217
217
  describe '.encode' do
218
- it "double encodes ';'" do
219
- described_class.encode( 'test;' ).should == 'test%253B'
220
- end
221
-
222
- it "double encodes '/'" do
223
- described_class.encode( 'test/' ).should == 'test%2F'
218
+ it 'URL-encodes the passed string' do
219
+ described_class.encode( 'test/;' ).should == 'test%2F%3B'
224
220
  end
225
221
  end
226
222
 
@@ -75,16 +75,30 @@ describe Arachni::Element::Server do
75
75
  name: 'Auditor',
76
76
  shortname: 'auditor_test'
77
77
  }
78
+ logged_issue.variations.first.proof.should ==
79
+ logged_issue.variations.first.page.response.status_line
80
+
78
81
  logged_issue.name.should == @auditor.class.info[:issue][:name]
79
82
  logged_issue.trusted.should be_true
80
83
  end
81
84
 
82
- it "does not push the response to the #{Arachni::Trainer}" do
83
- file = @base_url + 'true'
84
- auditable.log_remote_file_if_exists( file )
85
+ context 'when one issue is logged' do
86
+ it "does not push the response to the #{Arachni::Trainer}" do
87
+ auditable.log_remote_file_if_exists( @base_url + 'true' )
85
88
 
86
- @framework.trainer.should_not receive(:push)
87
- @framework.http.run
89
+ @framework.trainer.should_not receive(:push)
90
+ @framework.http.run
91
+ end
92
+ end
93
+
94
+ context 'when multiple issues are logged' do
95
+ it "pushes the responses to the #{Arachni::Trainer}" do
96
+ auditable.log_remote_file_if_exists( @base_url + 'true' )
97
+ auditable.log_remote_file_if_exists( "#{url}/each_candidate_dom_element" )
98
+
99
+ @framework.trainer.should receive(:push).twice
100
+ @framework.http.run
101
+ end
88
102
  end
89
103
  end
90
104
 
@@ -94,12 +108,41 @@ describe Arachni::Element::Server do
94
108
  @framework.http.run
95
109
  Arachni::Data.issues.should be_empty
96
110
  end
111
+
112
+ it "does not push the responses to the #{Arachni::Trainer}" do
113
+ auditable.log_remote_file_if_exists( @base_url + 'false' )
114
+
115
+ @framework.trainer.should_not receive(:push)
116
+ @framework.http.run
117
+ end
97
118
  end
98
119
 
99
120
  context 'when issues are too similar' do
121
+ let(:check_url) { @base_url + 'true' }
122
+
123
+ it 'flags them as untrusted' do
124
+ 10.times { auditable.log_remote_file_if_exists( check_url ) }
125
+ @framework.http.run
126
+
127
+ issues.should be_any
128
+ issues.each do |issue|
129
+ issue.should be_untrusted
130
+ end
131
+ end
132
+
133
+ it 'assigns a remark' do
134
+ 10.times { auditable.log_remote_file_if_exists( check_url ) }
135
+ @framework.http.run
136
+
137
+ issues.should be_any
138
+
139
+ issues.each do |issue|
140
+ issue.remarks[:meta_analysis].should == [described_class::REMARK]
141
+ end
142
+ end
143
+
100
144
  it "does not push the responses to the #{Arachni::Trainer}" do
101
- file = @base_url + 'true'
102
- 10.times { auditable.log_remote_file_if_exists( file ) }
145
+ 10.times { auditable.log_remote_file_if_exists( url ) }
103
146
 
104
147
  @framework.trainer.should_not receive(:push)
105
148
  @framework.http.run
@@ -125,11 +168,33 @@ describe Arachni::Element::Server do
125
168
  end
126
169
 
127
170
  context 'without a custom 404 handler' do
171
+ it 'performs fingerprinting' do
172
+ url = @base_url + 'true'
173
+
174
+ # We run this twice because the cache is empty the first time
175
+ # around so we don't know what kind of handler we're dealing with.
176
+
177
+ auditable.remote_file_exist?( url ) {}
178
+ @framework.http.run
179
+
180
+ request = nil
181
+ @framework.http.on_complete do |response|
182
+ next if url != response.url
183
+ request = response.request
184
+ end
185
+
186
+ auditable.remote_file_exist?( url ) {}
187
+ @framework.http.run
188
+
189
+ request.fingerprint?.should be_true
190
+ end
191
+
128
192
  context 'when a remote file exists' do
129
193
  it 'yields true' do
130
194
  exists = false
131
195
  auditable.remote_file_exist?( @base_url + 'true' ) { |bool| exists = bool }
132
196
  @framework.http.run
197
+ exists.should be_true
133
198
  end
134
199
 
135
200
  context 'on subsequent calls' do
@@ -165,9 +230,30 @@ describe Arachni::Element::Server do
165
230
  end
166
231
  end
167
232
 
168
- context 'without a custom 404 handler' do
233
+ context 'with a custom 404 handler' do
169
234
  before { @_404_url = @base_url + 'custom_404/' }
170
235
 
236
+ it 'does not perform fingerprinting' do
237
+ url = @_404_url + 'true'
238
+
239
+ # We run this twice because the cache is empty the first time
240
+ # around so we don't know what kind of handler we're dealing with.
241
+
242
+ auditable.remote_file_exist?( url ) {}
243
+ @framework.http.run
244
+
245
+ request = nil
246
+ @framework.http.on_complete do |response|
247
+ next if url != response.url
248
+ request = response.request
249
+ end
250
+
251
+ auditable.remote_file_exist?( url ) {}
252
+ @framework.http.run
253
+
254
+ request.fingerprint?.should be_false
255
+ end
256
+
171
257
  context 'and the response' do
172
258
  context 'is static' do
173
259
  it 'yields false' do