arachni 1.2.1 → 1.3

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 (373) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +66 -0
  3. data/Gemfile +1 -1
  4. data/README.md +16 -5
  5. data/components/checks/active/ldap_injection/errors.txt +1 -0
  6. data/components/checks/active/source_code_disclosure.rb +1 -1
  7. data/components/checks/active/unvalidated_redirect.rb +6 -6
  8. data/components/checks/active/unvalidated_redirect_dom.rb +10 -7
  9. data/components/checks/passive/grep/captcha.rb +14 -5
  10. data/components/checks/passive/grep/form_upload.rb +7 -3
  11. data/components/checks/passive/grep/hsts.rb +3 -3
  12. data/components/checks/passive/grep/html_objects.rb +2 -3
  13. data/components/checks/passive/grep/http_only_cookies.rb +2 -3
  14. data/components/checks/passive/grep/insecure_cookies.rb +1 -1
  15. data/components/checks/passive/grep/password_autocomplete.rb +2 -2
  16. data/components/checks/passive/grep/unencrypted_password_forms.rb +7 -7
  17. data/components/checks/passive/grep/x_frame_options.rb +2 -2
  18. data/components/checks/passive/http_put.rb +2 -3
  19. data/components/path_extractors/comments.rb +3 -3
  20. data/components/path_extractors/scripts.rb +10 -1
  21. data/components/plugins/defaults/autothrottle.rb +27 -18
  22. data/components/plugins/defaults/meta/remedies/discovery.rb +30 -33
  23. data/components/plugins/defaults/meta/remedies/timing_attacks.rb +7 -11
  24. data/components/plugins/login_script.rb +9 -3
  25. data/components/plugins/proxy.rb +4 -3
  26. data/components/reporters/html.rb +11 -14
  27. data/components/reporters/html/default/issue.erb +13 -38
  28. data/components/reporters/html/default/issue/info.erb +1 -1
  29. data/components/reporters/html/default/summary/issues/by_name.erb +3 -3
  30. data/components/reporters/stdout.rb +62 -71
  31. data/components/reporters/xml.rb +26 -40
  32. data/components/reporters/xml/schema.xsd +43 -89
  33. data/lib/arachni/browser.rb +52 -3
  34. data/lib/arachni/browser/javascript.rb +3 -3
  35. data/lib/arachni/browser/javascript/scripts/taint_tracer.js +46 -25
  36. data/lib/arachni/browser_cluster.rb +61 -0
  37. data/lib/arachni/browser_cluster/job.rb +21 -1
  38. data/lib/arachni/browser_cluster/jobs/browser_provider.rb +3 -1
  39. data/lib/arachni/browser_cluster/jobs/resource_exploration.rb +2 -1
  40. data/lib/arachni/browser_cluster/jobs/resource_exploration/event_trigger.rb +2 -1
  41. data/lib/arachni/browser_cluster/jobs/taint_trace.rb +3 -2
  42. data/lib/arachni/browser_cluster/jobs/taint_trace/event_trigger.rb +1 -1
  43. data/lib/arachni/browser_cluster/worker.rb +5 -0
  44. data/lib/arachni/check/auditor.rb +22 -12
  45. data/lib/arachni/data/framework.rb +13 -1
  46. data/lib/arachni/data/issues.rb +9 -25
  47. data/lib/arachni/element/base.rb +9 -3
  48. data/lib/arachni/element/capabilities/analyzable.rb +2 -6
  49. data/lib/arachni/element/capabilities/analyzable/differential.rb +24 -7
  50. data/lib/arachni/element/capabilities/analyzable/{taint.rb → signature.rb} +23 -23
  51. data/lib/arachni/element/capabilities/auditable.rb +0 -6
  52. data/lib/arachni/element/capabilities/dom_only.rb +61 -0
  53. data/lib/arachni/element/capabilities/with_dom.rb +3 -1
  54. data/lib/arachni/element/cookie.rb +35 -5
  55. data/lib/arachni/element/cookie/dom.rb +13 -4
  56. data/lib/arachni/element/{capabilities/auditable/dom.rb → dom.rb} +20 -68
  57. data/lib/arachni/element/dom/capabilities/auditable.rb +29 -0
  58. data/lib/arachni/element/dom/capabilities/inputtable.rb +27 -0
  59. data/lib/arachni/element/dom/capabilities/mutable.rb +21 -0
  60. data/lib/arachni/element/dom/capabilities/submittable.rb +52 -0
  61. data/lib/arachni/element/form.rb +12 -1
  62. data/lib/arachni/element/form/capabilities/mutable.rb +2 -1
  63. data/lib/arachni/element/form/capabilities/with_dom.rb +0 -1
  64. data/lib/arachni/element/form/dom.rb +9 -3
  65. data/lib/arachni/element/header.rb +14 -33
  66. data/lib/arachni/element/header/capabilities/inputtable.rb +29 -0
  67. data/lib/arachni/element/header/capabilities/mutable.rb +51 -0
  68. data/lib/arachni/element/input/dom.rb +71 -0
  69. data/lib/arachni/element/json.rb +2 -0
  70. data/lib/arachni/element/link.rb +3 -0
  71. data/lib/arachni/element/link/capabilities/with_dom.rb +0 -1
  72. data/lib/arachni/element/link/dom.rb +16 -3
  73. data/lib/arachni/element/link/dom/capabilities/submittable.rb +29 -0
  74. data/lib/arachni/element/link_template.rb +3 -5
  75. data/lib/arachni/element/link_template/capabilities/inputtable.rb +5 -0
  76. data/lib/arachni/element/link_template/capabilities/with_dom.rb +0 -1
  77. data/lib/arachni/element/link_template/dom.rb +16 -3
  78. data/lib/arachni/element/link_template/dom/capabilities/submittable.rb +29 -0
  79. data/lib/arachni/element/server.rb +3 -5
  80. data/lib/arachni/element/ui_form.rb +106 -0
  81. data/lib/arachni/element/ui_form/dom.rb +107 -0
  82. data/lib/arachni/element/ui_input.rb +62 -0
  83. data/lib/arachni/element/xml.rb +2 -1
  84. data/lib/arachni/framework.rb +7 -5
  85. data/lib/arachni/framework/parts/audit.rb +0 -1
  86. data/lib/arachni/framework/parts/check.rb +1 -0
  87. data/lib/arachni/framework/parts/data.rb +4 -0
  88. data/lib/arachni/framework/parts/state.rb +0 -2
  89. data/lib/arachni/http/client.rb +17 -6
  90. data/lib/arachni/http/proxy_server.rb +52 -5
  91. data/lib/arachni/http/request.rb +1 -1
  92. data/lib/arachni/issue.rb +34 -179
  93. data/lib/arachni/issue/severity.rb +2 -0
  94. data/lib/arachni/option_groups/audit.rb +22 -2
  95. data/lib/arachni/option_groups/browser_cluster.rb +15 -0
  96. data/lib/arachni/page.rb +3 -2
  97. data/lib/arachni/parser.rb +24 -5
  98. data/lib/arachni/platform/manager.rb +1 -2
  99. data/lib/arachni/rpc/server/framework.rb +3 -4
  100. data/lib/arachni/rpc/server/framework/multi_instance.rb +2 -1
  101. data/lib/arachni/session.rb +1 -1
  102. data/lib/arachni/trainer.rb +4 -7
  103. data/lib/arachni/watir/element.rb +12 -1
  104. data/lib/version +1 -1
  105. data/spec/arachni/browser/element_locator_spec.rb +43 -43
  106. data/spec/arachni/browser/javascript/dom_monitor_spec.rb +44 -44
  107. data/spec/arachni/browser/javascript/proxy/stub_spec.rb +17 -14
  108. data/spec/arachni/browser/javascript/proxy_spec.rb +24 -24
  109. data/spec/arachni/browser/javascript/taint_tracer/frame/called_function_spec.rb +11 -11
  110. data/spec/arachni/browser/javascript/taint_tracer/frame_spec.rb +7 -7
  111. data/spec/arachni/browser/javascript/taint_tracer/sink/data_flow_spec.rb +13 -13
  112. data/spec/arachni/browser/javascript/taint_tracer/sink/execution_flow_spec.rb +7 -7
  113. data/spec/arachni/browser/javascript/taint_tracer_spec.rb +568 -558
  114. data/spec/arachni/browser/javascript_spec.rb +73 -63
  115. data/spec/arachni/browser_cluster/job/result_spec.rb +3 -3
  116. data/spec/arachni/browser_cluster/job_spec.rb +68 -48
  117. data/spec/arachni/browser_cluster/jobs/resource_exploration/event_trigger/result_spec.rb +2 -2
  118. data/spec/arachni/browser_cluster/jobs/resource_exploration/event_trigger_spec.rb +5 -4
  119. data/spec/arachni/browser_cluster/jobs/resource_exploration/result_spec.rb +2 -2
  120. data/spec/arachni/browser_cluster/jobs/resource_exploration_spec.rb +5 -5
  121. data/spec/arachni/browser_cluster/worker_spec.rb +87 -70
  122. data/spec/arachni/browser_cluster_spec.rb +64 -39
  123. data/spec/arachni/browser_spec.rb +692 -527
  124. data/spec/arachni/check/auditor_spec.rb +177 -147
  125. data/spec/arachni/check/base_spec.rb +33 -33
  126. data/spec/arachni/check/manager_spec.rb +15 -15
  127. data/spec/arachni/component/base_spec.rb +8 -8
  128. data/spec/arachni/component/manager_spec.rb +100 -99
  129. data/spec/arachni/component/options/address_spec.rb +3 -3
  130. data/spec/arachni/component/options/base_spec.rb +7 -7
  131. data/spec/arachni/component/options/bool_spec.rb +9 -9
  132. data/spec/arachni/component/options/float_spec.rb +6 -6
  133. data/spec/arachni/component/options/int_spec.rb +5 -5
  134. data/spec/arachni/component/options/multiple_choice_spec.rb +12 -12
  135. data/spec/arachni/component/options/object_spec.rb +2 -2
  136. data/spec/arachni/component/options/path_spec.rb +3 -3
  137. data/spec/arachni/component/options/port_spec.rb +5 -5
  138. data/spec/arachni/component/options/string_spec.rb +3 -3
  139. data/spec/arachni/component/options/url_spec.rb +4 -4
  140. data/spec/arachni/component/utilities_spec.rb +2 -2
  141. data/spec/arachni/data/framework/rpc_spec.rb +10 -9
  142. data/spec/arachni/data/framework_spec.rb +65 -46
  143. data/spec/arachni/data/issues_spec.rb +39 -77
  144. data/spec/arachni/data/plugins_spec.rb +11 -11
  145. data/spec/arachni/data/session_spec.rb +6 -6
  146. data/spec/arachni/data_spec.rb +8 -8
  147. data/spec/arachni/element/body_spec.rb +10 -10
  148. data/spec/arachni/element/capabilities/analyzable/differential_spec.rb +39 -21
  149. data/spec/arachni/element/capabilities/analyzable/{taint_spec.rb → signature_spec.rb} +63 -63
  150. data/spec/arachni/element/capabilities/analyzable/timeout_spec.rb +51 -51
  151. data/spec/arachni/element/capabilities/with_scope/scope_spec.rb +5 -5
  152. data/spec/arachni/element/cookie/dom_spec.rb +37 -18
  153. data/spec/arachni/element/cookie_spec.rb +206 -139
  154. data/spec/arachni/element/form/dom_spec.rb +36 -19
  155. data/spec/arachni/element/form_spec.rb +210 -187
  156. data/spec/arachni/element/generic_dom_spec.rb +14 -14
  157. data/spec/arachni/element/header_spec.rb +35 -17
  158. data/spec/arachni/element/json_spec.rb +53 -31
  159. data/spec/arachni/element/link/dom_spec.rb +46 -28
  160. data/spec/arachni/element/link_spec.rb +58 -40
  161. data/spec/arachni/element/link_template/dom_spec.rb +47 -29
  162. data/spec/arachni/element/link_template_spec.rb +79 -61
  163. data/spec/arachni/element/path_spec.rb +1 -1
  164. data/spec/arachni/element/server_spec.rb +33 -32
  165. data/spec/arachni/element/ui_form/ui_form_dom_spec.rb +164 -0
  166. data/spec/arachni/element/ui_form_spec.rb +242 -0
  167. data/spec/arachni/element/ui_input/dom_spec.rb +157 -0
  168. data/spec/arachni/element/ui_input_spec.rb +136 -0
  169. data/spec/arachni/element/xml_spec.rb +42 -24
  170. data/spec/arachni/element_filter_spec.rb +49 -48
  171. data/spec/arachni/error_spec.rb +3 -3
  172. data/spec/arachni/framework/parts/audit_spec.rb +64 -63
  173. data/spec/arachni/framework/parts/browser_spec.rb +16 -16
  174. data/spec/arachni/framework/parts/check_spec.rb +3 -3
  175. data/spec/arachni/framework/parts/data_spec.rb +48 -48
  176. data/spec/arachni/framework/parts/platform_spec.rb +3 -3
  177. data/spec/arachni/framework/parts/plugin_spec.rb +7 -6
  178. data/spec/arachni/framework/parts/report_spec.rb +7 -7
  179. data/spec/arachni/framework/parts/scope_spec.rb +16 -16
  180. data/spec/arachni/framework/parts/state_spec.rb +68 -69
  181. data/spec/arachni/framework_spec.rb +39 -31
  182. data/spec/arachni/http/client/dynamic_404_handlers_spec.rb +32 -32
  183. data/spec/arachni/http/client_spec.rb +219 -208
  184. data/spec/arachni/http/cookie_jar_spec.rb +72 -72
  185. data/spec/arachni/http/headers_spec.rb +14 -14
  186. data/spec/arachni/http/proxy_server_spec.rb +43 -42
  187. data/spec/arachni/http/request_spec.rb +105 -103
  188. data/spec/arachni/http/response/scope_spec.rb +24 -24
  189. data/spec/arachni/http/response_spec.rb +50 -49
  190. data/spec/arachni/issue/severity_spec.rb +10 -9
  191. data/spec/arachni/issue_spec.rb +71 -369
  192. data/spec/arachni/option_groups/audit_spec.rb +114 -114
  193. data/spec/arachni/option_groups/browser_cluster_spec.rb +20 -3
  194. data/spec/arachni/option_groups/datastore_spec.rb +6 -6
  195. data/spec/arachni/option_groups/dispatcher_spec.rb +19 -19
  196. data/spec/arachni/option_groups/http_spec.rb +11 -11
  197. data/spec/arachni/option_groups/input_spec.rb +31 -27
  198. data/spec/arachni/option_groups/output_spec.rb +2 -2
  199. data/spec/arachni/option_groups/paths_spec.rb +17 -17
  200. data/spec/arachni/option_groups/rpc_spec.rb +2 -2
  201. data/spec/arachni/option_groups/scope_spec.rb +40 -40
  202. data/spec/arachni/option_groups/session_spec.rb +6 -5
  203. data/spec/arachni/option_groups/snapshot_spec.rb +4 -4
  204. data/spec/arachni/options_spec.rb +46 -45
  205. data/spec/arachni/page/dom/transition_spec.rb +74 -72
  206. data/spec/arachni/page/dom_spec.rb +35 -35
  207. data/spec/arachni/page/scope_spec.rb +15 -15
  208. data/spec/arachni/page_spec.rb +217 -217
  209. data/spec/arachni/parser_spec.rb +106 -104
  210. data/spec/arachni/platform/fingerprinter_spec.rb +17 -14
  211. data/spec/arachni/platform/list_spec.rb +33 -33
  212. data/spec/arachni/platform/manager_spec.rb +67 -64
  213. data/spec/arachni/plugin/base_spec.rb +10 -10
  214. data/spec/arachni/plugin/manager_spec.rb +38 -37
  215. data/spec/arachni/report_spec.rb +43 -40
  216. data/spec/arachni/reporter/base_spec.rb +15 -15
  217. data/spec/arachni/reporter/manager_spec.rb +4 -4
  218. data/spec/arachni/reporter/options_spec.rb +6 -6
  219. data/spec/arachni/rpc/client/base_spec.rb +6 -6
  220. data/spec/arachni/rpc/client/dispatcher_spec.rb +2 -2
  221. data/spec/arachni/rpc/client/instance_spec.rb +6 -6
  222. data/spec/arachni/rpc/server/active_options_spec.rb +11 -8
  223. data/spec/arachni/rpc/server/base_spec.rb +5 -5
  224. data/spec/arachni/rpc/server/checks/manager_spec.rb +8 -8
  225. data/spec/arachni/rpc/server/dispatcher/node_spec.rb +37 -37
  226. data/spec/arachni/rpc/server/dispatcher/service_spec.rb +15 -14
  227. data/spec/arachni/rpc/server/dispatcher_spec.rb +36 -35
  228. data/spec/arachni/rpc/server/framework/distributor_spec.rb +36 -36
  229. data/spec/arachni/rpc/server/framework_multi_spec.rb +340 -336
  230. data/spec/arachni/rpc/server/framework_spec.rb +90 -85
  231. data/spec/arachni/rpc/server/instance_spec.rb +126 -107
  232. data/spec/arachni/rpc/server/output_spec.rb +1 -1
  233. data/spec/arachni/rpc/server/plugin/manager_spec.rb +6 -6
  234. data/spec/arachni/ruby/array_spec.rb +42 -42
  235. data/spec/arachni/ruby/hash_spec.rb +20 -18
  236. data/spec/arachni/ruby/io_spec.rb +2 -2
  237. data/spec/arachni/ruby/object_spec.rb +1 -1
  238. data/spec/arachni/ruby/set_spec.rb +3 -3
  239. data/spec/arachni/ruby/string_spec.rb +30 -30
  240. data/spec/arachni/ruby/webrick_spec.rb +2 -2
  241. data/spec/arachni/scope_spec.rb +1 -1
  242. data/spec/arachni/session_spec.rb +67 -64
  243. data/spec/arachni/snapshot_spec.rb +15 -15
  244. data/spec/arachni/state/audit_spec.rb +11 -11
  245. data/spec/arachni/state/element_filter_spec.rb +6 -6
  246. data/spec/arachni/state/framework/rpc_spec.rb +12 -12
  247. data/spec/arachni/state/framework_spec.rb +125 -121
  248. data/spec/arachni/state/http_spec.rb +7 -7
  249. data/spec/arachni/state/options_spec.rb +7 -7
  250. data/spec/arachni/state/plugins_spec.rb +8 -8
  251. data/spec/arachni/state_spec.rb +10 -10
  252. data/spec/arachni/support/buffer/autoflush_spec.rb +16 -16
  253. data/spec/arachni/support/buffer/base_spec.rb +39 -39
  254. data/spec/arachni/support/cache/least_cost_replacement_spec.rb +18 -18
  255. data/spec/arachni/support/cache/least_recently_pushed_spec.rb +24 -24
  256. data/spec/arachni/support/cache/least_recently_used_spec.rb +20 -20
  257. data/spec/arachni/support/cache/preference_spec.rb +4 -4
  258. data/spec/arachni/support/cache/random_replacement_spec.rb +8 -8
  259. data/spec/arachni/support/crypto/rsa_aes_cbc_spec.rb +1 -1
  260. data/spec/arachni/support/database/hash_spec.rb +44 -43
  261. data/spec/arachni/support/database/queue_spec.rb +27 -27
  262. data/spec/arachni/support/lookup/hash_set_spec.rb +8 -8
  263. data/spec/arachni/support/lookup/moolb_spec.rb +3 -3
  264. data/spec/arachni/support/mixins/observable_spec.rb +6 -6
  265. data/spec/arachni/support/signature_spec.rb +19 -19
  266. data/spec/arachni/trainer_spec.rb +39 -39
  267. data/spec/arachni/typhoeus/hydra_spec.rb +2 -2
  268. data/spec/arachni/uri/scope_spec.rb +66 -66
  269. data/spec/arachni/uri_spec.rb +107 -105
  270. data/spec/arachni/utilities_spec.rb +40 -40
  271. data/spec/components/checks/active/csrf_spec.rb +8 -8
  272. data/spec/components/checks/active/no_sql_injection_spec.rb +1 -1
  273. data/spec/components/checks/active/sql_injection_spec.rb +16 -16
  274. data/spec/components/checks/active/trainer_spec.rb +4 -4
  275. data/spec/components/checks/active/unvalidated_redirect_dom_spec.rb +4 -2
  276. data/spec/components/checks/active/xpath_injection_spec.rb +1 -1
  277. data/spec/components/checks/active/xss_dom_script_context_spec.rb +51 -21
  278. data/spec/components/checks/active/xss_dom_spec.rb +46 -24
  279. data/spec/components/checks/passive/allowed_methods_spec.rb +1 -1
  280. data/spec/components/checks/passive/grep/cookie_set_for_parent_domain_spec.rb +1 -1
  281. data/spec/components/checks/passive/grep/hsts_spec.rb +2 -2
  282. data/spec/components/checks/passive/grep/http_only_cookies_spec.rb +1 -1
  283. data/spec/components/checks/passive/grep/insecure_cookies_spec.rb +1 -1
  284. data/spec/components/checks/passive/grep/insecure_cors_policy_spec.rb +2 -2
  285. data/spec/components/checks/passive/grep/password_autocomplete_spec.rb +1 -1
  286. data/spec/components/checks/passive/grep/private_ip_spec.rb +3 -3
  287. data/spec/components/checks/passive/grep/unencrypted_password_forms_spec.rb +1 -1
  288. data/spec/components/checks/passive/grep/x_frame_options_spec.rb +2 -2
  289. data/spec/components/checks/passive/interesting_responses_spec.rb +2 -2
  290. data/spec/components/checks/passive/webdav_spec.rb +1 -1
  291. data/spec/components/checks/passive/xst_spec.rb +1 -1
  292. data/spec/components/fingerprinters/servers/apache_spec.rb +2 -2
  293. data/spec/components/path_extractors/comments_spec.rb +5 -1
  294. data/spec/components/path_extractors/scripts_spec.rb +5 -2
  295. data/spec/components/plugins/autologin_spec.rb +22 -22
  296. data/spec/components/plugins/autothrottle_spec.rb +6 -5
  297. data/spec/components/plugins/content_types_spec.rb +4 -4
  298. data/spec/components/plugins/cookie_collector_spec.rb +5 -5
  299. data/spec/components/plugins/exec_spec.rb +12 -12
  300. data/spec/components/plugins/form_dicattack_spec.rb +3 -3
  301. data/spec/components/plugins/headers_collector_spec.rb +8 -8
  302. data/spec/components/plugins/healthmap_spec.rb +3 -3
  303. data/spec/components/plugins/http_dicattack_spec.rb +3 -3
  304. data/spec/components/plugins/login_script_spec.rb +79 -22
  305. data/spec/components/plugins/meta/remedies/discovery_spec.rb +3 -2
  306. data/spec/components/plugins/meta/remedies/timing_attacks_spec.rb +3 -3
  307. data/spec/components/plugins/meta/uniformity_spec.rb +2 -2
  308. data/spec/components/plugins/restrict_to_dom_state_spec.rb +1 -1
  309. data/spec/components/plugins/script_spec.rb +1 -1
  310. data/spec/components/plugins/uncommon_headers_spec.rb +2 -2
  311. data/spec/components/plugins/vector_collector_spec.rb +2 -2
  312. data/spec/components/plugins/vector_feed_spec.rb +40 -40
  313. data/spec/components/plugins/waf_detector_spec.rb +6 -6
  314. data/spec/components/reporters/json_spec.rb +4 -4
  315. data/spec/components/reporters/marshal_spec.rb +2 -2
  316. data/spec/components/reporters/yaml_spec.rb +3 -2
  317. data/spec/external/wavsep/active/sqli_spec.rb +1 -3
  318. data/spec/spec_helper.rb +4 -0
  319. data/spec/support/factories/element/ui_form.rb +14 -0
  320. data/spec/support/factories/element/ui_input.rb +13 -0
  321. data/spec/support/factories/issue.rb +0 -13
  322. data/spec/support/fixtures/report.afr +0 -0
  323. data/spec/support/fixtures/{taint_check/taint.rb → signature_check/signature.rb} +2 -2
  324. data/spec/support/helpers/browser_cluster/jobs/taint_tracer.rb +11 -11
  325. data/spec/support/helpers/framework.rb +1 -1
  326. data/spec/support/helpers/pages.rb +2 -2
  327. data/spec/support/servers/arachni/browser.rb +139 -0
  328. data/spec/support/servers/arachni/browser/javascript/taint_tracer.rb +40 -0
  329. data/spec/support/servers/arachni/element/capabilities/analyzable/{taint.rb → signature.rb} +0 -0
  330. data/spec/support/servers/arachni/element/input/input_dom.rb +102 -0
  331. data/spec/support/servers/arachni/element/ui_form/ui_form_dom.rb +238 -0
  332. data/spec/support/servers/checks/active/trainer_check.rb +7 -7
  333. data/spec/support/servers/checks/active/unvalidated_redirect_dom.rb +22 -6
  334. data/spec/support/servers/checks/active/xss_dom.rb +50 -0
  335. data/spec/support/servers/checks/active/xss_dom_script_context.rb +53 -0
  336. data/spec/support/shared/browser/javascript/taint_tracer/sink/base.rb +6 -6
  337. data/spec/support/shared/check.rb +10 -12
  338. data/spec/support/shared/component/options/base.rb +24 -24
  339. data/spec/support/shared/element/base.rb +25 -25
  340. data/spec/support/shared/element/capabilities/auditable.rb +116 -140
  341. data/spec/support/shared/element/capabilities/dom_only.rb +65 -0
  342. data/spec/support/shared/element/capabilities/inputtable.rb +71 -86
  343. data/spec/support/shared/element/capabilities/mutable.rb +122 -111
  344. data/spec/support/shared/element/capabilities/refreshable.rb +10 -10
  345. data/spec/support/shared/element/capabilities/{submitable.rb → submittable.rb} +26 -26
  346. data/spec/support/shared/element/capabilities/with_auditor.rb +10 -10
  347. data/spec/support/shared/element/capabilities/with_dom.rb +8 -8
  348. data/spec/support/shared/element/capabilities/with_node.rb +4 -6
  349. data/spec/support/shared/element/capabilities/with_scope.rb +2 -2
  350. data/spec/support/shared/element/capabilities/with_source.rb +6 -8
  351. data/spec/support/shared/element/dom.rb +144 -0
  352. data/spec/support/shared/element/dom/auditable.rb +42 -0
  353. data/spec/support/shared/element/dom/inputtable.rb +5 -0
  354. data/spec/support/shared/element/dom/mutable.rb +3 -0
  355. data/spec/support/shared/element/dom/submittable.rb +119 -0
  356. data/spec/support/shared/external/wavsep.rb +3 -3
  357. data/spec/support/shared/fingerprinter.rb +2 -2
  358. data/spec/support/shared/framework.rb +1 -1
  359. data/spec/support/shared/http/message.rb +9 -9
  360. data/spec/support/shared/option_group.rb +17 -17
  361. data/spec/support/shared/path_extractor.rb +1 -1
  362. data/spec/support/shared/plugin.rb +2 -2
  363. data/spec/support/shared/support/cache.rb +57 -57
  364. data/spec/support/shared/support/lookup.rb +25 -25
  365. data/ui/cli/framework.rb +22 -11
  366. data/ui/cli/framework/option_parser.rb +15 -0
  367. data/ui/cli/option_parser.rb +8 -1
  368. data/ui/cli/output.rb +2 -1
  369. metadata +54 -20
  370. data/components/checks/active/xss_dom_inputs.rb +0 -236
  371. data/spec/components/checks/active/xss_dom_inputs_spec.rb +0 -30
  372. data/spec/support/servers/checks/active/xss_dom_inputs.rb +0 -59
  373. data/spec/support/shared/element/capabilities/auditable/dom.rb +0 -322
@@ -350,11 +350,11 @@ class Browser
350
350
  url: url,
351
351
  cookies: extra_cookies
352
352
  ) do
353
+ print_debug_level_2 "Loading: #{url}"
353
354
  watir.goto url
355
+ print_debug_level_2 'Done'
354
356
 
355
- @javascript.wait_till_ready
356
- wait_for_pending_requests
357
- wait_for_timers
357
+ wait_till_ready
358
358
 
359
359
  url = watir.url
360
360
  Options.browser_cluster.css_to_wait_for( url ).each do |css|
@@ -388,6 +388,20 @@ class Browser
388
388
  transition
389
389
  end
390
390
 
391
+ def wait_till_ready
392
+ print_debug_level_2 'Waiting for custom JS...'
393
+ @javascript.wait_till_ready
394
+ print_debug_level_2 'Done'
395
+
396
+ print_debug_level_2 "Waiting for #{@proxy.active_connections} connections to close.."
397
+ wait_for_pending_requests
398
+ print_debug_level_2 'Done'
399
+
400
+ print_debug_level_2 'Waiting for timers...'
401
+ wait_for_timers
402
+ print_debug_level_2 'Done'
403
+ end
404
+
391
405
  def shutdown
392
406
  begin
393
407
  watir.close if browser_alive?
@@ -704,6 +718,13 @@ class Browser
704
718
  # Some of these need an explicit event triggers.
705
719
  had_special_trigger = true if ![:change, :blur, :focus, :select].include? event
706
720
 
721
+ # Send keys will append to the existing value, so we need to
722
+ # clear it first. The receiving input may support values
723
+ # though, so watch out.
724
+ if (subtype = element.to_subtype).respond_to?( :value= )
725
+ subtype.value = ''
726
+ end
727
+
707
728
  element.send_keys( (options[:value] || value_for( element )).to_s )
708
729
  end
709
730
 
@@ -808,6 +829,14 @@ class Browser
808
829
  page.dom.transitions = @transitions.dup
809
830
  page.dom.skip_states = skip_states.dup
810
831
 
832
+ if Options.audit.ui_inputs?
833
+ page.ui_inputs = Element::UIInput.from_browser( self, page )
834
+ end
835
+
836
+ if Options.audit.ui_forms?
837
+ page.ui_forms = Element::UIForm.from_browser( self, page )
838
+ end
839
+
811
840
  # Go through auditable DOM forms and cookies and remove the DOM from
812
841
  # them if no events are associated with it.
813
842
  #
@@ -1012,6 +1041,11 @@ class Browser
1012
1041
  s << '>'
1013
1042
  end
1014
1043
 
1044
+ def filter_events( element, events )
1045
+ supported = Set.new( Arachni::Browser::Javascript.events_for( element ) )
1046
+ events.reject { |name, _| !supported.include? ('on' + name.to_s.gsub( /^on/, '' )).to_sym }
1047
+ end
1048
+
1015
1049
  private
1016
1050
 
1017
1051
  def fill_in_form_inputs( form, inputs = nil )
@@ -1273,8 +1307,23 @@ class Browser
1273
1307
  end
1274
1308
 
1275
1309
  url = "#{url}/set-cookies-#{request_token}"
1310
+
1311
+ body = ''
1312
+ if Arachni::Options::browser_cluster.local_storage.any?
1313
+ body = <<EOJS
1314
+ <script>
1315
+ var data = #{Arachni::Options::browser_cluster.local_storage.to_json};
1316
+
1317
+ for( prop in data ) {
1318
+ localStorage.setItem( prop, data[prop] );
1319
+ }
1320
+ </script>
1321
+ EOJS
1322
+ end
1323
+
1276
1324
  watir.goto preload( HTTP::Response.new(
1277
1325
  url: url,
1326
+ body: body,
1278
1327
  headers: {
1279
1328
  'Set-Cookie' => set_cookies.values.map(&:to_set_cookie)
1280
1329
  }
@@ -504,13 +504,13 @@ class Javascript
504
504
  end
505
505
 
506
506
  def wrapped_taint_tracer_initializer
507
- "/* #{token}_initialize_start */" <<
508
- "#{@taint_tracer.stub.function( :initialize, taints )}" <<
507
+ "/* #{token}_initialize_start */ " <<
508
+ "#{@taint_tracer.stub.function( :initialize, taints )} " <<
509
509
  "/* #{token}_initialize_stop */"
510
510
  end
511
511
 
512
512
  def wrapped_custom_code
513
- "/* #{token}_code_start */#{custom_code}/* #{token}_code_stop */"
513
+ "/* #{token}_code_start */ #{custom_code} /* #{token}_code_stop */"
514
514
  end
515
515
 
516
516
  def js_initialization_signal
@@ -25,6 +25,10 @@ var _tokenTaintTracer = _tokenTaintTracer || {
25
25
 
26
26
  max_sinks: 50,
27
27
 
28
+ // Limits the maximum depth when traversing object properties, looking for
29
+ // taints -- safeguard for circular references.
30
+ find_taint_recursively_max_depth: 3,
31
+
28
32
  // Hold debugging information, usually pushed by the 'debug' function.
29
33
  debugging_data: [],
30
34
 
@@ -41,8 +45,7 @@ var _tokenTaintTracer = _tokenTaintTracer || {
41
45
  },
42
46
 
43
47
  // Keeps track of which functions have had tracers installed.
44
- traced: {
45
- },
48
+ traced: {},
46
49
 
47
50
  // Original functions, without tracers. We don't want to trigger traced
48
51
  // functions to provide functionality to this object.
@@ -211,7 +214,7 @@ var _tokenTaintTracer = _tokenTaintTracer || {
211
214
  if( _tokenTaintTracer.data_flow_sinks[taint].length > _tokenTaintTracer.max_sinks ) {
212
215
  _tokenTaintTracer.data_flow_sinks[taint] =
213
216
  _tokenTaintTracer.data_flow_sinks[taint].slice(
214
- _tokenTaintTracer.data_flow_sinks[taint].length -
217
+ _tokenTaintTracer.data_flow_sinks[taint].length -
215
218
  _tokenTaintTracer.max_sinks,
216
219
  _tokenTaintTracer.data_flow_sinks[taint].length
217
220
  )
@@ -329,34 +332,38 @@ var _tokenTaintTracer = _tokenTaintTracer || {
329
332
  },
330
333
 
331
334
  cleanup_event: function( e ) {
332
- var elements = [
333
- 'toElement', 'target', 'srcElement', 'currentTarget',
334
- 'fromElement'
335
+ var keep = [
336
+ 'toElement',
337
+ 'target',
338
+ 'srcElement',
339
+ 'currentTarget',
340
+ 'fromElement',
341
+ 'eventPhase',
342
+ 'type'
335
343
  ];
336
344
 
337
- var arg = {};
338
- for( var prop in e ) {
339
- if( elements.indexOf( prop ) != -1 && e[prop] ) {
345
+ var prop;
346
+ var event_data = {};
347
+ for( var i = 0; i < keep.length; i++ ) {
348
+ prop = keep[i];
340
349
 
341
- // Quick and easy, get the element as HTML.
342
- if( e[prop].outerHTML ) {
343
- arg[prop] = e[prop].outerHTML;
350
+ if( !e[prop] ) continue;
344
351
 
345
- // Dealing with a HTMLDocument,, needs some special
346
- // treatment to get the HTML.
347
- } else if( e[prop].documentElement ) {
348
- arg[prop] = e[prop].documentElement.outerHTML;
352
+ // Quick and easy, get the element as HTML.
353
+ if( e[prop].outerHTML ) {
354
+ event_data[prop] = e[prop].outerHTML;
349
355
 
350
- // You never know...
351
- } else {
352
- arg[prop] = e[prop].toString();
353
- }
356
+ // Dealing with a HTMLDocument, needs some special treatment to get the HTML.
357
+ } else if( e[prop].documentElement ) {
358
+ event_data[prop] = e[prop].documentElement.outerHTML;
359
+
360
+ // You never know...
354
361
  } else {
355
- arg[prop] = e[prop];
362
+ event_data[prop] = e[prop].toString();
356
363
  }
357
364
  }
358
365
 
359
- return arg;
366
+ return event_data;
360
367
  },
361
368
 
362
369
  has_function: function( func ) {
@@ -414,8 +421,12 @@ var _tokenTaintTracer = _tokenTaintTracer || {
414
421
  return null;
415
422
  },
416
423
 
417
- find_taint_recursively: function( taint, object ) {
424
+ find_taint_recursively: function( taint, object, depth ) {
418
425
  var tainted;
426
+ depth = depth || 0;
427
+
428
+ if( depth > _tokenTaintTracer.find_taint_recursively_max_depth ) return;
429
+ depth++;
419
430
 
420
431
  switch( Object.prototype.toString.call( object ) ) {
421
432
  case '[object String]':
@@ -424,7 +435,12 @@ var _tokenTaintTracer = _tokenTaintTracer || {
424
435
 
425
436
  case '[object Array]':
426
437
  for( var i = 0; i < object.length; i++ ) {
427
- tainted = _tokenTaintTracer.find_taint_recursively( taint, object[i] );
438
+ tainted = _tokenTaintTracer.find_taint_recursively(
439
+ taint,
440
+ object[i],
441
+ depth
442
+ );
443
+
428
444
  if ( tainted ) return tainted;
429
445
  }
430
446
  break;
@@ -435,7 +451,12 @@ var _tokenTaintTracer = _tokenTaintTracer || {
435
451
  var property_value = object[property];
436
452
 
437
453
  if( Object.prototype.toString.call( property_value ) !== '[object Function]' ){
438
- tainted = _tokenTaintTracer.find_taint_recursively( taint, property_value );
454
+ tainted = _tokenTaintTracer.find_taint_recursively(
455
+ taint,
456
+ property_value,
457
+ depth
458
+ );
459
+
439
460
  if ( tainted ) return tainted;
440
461
  }
441
462
  }
@@ -71,6 +71,8 @@ class BrowserCluster
71
71
 
72
72
  attr_reader :consumed_pids
73
73
 
74
+ attr_reader :job_counter
75
+
74
76
  # @param [Hash] options
75
77
  # @option options [Integer] :pool_size (5)
76
78
  # Amount of {Worker browsers} to add to the pool.
@@ -153,6 +155,8 @@ class BrowserCluster
153
155
 
154
156
  notify_on_queue job
155
157
 
158
+ self.class.increment_queued_job_count
159
+
156
160
  @pending_job_counter += 1
157
161
  @pending_jobs[job.id] += 1
158
162
  @job_callbacks[job.id] = block if block
@@ -362,6 +366,9 @@ class BrowserCluster
362
366
  # @private
363
367
  def decrease_pending_job( job )
364
368
  synchronize do
369
+ increment_completed_job_count
370
+ add_to_total_job_time( job.time )
371
+
365
372
  @pending_job_counter -= 1
366
373
  @pending_jobs[job.id] -= 1
367
374
  job_done( job ) if @pending_jobs[job.id] <= 0
@@ -373,6 +380,60 @@ class BrowserCluster
373
380
  @job_callbacks[job.id]
374
381
  end
375
382
 
383
+ def increment_queued_job_count
384
+ synchronize do
385
+ self.class.increment_queued_job_count
386
+ end
387
+ end
388
+
389
+ def increment_completed_job_count( *args )
390
+ synchronize do
391
+ self.class.increment_completed_job_count( *args )
392
+ end
393
+ end
394
+
395
+ def add_to_total_job_time( time )
396
+ synchronize do
397
+ self.class.add_to_total_job_time( time )
398
+ end
399
+ end
400
+
401
+ def self.seconds_per_job
402
+ total_job_time / Float( completed_job_count )
403
+ end
404
+
405
+ def self.increment_queued_job_count
406
+ @queued_job_count ||= 0
407
+ @queued_job_count += 1
408
+ end
409
+
410
+ def self.increment_completed_job_count( increment = 1 )
411
+ @completed_job_count ||= 0
412
+ @completed_job_count += increment
413
+ end
414
+
415
+ def self.completed_job_count
416
+ @completed_job_count.to_i
417
+ end
418
+
419
+ def self.total_job_time
420
+ @total_job_time.to_i
421
+ end
422
+
423
+ def self.add_to_total_job_time( time )
424
+ @total_job_time ||= 0
425
+ @total_job_time += time.to_i
426
+ end
427
+
428
+ def self.statistics
429
+ {
430
+ seconds_per_job: seconds_per_job,
431
+ total_job_time: total_job_time,
432
+ queued_job_count: @queued_job_count || 0,
433
+ completed_job_count: @completed_job_count || 0
434
+ }
435
+ end
436
+
376
437
  private
377
438
 
378
439
  def notify_on_queue( job )
@@ -44,6 +44,10 @@ class Job
44
44
  # @see #forward_as
45
45
  attr_accessor :forwarder
46
46
 
47
+ # @return [Integer]
48
+ # Duration of the job, in seconds.
49
+ attr_accessor :time
50
+
47
51
  # @param [Hash] options
48
52
  def initialize( options = {} )
49
53
  @options = options.dup
@@ -52,6 +56,19 @@ class Job
52
56
  options.each { |k, v| options[k] = send( "#{k}=", v ) }
53
57
  end
54
58
 
59
+ # @param [Integer] time
60
+ # Amount of {#time} elapsed until time-out.
61
+ def timed_out!( time )
62
+ @timed_out = true
63
+ @time = time
64
+ end
65
+
66
+ # @return [Bool]
67
+ # `true` if timed-ot, `false` otherwise.
68
+ def timed_out?
69
+ !!@timed_out
70
+ end
71
+
55
72
  # @note The following resources will be available at the time of execution:
56
73
  #
57
74
  # * {#browser}
@@ -121,7 +138,10 @@ class Job
121
138
  # @return [Job]
122
139
  # Copy of `self`
123
140
  def dup
124
- self.class.new add_id( @options )
141
+ n = self.class.new( add_id( @options ) )
142
+ n.time = time
143
+ n.timed_out!( time ) if timed_out?
144
+ n
125
145
  end
126
146
 
127
147
  # @param [Hash] options
@@ -21,7 +21,9 @@ class BrowserProvider < Job
21
21
  end
22
22
 
23
23
  def to_s
24
- "#<#{self.class}:#{object_id} callback=#{browser.master.callback_for( self ) if browser && browser.master}>"
24
+ "#<#{self.class}:#{object_id} " <<
25
+ "callback=#{browser.master.callback_for( self ) if browser && browser.master} " <<
26
+ "time=#{@time} timed_out=#{timed_out?}>"
25
27
  end
26
28
  alias :inspect :to_s
27
29
 
@@ -45,7 +45,8 @@ class ResourceExploration < Job
45
45
  end
46
46
 
47
47
  def to_s
48
- "#<#{self.class}:#{object_id} @resource=#{@resource}>"
48
+ "#<#{self.class}:#{object_id} @resource=#{@resource} " <<
49
+ "time=#{@time} timed_out=#{timed_out?}>"
49
50
  end
50
51
  alias :inspect :to_s
51
52
 
@@ -37,7 +37,8 @@ class EventTrigger < ResourceExploration
37
37
 
38
38
  def to_s
39
39
  "#<#{self.class}:#{object_id} @resource=#{@resource} " +
40
- "@event=#{@event.inspect} @element=#{@element.inspect}>"
40
+ "@event=#{@event.inspect} @element=#{@element.inspect} " <<
41
+ "time=#{@time} timed_out=#{timed_out?}>"
41
42
  end
42
43
 
43
44
  end
@@ -42,8 +42,9 @@ class TaintTrace < ResourceExploration
42
42
  end
43
43
 
44
44
  def to_s
45
- "#<#{self.class}:#{object_id} @resource=#{@resource} " +
46
- "@taint=#{@taint.inspect} @injector=#{@injector.inspect}>"
45
+ "#<#{self.class}:#{object_id} @resource=#{@resource} " <<
46
+ "@taint=#{@taint.inspect} @injector=#{@injector.inspect} " <<
47
+ "time=#{@time} timed_out=#{timed_out?}>"
47
48
  end
48
49
  alias :inspect :to_s
49
50
 
@@ -28,7 +28,7 @@ class EventTrigger < ResourceExploration::EventTrigger
28
28
  def to_s
29
29
  "#<#{self.class}:#{object_id} @resource=#{@resource} " +
30
30
  "@event=#{@event.inspect} @element=#{@element.inspect} " +
31
- "@forwarder=#{@forwarder}>"
31
+ "@forwarder=#{@forwarder} time=#{@time} timed_out=#{timed_out?}>"
32
32
  end
33
33
 
34
34
  end
@@ -82,6 +82,7 @@ class Worker < Arachni::Browser
82
82
  # If we can't respawn, then bail out.
83
83
  return if browser_respawn_if_necessary.nil?
84
84
 
85
+ time = Time.now
85
86
  begin
86
87
  with_timeout @job_timeout do
87
88
  exception_jail false do
@@ -98,7 +99,11 @@ class Worker < Arachni::Browser
98
99
  end
99
100
  end
100
101
  end
102
+
103
+ job.time = Time.now - time
101
104
  rescue TimeoutError => e
105
+ job.timed_out!( Time.now - time )
106
+
102
107
  print_bad "Job timed-out after #{@job_timeout} seconds: #{@job}"
103
108
 
104
109
  # Could have left us with a broken browser.