arachni 1.4 → 1.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (746) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +136 -0
  3. data/Gemfile +3 -1
  4. data/LICENSE.md +1 -1
  5. data/README.md +5 -2
  6. data/Rakefile +1 -1
  7. data/arachni.gemspec +35 -30
  8. data/bin/arachni +1 -1
  9. data/bin/arachni_console +1 -1
  10. data/bin/arachni_multi +6 -1
  11. data/bin/arachni_reporter +1 -1
  12. data/bin/arachni_reproduce +12 -0
  13. data/bin/arachni_rest_server +1 -1
  14. data/bin/arachni_restore +1 -1
  15. data/bin/arachni_rpc +6 -1
  16. data/bin/arachni_rpcd +1 -1
  17. data/bin/arachni_rpcd_monitor +6 -1
  18. data/bin/arachni_script +1 -1
  19. data/components/checks/active/code_injection.rb +1 -1
  20. data/components/checks/active/code_injection_php_input_wrapper.rb +1 -1
  21. data/components/checks/active/code_injection_timing.rb +1 -1
  22. data/components/checks/active/csrf.rb +15 -75
  23. data/components/checks/active/file_inclusion.rb +1 -1
  24. data/components/checks/active/ldap_injection.rb +1 -1
  25. data/components/checks/active/no_sql_injection.rb +1 -1
  26. data/components/checks/active/no_sql_injection_differential.rb +1 -1
  27. data/components/checks/active/os_cmd_injection.rb +1 -1
  28. data/components/checks/active/os_cmd_injection_timing.rb +1 -1
  29. data/components/checks/active/path_traversal.rb +3 -3
  30. data/components/checks/active/response_splitting.rb +1 -1
  31. data/components/checks/active/rfi.rb +1 -1
  32. data/components/checks/active/session_fixation.rb +1 -1
  33. data/components/checks/active/source_code_disclosure.rb +1 -1
  34. data/components/checks/active/sql_injection.rb +1 -1
  35. data/components/checks/active/sql_injection/regexps/hsqldb.yaml +1 -0
  36. data/components/checks/active/sql_injection/substrings/hsqldb +1 -0
  37. data/components/checks/active/sql_injection/substrings/java +4 -0
  38. data/components/checks/active/sql_injection/substrings/oracle +0 -1
  39. data/components/checks/active/sql_injection/substrings/sqlite +1 -0
  40. data/components/checks/active/sql_injection_differential.rb +1 -1
  41. data/components/checks/active/sql_injection_timing.rb +1 -1
  42. data/components/checks/active/trainer.rb +1 -1
  43. data/components/checks/active/unvalidated_redirect.rb +34 -11
  44. data/components/checks/active/unvalidated_redirect_dom.rb +4 -4
  45. data/components/checks/active/xpath_injection.rb +1 -1
  46. data/components/checks/active/xss.rb +52 -27
  47. data/components/checks/active/xss_dom.rb +15 -11
  48. data/components/checks/active/xss_dom_script_context.rb +4 -6
  49. data/components/checks/active/xss_event.rb +45 -33
  50. data/components/checks/active/xss_path.rb +9 -6
  51. data/components/checks/active/xss_script_context.rb +99 -46
  52. data/components/checks/active/xss_tag.rb +39 -14
  53. data/components/checks/active/xxe.rb +1 -1
  54. data/components/checks/passive/allowed_methods.rb +1 -1
  55. data/components/checks/passive/backdoors.rb +1 -1
  56. data/components/checks/passive/backup_directories.rb +15 -3
  57. data/components/checks/passive/backup_files.rb +39 -6
  58. data/components/checks/passive/common_admin_interfaces.rb +1 -1
  59. data/components/checks/passive/common_admin_interfaces/admin-panels.txt +1 -0
  60. data/components/checks/passive/common_directories.rb +1 -1
  61. data/components/checks/passive/common_files.rb +1 -1
  62. data/components/checks/passive/directory_listing.rb +1 -1
  63. data/components/checks/passive/grep/captcha.rb +8 -9
  64. data/components/checks/passive/grep/cookie_set_for_parent_domain.rb +1 -1
  65. data/components/checks/passive/grep/credit_card.rb +1 -1
  66. data/components/checks/passive/grep/cvs_svn_users.rb +1 -1
  67. data/components/checks/passive/grep/emails.rb +1 -1
  68. data/components/checks/passive/grep/form_upload.rb +3 -5
  69. data/components/checks/passive/grep/hsts.rb +1 -1
  70. data/components/checks/passive/grep/html_objects.rb +1 -1
  71. data/components/checks/passive/grep/http_only_cookies.rb +1 -1
  72. data/components/checks/passive/grep/insecure_cookies.rb +5 -5
  73. data/components/checks/passive/grep/insecure_cors_policy.rb +1 -1
  74. data/components/checks/passive/grep/mixed_resource.rb +4 -4
  75. data/components/checks/passive/grep/password_autocomplete.rb +1 -1
  76. data/components/checks/passive/grep/private_ip.rb +1 -1
  77. data/components/checks/passive/grep/ssn.rb +1 -1
  78. data/components/checks/passive/grep/unencrypted_password_forms.rb +3 -3
  79. data/components/checks/passive/grep/x_frame_options.rb +1 -1
  80. data/components/checks/passive/htaccess_limit.rb +1 -1
  81. data/components/checks/passive/http_put.rb +1 -1
  82. data/components/checks/passive/insecure_client_access_policy.rb +2 -2
  83. data/components/checks/passive/insecure_cross_domain_policy_access.rb +2 -2
  84. data/components/checks/passive/insecure_cross_domain_policy_headers.rb +2 -2
  85. data/components/checks/passive/interesting_responses.rb +1 -1
  86. data/components/checks/passive/localstart_asp.rb +1 -1
  87. data/components/checks/passive/origin_spoof_access_restriction_bypass.rb +1 -1
  88. data/components/checks/passive/webdav.rb +1 -1
  89. data/components/checks/passive/xst.rb +10 -12
  90. data/components/fingerprinters/frameworks/aspx_mvc.rb +1 -1
  91. data/components/fingerprinters/frameworks/cakephp.rb +1 -1
  92. data/components/fingerprinters/frameworks/cherrypy.rb +1 -1
  93. data/components/fingerprinters/frameworks/django.rb +1 -1
  94. data/components/fingerprinters/frameworks/jsf.rb +1 -1
  95. data/components/fingerprinters/frameworks/nette.rb +1 -1
  96. data/components/fingerprinters/frameworks/rack.rb +1 -1
  97. data/components/fingerprinters/frameworks/rails.rb +1 -1
  98. data/components/fingerprinters/frameworks/symfony.rb +1 -1
  99. data/components/fingerprinters/languages/asp.rb +1 -1
  100. data/components/fingerprinters/languages/aspx.rb +1 -1
  101. data/components/fingerprinters/languages/java.rb +1 -1
  102. data/components/fingerprinters/languages/php.rb +1 -1
  103. data/components/fingerprinters/languages/python.rb +1 -1
  104. data/components/fingerprinters/languages/ruby.rb +1 -1
  105. data/components/fingerprinters/os/bsd.rb +1 -1
  106. data/components/fingerprinters/os/linux.rb +1 -1
  107. data/components/fingerprinters/os/solaris.rb +1 -1
  108. data/components/fingerprinters/os/unix.rb +1 -1
  109. data/components/fingerprinters/os/windows.rb +1 -1
  110. data/components/fingerprinters/servers/apache.rb +1 -1
  111. data/components/fingerprinters/servers/gunicorn.rb +1 -1
  112. data/components/fingerprinters/servers/iis.rb +1 -1
  113. data/components/fingerprinters/servers/jetty.rb +1 -1
  114. data/components/fingerprinters/servers/nginx.rb +1 -1
  115. data/components/fingerprinters/servers/tomcat.rb +1 -1
  116. data/components/path_extractors/anchors.rb +3 -5
  117. data/components/path_extractors/areas.rb +3 -4
  118. data/components/path_extractors/comments.rb +4 -5
  119. data/components/path_extractors/data_url.rb +4 -5
  120. data/components/path_extractors/forms.rb +3 -4
  121. data/components/path_extractors/frames.rb +3 -5
  122. data/components/path_extractors/generic.rb +3 -1
  123. data/components/path_extractors/links.rb +3 -4
  124. data/components/path_extractors/meta_refresh.rb +11 -17
  125. data/components/path_extractors/scripts.rb +18 -15
  126. data/components/plugins/autologin.rb +3 -2
  127. data/components/plugins/beep_notify.rb +1 -1
  128. data/components/plugins/content_types.rb +1 -1
  129. data/components/plugins/cookie_collector.rb +1 -1
  130. data/components/plugins/debug/browser_cluster_job_monitor.rb +60 -0
  131. data/components/plugins/defaults/autothrottle.rb +1 -1
  132. data/components/plugins/defaults/healthmap.rb +3 -1
  133. data/components/plugins/defaults/meta/remedies/discovery.rb +1 -1
  134. data/components/plugins/defaults/meta/remedies/timing_attacks.rb +1 -1
  135. data/components/plugins/defaults/meta/uniformity.rb +1 -1
  136. data/components/plugins/email_notify.rb +26 -9
  137. data/components/plugins/exec.rb +1 -1
  138. data/components/plugins/form_dicattack.rb +3 -4
  139. data/components/plugins/headers_collector.rb +1 -1
  140. data/components/plugins/http_dicattack.rb +4 -5
  141. data/components/plugins/login_script.rb +2 -2
  142. data/components/plugins/metrics.rb +41 -15
  143. data/components/plugins/page_dump.rb +60 -0
  144. data/components/plugins/proxy.rb +42 -30
  145. data/components/plugins/proxy/template_scope.rb +6 -1
  146. data/components/plugins/rate_limiter.rb +80 -0
  147. data/components/plugins/restrict_to_dom_state.rb +1 -1
  148. data/components/plugins/script.rb +1 -1
  149. data/components/plugins/uncommon_headers.rb +1 -1
  150. data/components/plugins/vector_collector.rb +1 -1
  151. data/components/plugins/vector_feed.rb +1 -1
  152. data/components/plugins/waf_detector.rb +3 -3
  153. data/components/plugins/webhook_notify.rb +99 -0
  154. data/components/reporters/ap.rb +1 -1
  155. data/components/reporters/html.rb +2 -3
  156. data/components/reporters/html/default.erb +1 -2
  157. data/components/reporters/html/default/configuration.erb +2 -0
  158. data/components/reporters/json.rb +1 -1
  159. data/components/reporters/marshal.rb +1 -1
  160. data/components/reporters/plugin_formatters/html/autologin.rb +1 -1
  161. data/components/reporters/plugin_formatters/html/content_types.rb +1 -1
  162. data/components/reporters/plugin_formatters/html/cookie_collector.rb +1 -1
  163. data/components/reporters/plugin_formatters/html/exec.rb +1 -1
  164. data/components/reporters/plugin_formatters/html/form_dicattack.rb +1 -1
  165. data/components/reporters/plugin_formatters/html/healthmap.rb +1 -1
  166. data/components/reporters/plugin_formatters/html/http_dicattack.rb +1 -1
  167. data/components/reporters/plugin_formatters/html/login_script.rb +1 -1
  168. data/components/reporters/plugin_formatters/html/metrics.rb +46 -1
  169. data/components/reporters/plugin_formatters/html/uncommon_headers.rb +1 -1
  170. data/components/reporters/plugin_formatters/html/uniformity.rb +1 -1
  171. data/components/reporters/plugin_formatters/html/vector_collector.rb +1 -1
  172. data/components/reporters/plugin_formatters/html/waf_detector.rb +1 -1
  173. data/components/reporters/plugin_formatters/stdout/autologin.rb +1 -1
  174. data/components/reporters/plugin_formatters/stdout/content_types.rb +1 -1
  175. data/components/reporters/plugin_formatters/stdout/cookie_collector.rb +1 -1
  176. data/components/reporters/plugin_formatters/stdout/exec.rb +1 -1
  177. data/components/reporters/plugin_formatters/stdout/form_dicattack.rb +1 -1
  178. data/components/reporters/plugin_formatters/stdout/healthmap.rb +1 -1
  179. data/components/reporters/plugin_formatters/stdout/http_dicattack.rb +1 -1
  180. data/components/reporters/plugin_formatters/stdout/login_script.rb +1 -1
  181. data/components/reporters/plugin_formatters/stdout/metrics.rb +11 -1
  182. data/components/reporters/plugin_formatters/stdout/uncommon_headers.rb +1 -1
  183. data/components/reporters/plugin_formatters/stdout/uniformity.rb +1 -1
  184. data/components/reporters/plugin_formatters/stdout/vector_collector.rb +1 -1
  185. data/components/reporters/plugin_formatters/stdout/waf_detector.rb +1 -1
  186. data/components/reporters/plugin_formatters/xml/autologin.rb +1 -1
  187. data/components/reporters/plugin_formatters/xml/content_types.rb +10 -7
  188. data/components/reporters/plugin_formatters/xml/cookie_collector.rb +6 -3
  189. data/components/reporters/plugin_formatters/xml/exec.rb +1 -1
  190. data/components/reporters/plugin_formatters/xml/form_dicattack.rb +1 -1
  191. data/components/reporters/plugin_formatters/xml/healthmap.rb +1 -1
  192. data/components/reporters/plugin_formatters/xml/http_dicattack.rb +1 -1
  193. data/components/reporters/plugin_formatters/xml/login_script.rb +1 -1
  194. data/components/reporters/plugin_formatters/xml/metrics.rb +1 -1
  195. data/components/reporters/plugin_formatters/xml/uncommon_headers.rb +5 -2
  196. data/components/reporters/plugin_formatters/xml/uniformity.rb +1 -1
  197. data/components/reporters/plugin_formatters/xml/vector_collector.rb +8 -5
  198. data/components/reporters/plugin_formatters/xml/waf_detector.rb +1 -1
  199. data/components/reporters/stdout.rb +3 -2
  200. data/components/reporters/txt.rb +1 -1
  201. data/components/reporters/xml.rb +39 -22
  202. data/components/reporters/xml/schema.xsd +28 -13
  203. data/components/reporters/yaml.rb +1 -1
  204. data/lib/arachni.rb +1 -1
  205. data/lib/arachni/banner.rb +1 -1
  206. data/lib/arachni/browser.rb +242 -231
  207. data/lib/arachni/browser/element_locator.rb +9 -5
  208. data/lib/arachni/browser/javascript.rb +103 -168
  209. data/lib/arachni/browser/javascript/dom_monitor.rb +1 -1
  210. data/lib/arachni/browser/javascript/proxy.rb +1 -1
  211. data/lib/arachni/browser/javascript/proxy/stub.rb +1 -1
  212. data/lib/arachni/browser/javascript/scripts/dom_monitor.js +295 -51
  213. data/lib/arachni/browser/javascript/scripts/polyfills.js +0 -28
  214. data/lib/arachni/browser/javascript/scripts/taint_tracer.js +46 -8
  215. data/lib/arachni/browser/javascript/taint_tracer.rb +1 -1
  216. data/lib/arachni/browser/javascript/taint_tracer/frame.rb +1 -1
  217. data/lib/arachni/browser/javascript/taint_tracer/frame/called_function.rb +1 -1
  218. data/lib/arachni/browser/javascript/taint_tracer/sink/base.rb +1 -1
  219. data/lib/arachni/browser/javascript/taint_tracer/sink/data_flow.rb +1 -1
  220. data/lib/arachni/browser/javascript/taint_tracer/sink/execution_flow.rb +1 -1
  221. data/lib/arachni/browser_cluster.rb +78 -60
  222. data/lib/arachni/browser_cluster/job.rb +9 -2
  223. data/lib/arachni/browser_cluster/job/result.rb +1 -1
  224. data/lib/arachni/browser_cluster/jobs/browser_provider.rb +8 -2
  225. data/lib/arachni/browser_cluster/jobs/dom_exploration.rb +13 -1
  226. data/lib/arachni/browser_cluster/jobs/dom_exploration/event_trigger.rb +1 -1
  227. data/lib/arachni/browser_cluster/jobs/dom_exploration/event_trigger/result.rb +1 -1
  228. data/lib/arachni/browser_cluster/jobs/dom_exploration/result.rb +1 -1
  229. data/lib/arachni/browser_cluster/jobs/taint_trace.rb +1 -1
  230. data/lib/arachni/browser_cluster/jobs/taint_trace/event_trigger.rb +1 -1
  231. data/lib/arachni/browser_cluster/jobs/taint_trace/event_trigger/result.rb +1 -1
  232. data/lib/arachni/browser_cluster/jobs/taint_trace/result.rb +1 -1
  233. data/lib/arachni/browser_cluster/worker.rb +109 -84
  234. data/lib/arachni/check.rb +1 -1
  235. data/lib/arachni/check/auditor.rb +137 -93
  236. data/lib/arachni/check/base.rb +1 -1
  237. data/lib/arachni/check/manager.rb +1 -1
  238. data/lib/arachni/component.rb +1 -1
  239. data/lib/arachni/component/base.rb +3 -1
  240. data/lib/arachni/component/manager.rb +1 -1
  241. data/lib/arachni/component/options.rb +1 -1
  242. data/lib/arachni/component/options/address.rb +1 -1
  243. data/lib/arachni/component/options/base.rb +1 -1
  244. data/lib/arachni/component/options/bool.rb +1 -1
  245. data/lib/arachni/component/options/float.rb +1 -1
  246. data/lib/arachni/component/options/int.rb +1 -1
  247. data/lib/arachni/component/options/multiple_choice.rb +1 -1
  248. data/lib/arachni/component/options/object.rb +1 -1
  249. data/lib/arachni/component/options/path.rb +1 -1
  250. data/lib/arachni/component/options/port.rb +1 -1
  251. data/lib/arachni/component/options/string.rb +1 -1
  252. data/lib/arachni/component/options/url.rb +1 -1
  253. data/lib/arachni/component/output.rb +8 -2
  254. data/lib/arachni/component/utilities.rb +1 -1
  255. data/lib/arachni/data.rb +1 -1
  256. data/lib/arachni/data/framework.rb +2 -1
  257. data/lib/arachni/data/framework/rpc.rb +1 -1
  258. data/lib/arachni/data/issues.rb +1 -1
  259. data/lib/arachni/data/plugins.rb +1 -1
  260. data/lib/arachni/data/session.rb +1 -1
  261. data/lib/arachni/element/base.rb +1 -1
  262. data/lib/arachni/element/body.rb +1 -1
  263. data/lib/arachni/element/capabilities/analyzable.rb +1 -1
  264. data/lib/arachni/element/capabilities/analyzable/differential.rb +142 -175
  265. data/lib/arachni/element/capabilities/analyzable/signature.rb +39 -17
  266. data/lib/arachni/element/capabilities/analyzable/timeout.rb +1 -1
  267. data/lib/arachni/element/capabilities/auditable.rb +2 -8
  268. data/lib/arachni/element/capabilities/auditable/buffered.rb +92 -0
  269. data/lib/arachni/element/capabilities/auditable/line_buffered.rb +103 -0
  270. data/lib/arachni/element/capabilities/dom_only.rb +1 -1
  271. data/lib/arachni/element/capabilities/inputtable.rb +6 -2
  272. data/lib/arachni/element/capabilities/mutable.rb +1 -1
  273. data/lib/arachni/element/capabilities/refreshable.rb +1 -1
  274. data/lib/arachni/element/capabilities/submittable.rb +1 -1
  275. data/lib/arachni/element/capabilities/with_auditor.rb +1 -1
  276. data/lib/arachni/element/capabilities/with_auditor/output.rb +4 -3
  277. data/lib/arachni/element/capabilities/with_dom.rb +1 -1
  278. data/lib/arachni/element/capabilities/with_node.rb +3 -3
  279. data/lib/arachni/element/capabilities/with_scope.rb +1 -1
  280. data/lib/arachni/element/capabilities/with_scope/scope.rb +1 -1
  281. data/lib/arachni/element/capabilities/with_source.rb +2 -2
  282. data/lib/arachni/element/cookie.rb +49 -24
  283. data/lib/arachni/element/cookie/capabilities/inputtable.rb +1 -1
  284. data/lib/arachni/element/cookie/capabilities/mutable.rb +1 -1
  285. data/lib/arachni/element/cookie/capabilities/with_dom.rb +1 -1
  286. data/lib/arachni/element/cookie/dom.rb +1 -1
  287. data/lib/arachni/element/dom.rb +1 -1
  288. data/lib/arachni/element/dom/capabilities/auditable.rb +44 -3
  289. data/lib/arachni/element/dom/capabilities/inputtable.rb +1 -1
  290. data/lib/arachni/element/dom/capabilities/locatable.rb +1 -1
  291. data/lib/arachni/element/dom/capabilities/mutable.rb +7 -3
  292. data/lib/arachni/element/dom/capabilities/submittable.rb +51 -22
  293. data/lib/arachni/element/form.rb +21 -32
  294. data/lib/arachni/element/form/capabilities/auditable.rb +1 -1
  295. data/lib/arachni/element/form/capabilities/mutable.rb +16 -11
  296. data/lib/arachni/element/form/capabilities/submittable.rb +1 -1
  297. data/lib/arachni/element/form/capabilities/with_dom.rb +1 -1
  298. data/lib/arachni/element/form/dom.rb +1 -1
  299. data/lib/arachni/element/generic_dom.rb +1 -1
  300. data/lib/arachni/element/header.rb +3 -1
  301. data/lib/arachni/element/header/capabilities/inputtable.rb +1 -1
  302. data/lib/arachni/element/header/capabilities/mutable.rb +1 -1
  303. data/lib/arachni/element/json.rb +4 -8
  304. data/lib/arachni/element/json/capabilities/inputtable.rb +1 -1
  305. data/lib/arachni/element/json/capabilities/mutable.rb +1 -1
  306. data/lib/arachni/element/link.rb +11 -30
  307. data/lib/arachni/element/link/capabilities/auditable.rb +1 -1
  308. data/lib/arachni/element/link/capabilities/submittable.rb +1 -1
  309. data/lib/arachni/element/link/capabilities/with_dom.rb +1 -1
  310. data/lib/arachni/element/link/dom.rb +1 -1
  311. data/lib/arachni/element/link/dom/capabilities/submittable.rb +1 -1
  312. data/lib/arachni/element/link_template.rb +10 -19
  313. data/lib/arachni/element/link_template/capabilities/auditable.rb +1 -1
  314. data/lib/arachni/element/link_template/capabilities/inputtable.rb +1 -1
  315. data/lib/arachni/element/link_template/capabilities/with_dom.rb +1 -1
  316. data/lib/arachni/element/link_template/dom.rb +2 -2
  317. data/lib/arachni/element/link_template/dom/capabilities/submittable.rb +1 -1
  318. data/lib/arachni/element/path.rb +1 -1
  319. data/lib/arachni/element/server.rb +11 -11
  320. data/lib/arachni/element/ui_form.rb +5 -6
  321. data/lib/arachni/element/ui_form/dom.rb +1 -1
  322. data/lib/arachni/element/ui_input.rb +4 -6
  323. data/lib/arachni/element/ui_input/dom.rb +1 -1
  324. data/lib/arachni/element/xml.rb +3 -7
  325. data/lib/arachni/element/xml/capabilities/inputtable.rb +1 -1
  326. data/lib/arachni/element/xml/capabilities/mutable.rb +1 -1
  327. data/lib/arachni/element_filter.rb +1 -1
  328. data/lib/arachni/error.rb +1 -1
  329. data/lib/arachni/ethon/easy.rb +1 -1
  330. data/lib/arachni/framework.rb +1 -1
  331. data/lib/arachni/framework/parts/audit.rb +6 -1
  332. data/lib/arachni/framework/parts/browser.rb +14 -14
  333. data/lib/arachni/framework/parts/check.rb +1 -1
  334. data/lib/arachni/framework/parts/data.rb +1 -1
  335. data/lib/arachni/framework/parts/platform.rb +1 -1
  336. data/lib/arachni/framework/parts/plugin.rb +1 -1
  337. data/lib/arachni/framework/parts/report.rb +2 -2
  338. data/lib/arachni/framework/parts/scope.rb +1 -1
  339. data/lib/arachni/framework/parts/state.rb +1 -1
  340. data/lib/arachni/http.rb +1 -1
  341. data/lib/arachni/http/client.rb +32 -7
  342. data/lib/arachni/http/client/dynamic_404_handler.rb +74 -16
  343. data/lib/arachni/http/cookie_jar.rb +13 -8
  344. data/lib/arachni/http/headers.rb +11 -5
  345. data/lib/arachni/http/message.rb +9 -8
  346. data/lib/arachni/http/message/scope.rb +1 -1
  347. data/lib/arachni/http/proxy_server.rb +44 -11
  348. data/lib/arachni/http/proxy_server/connection.rb +113 -80
  349. data/lib/arachni/http/proxy_server/ssl_interceptor.rb +2 -1
  350. data/lib/arachni/http/proxy_server/tunnel.rb +4 -4
  351. data/lib/arachni/http/request.rb +236 -44
  352. data/lib/arachni/http/request/scope.rb +1 -1
  353. data/lib/arachni/http/response.rb +71 -8
  354. data/lib/arachni/http/response/scope.rb +1 -1
  355. data/lib/arachni/issue.rb +42 -14
  356. data/lib/arachni/issue/severity.rb +1 -1
  357. data/lib/arachni/issue/severity/base.rb +1 -1
  358. data/lib/arachni/option_group.rb +1 -1
  359. data/lib/arachni/option_groups.rb +1 -1
  360. data/lib/arachni/option_groups/audit.rb +1 -1
  361. data/lib/arachni/option_groups/browser_cluster.rb +6 -2
  362. data/lib/arachni/option_groups/datastore.rb +1 -1
  363. data/lib/arachni/option_groups/dispatcher.rb +1 -1
  364. data/lib/arachni/option_groups/http.rb +35 -6
  365. data/lib/arachni/option_groups/input.rb +1 -1
  366. data/lib/arachni/option_groups/output.rb +1 -1
  367. data/lib/arachni/option_groups/paths.rb +1 -1
  368. data/lib/arachni/option_groups/rpc.rb +1 -1
  369. data/lib/arachni/option_groups/scope.rb +13 -1
  370. data/lib/arachni/option_groups/session.rb +1 -1
  371. data/lib/arachni/option_groups/snapshot.rb +1 -1
  372. data/lib/arachni/options.rb +23 -4
  373. data/lib/arachni/page.rb +8 -6
  374. data/lib/arachni/page/dom.rb +46 -54
  375. data/lib/arachni/page/dom/transition.rb +5 -2
  376. data/lib/arachni/page/scope.rb +1 -1
  377. data/lib/arachni/parser.rb +157 -77
  378. data/lib/arachni/parser/document.rb +34 -0
  379. data/lib/arachni/parser/extractors/base.rb +48 -0
  380. data/lib/arachni/parser/nodes/base.rb +22 -0
  381. data/lib/arachni/parser/nodes/comment.rb +32 -0
  382. data/lib/arachni/parser/nodes/element.rb +48 -0
  383. data/lib/arachni/parser/nodes/element/with_attributes.rb +35 -0
  384. data/lib/arachni/parser/nodes/element/with_attributes/attributes.rb +31 -0
  385. data/lib/arachni/parser/nodes/text.rb +32 -0
  386. data/lib/arachni/parser/nodes/with_value.rb +29 -0
  387. data/lib/arachni/parser/sax.rb +75 -0
  388. data/lib/arachni/parser/with_children.rb +35 -0
  389. data/lib/arachni/parser/with_children/search.rb +92 -0
  390. data/lib/arachni/platform.rb +1 -1
  391. data/lib/arachni/platform/fingerprinter.rb +1 -1
  392. data/lib/arachni/platform/list.rb +1 -1
  393. data/lib/arachni/platform/manager.rb +2 -2
  394. data/lib/arachni/plugin.rb +1 -1
  395. data/lib/arachni/plugin/base.rb +2 -2
  396. data/lib/arachni/plugin/formatter.rb +1 -1
  397. data/lib/arachni/plugin/manager.rb +8 -5
  398. data/lib/arachni/processes.rb +1 -1
  399. data/lib/arachni/processes/dispatchers.rb +1 -1
  400. data/lib/arachni/processes/executables/browser.rb +0 -2
  401. data/lib/arachni/processes/helpers.rb +1 -1
  402. data/lib/arachni/processes/helpers/dispatchers.rb +1 -1
  403. data/lib/arachni/processes/helpers/instances.rb +1 -1
  404. data/lib/arachni/processes/helpers/processes.rb +1 -1
  405. data/lib/arachni/processes/instances.rb +1 -1
  406. data/lib/arachni/processes/manager.rb +10 -5
  407. data/lib/arachni/report.rb +8 -1
  408. data/lib/arachni/reporter.rb +1 -1
  409. data/lib/arachni/reporter/base.rb +1 -1
  410. data/lib/arachni/reporter/formatter_manager.rb +1 -1
  411. data/lib/arachni/reporter/manager.rb +1 -1
  412. data/lib/arachni/reporter/options.rb +1 -1
  413. data/lib/arachni/rest/server.rb +7 -1
  414. data/lib/arachni/rest/server/instance_helpers.rb +1 -1
  415. data/lib/arachni/rpc/client/base.rb +1 -1
  416. data/lib/arachni/rpc/client/dispatcher.rb +1 -1
  417. data/lib/arachni/rpc/client/instance.rb +1 -1
  418. data/lib/arachni/rpc/client/instance/framework.rb +1 -1
  419. data/lib/arachni/rpc/client/instance/service.rb +1 -1
  420. data/lib/arachni/rpc/serializer.rb +1 -1
  421. data/lib/arachni/rpc/server/active_options.rb +1 -1
  422. data/lib/arachni/rpc/server/base.rb +1 -1
  423. data/lib/arachni/rpc/server/check/manager.rb +1 -1
  424. data/lib/arachni/rpc/server/dispatcher.rb +1 -1
  425. data/lib/arachni/rpc/server/dispatcher/node.rb +1 -1
  426. data/lib/arachni/rpc/server/dispatcher/service.rb +1 -1
  427. data/lib/arachni/rpc/server/framework.rb +1 -1
  428. data/lib/arachni/rpc/server/framework/distributor.rb +1 -1
  429. data/lib/arachni/rpc/server/framework/master.rb +1 -1
  430. data/lib/arachni/rpc/server/framework/multi_instance.rb +1 -1
  431. data/lib/arachni/rpc/server/framework/slave.rb +1 -1
  432. data/lib/arachni/rpc/server/instance.rb +1 -1
  433. data/lib/arachni/rpc/server/output.rb +1 -1
  434. data/lib/arachni/rpc/server/plugin/manager.rb +1 -1
  435. data/lib/arachni/ruby.rb +1 -1
  436. data/lib/arachni/ruby/array.rb +1 -1
  437. data/lib/arachni/ruby/hash.rb +1 -1
  438. data/lib/arachni/ruby/object.rb +1 -1
  439. data/lib/arachni/ruby/set.rb +1 -1
  440. data/lib/arachni/ruby/string.rb +9 -5
  441. data/lib/arachni/ruby/webrick.rb +1 -1
  442. data/lib/arachni/ruby/webrick/cookie.rb +1 -1
  443. data/lib/arachni/ruby/webrick/httprequest.rb +1 -1
  444. data/lib/arachni/scope.rb +1 -1
  445. data/lib/arachni/selenium/webdriver/element.rb +4 -4
  446. data/lib/arachni/selenium/webdriver/remote/typhoeus.rb +69 -0
  447. data/lib/arachni/session.rb +32 -13
  448. data/lib/arachni/snapshot.rb +1 -1
  449. data/lib/arachni/state.rb +1 -1
  450. data/lib/arachni/state/audit.rb +1 -1
  451. data/lib/arachni/state/element_filter.rb +1 -1
  452. data/lib/arachni/state/framework.rb +1 -1
  453. data/lib/arachni/state/framework/rpc.rb +1 -1
  454. data/lib/arachni/state/http.rb +2 -2
  455. data/lib/arachni/state/options.rb +1 -1
  456. data/lib/arachni/state/plugins.rb +1 -1
  457. data/lib/arachni/support.rb +1 -1
  458. data/lib/arachni/support/buffer.rb +1 -1
  459. data/lib/arachni/support/buffer/autoflush.rb +1 -1
  460. data/lib/arachni/support/buffer/base.rb +1 -1
  461. data/lib/arachni/support/cache.rb +1 -1
  462. data/lib/arachni/support/cache/base.rb +1 -1
  463. data/lib/arachni/support/cache/least_cost_replacement.rb +1 -1
  464. data/lib/arachni/support/cache/least_recently_pushed.rb +1 -1
  465. data/lib/arachni/support/cache/least_recently_used.rb +1 -1
  466. data/lib/arachni/support/cache/preference.rb +1 -1
  467. data/lib/arachni/support/cache/random_replacement.rb +1 -1
  468. data/lib/arachni/support/crypto.rb +1 -1
  469. data/lib/arachni/support/crypto/rsa_aes_cbc.rb +1 -1
  470. data/lib/arachni/support/database.rb +1 -1
  471. data/lib/arachni/support/database/base.rb +1 -1
  472. data/lib/arachni/support/database/hash.rb +1 -1
  473. data/lib/arachni/support/database/queue.rb +1 -1
  474. data/lib/arachni/support/glob.rb +1 -1
  475. data/lib/arachni/support/lookup.rb +1 -1
  476. data/lib/arachni/support/lookup/base.rb +1 -1
  477. data/lib/arachni/support/lookup/hash_set.rb +1 -1
  478. data/lib/arachni/support/lookup/moolb.rb +1 -1
  479. data/lib/arachni/support/mixins.rb +1 -1
  480. data/lib/arachni/support/mixins/observable.rb +1 -1
  481. data/lib/arachni/support/mixins/terminal.rb +1 -1
  482. data/lib/arachni/support/profiler.rb +52 -13
  483. data/lib/arachni/support/signature.rb +18 -6
  484. data/lib/arachni/trainer.rb +55 -39
  485. data/lib/arachni/ui/foo/output.rb +1 -1
  486. data/lib/arachni/uri.rb +132 -103
  487. data/lib/arachni/uri/scope.rb +15 -13
  488. data/lib/arachni/utilities.rb +10 -10
  489. data/lib/arachni/version.rb +1 -1
  490. data/lib/version +1 -1
  491. data/logs/error-11897.log +2006 -0
  492. data/logs/error-3855.log +382 -0
  493. data/spec/arachni/browser/element_locator_spec.rb +42 -18
  494. data/spec/arachni/browser/javascript/dom_monitor_spec.rb +214 -63
  495. data/spec/arachni/browser/javascript/polyfills_spec.rb +0 -15
  496. data/spec/arachni/browser/javascript/taint_tracer_spec.rb +68 -121
  497. data/spec/arachni/browser/javascript_spec.rb +92 -51
  498. data/spec/arachni/browser_cluster/job_spec.rb +23 -8
  499. data/spec/arachni/browser_cluster/jobs/dom_exploration_spec.rb +6 -1
  500. data/spec/arachni/browser_cluster/worker_spec.rb +31 -57
  501. data/spec/arachni/browser_cluster_spec.rb +124 -43
  502. data/spec/arachni/browser_spec.rb +352 -312
  503. data/spec/arachni/check/auditor_spec.rb +118 -33
  504. data/spec/arachni/element/capabilities/analyzable/signature_spec.rb +46 -3
  505. data/spec/arachni/element/cookie/dom_spec.rb +1 -1
  506. data/spec/arachni/element/cookie_spec.rb +158 -63
  507. data/spec/arachni/element/form/dom_spec.rb +1 -1
  508. data/spec/arachni/element/form_spec.rb +101 -54
  509. data/spec/arachni/element/header_spec.rb +3 -1
  510. data/spec/arachni/element/json_spec.rb +2 -0
  511. data/spec/arachni/element/link/dom_spec.rb +2 -2
  512. data/spec/arachni/element/link_spec.rb +46 -15
  513. data/spec/arachni/element/link_template/dom_spec.rb +1 -1
  514. data/spec/arachni/element/link_template_spec.rb +36 -12
  515. data/spec/arachni/element/server_spec.rb +22 -5
  516. data/spec/arachni/element/ui_form/dom_spec.rb +1 -1
  517. data/spec/arachni/element/ui_input/dom_spec.rb +1 -1
  518. data/spec/arachni/element/xml_spec.rb +5 -3
  519. data/spec/arachni/framework/parts/audit_spec.rb +2 -14
  520. data/spec/arachni/framework/parts/data_spec.rb +0 -6
  521. data/spec/arachni/http/client/dynamic_404_handlers_spec.rb +126 -0
  522. data/spec/arachni/http/client_spec.rb +82 -10
  523. data/spec/arachni/http/headers_spec.rb +59 -12
  524. data/spec/arachni/http/proxy_server_spec.rb +56 -25
  525. data/spec/arachni/http/request_spec.rb +379 -33
  526. data/spec/arachni/http/response_spec.rb +135 -7
  527. data/spec/arachni/issue_spec.rb +20 -1
  528. data/spec/arachni/option_groups/http_spec.rb +15 -0
  529. data/spec/arachni/option_groups/scope_spec.rb +26 -1
  530. data/spec/arachni/options_spec.rb +8 -1
  531. data/spec/arachni/page/dom_spec.rb +20 -6
  532. data/spec/arachni/page_spec.rb +5 -5
  533. data/spec/arachni/parser/document_spec.rb +49 -0
  534. data/spec/arachni/parser/nodes/comment_spec.rb +24 -0
  535. data/spec/arachni/parser/nodes/element/with_attributes/attributes_spec.rb +40 -0
  536. data/spec/arachni/parser/nodes/element/with_attributes_spec.rb +50 -0
  537. data/spec/arachni/parser/nodes/element_spec.rb +18 -0
  538. data/spec/arachni/parser/nodes/text_spec.rb +24 -0
  539. data/spec/arachni/parser/sax_spec.rb +88 -0
  540. data/spec/arachni/parser/with_children/search_spec.rb +146 -0
  541. data/spec/arachni/parser/with_children_spec.rb +37 -0
  542. data/spec/arachni/parser_spec.rb +166 -26
  543. data/spec/arachni/report_spec.rb +9 -2
  544. data/spec/arachni/rest/server_spec.rb +52 -6
  545. data/spec/arachni/rpc/server/active_options_spec.rb +1 -1
  546. data/spec/arachni/rpc/server/framework/distributor_spec.rb +6 -6
  547. data/spec/arachni/ruby/string_spec.rb +6 -0
  548. data/spec/arachni/session_spec.rb +69 -8
  549. data/spec/arachni/support/signature_spec.rb +58 -0
  550. data/spec/arachni/trainer_spec.rb +102 -21
  551. data/spec/arachni/uri_spec.rb +11 -8
  552. data/spec/arachni/utilities_spec.rb +3 -3
  553. data/spec/components/checks/active/csrf_spec.rb +1 -21
  554. data/spec/components/checks/active/path_traversal_spec.rb +12 -12
  555. data/spec/components/checks/active/sql_injection_spec.rb +10 -1
  556. data/spec/components/checks/active/unvalidated_redirect_spec.rb +6 -6
  557. data/spec/components/checks/active/xss_dom_script_context_spec.rb +1 -5
  558. data/spec/components/checks/active/xss_dom_spec.rb +2 -2
  559. data/spec/components/checks/active/xss_event_spec.rb +8 -2
  560. data/spec/components/checks/active/xss_script_context_spec.rb +5 -5
  561. data/spec/components/checks/active/xss_spec.rb +3 -3
  562. data/spec/components/checks/passive/backup_directories_spec.rb +3 -1
  563. data/spec/components/checks/passive/backup_files_spec.rb +8 -1
  564. data/spec/components/checks/passive/grep/insecure_cookies_spec.rb +2 -2
  565. data/spec/components/path_extractors/comments_spec.rb +3 -1
  566. data/spec/components/path_extractors/data_url_spec.rb +6 -2
  567. data/spec/components/path_extractors/links_spec.rb +1 -1
  568. data/spec/components/plugins/autologin_spec.rb +2 -2
  569. data/spec/components/plugins/webhook_notify_spec.rb +69 -0
  570. data/spec/spec_helper.rb +1 -1
  571. data/spec/support/factories/page/dom.rb +6 -0
  572. data/spec/support/factories/scan_report.rb +1 -0
  573. data/spec/support/factories/vector.rb +7 -3
  574. data/spec/support/fixtures/check_with_invalid_platforms/with_invalid_platforms.rb +1 -1
  575. data/spec/support/fixtures/checks/test.rb +1 -1
  576. data/spec/support/fixtures/checks/test2.rb +1 -1
  577. data/spec/support/fixtures/checks/test3.rb +1 -1
  578. data/spec/support/fixtures/cookies.txt +2 -2
  579. data/spec/support/fixtures/fingerprinters/test.rb +1 -1
  580. data/spec/support/fixtures/plugins/bad.rb +1 -1
  581. data/spec/support/fixtures/plugins/defaults/default.rb +1 -1
  582. data/spec/support/fixtures/plugins/distributable.rb +1 -1
  583. data/spec/support/fixtures/plugins/loop.rb +1 -1
  584. data/spec/support/fixtures/plugins/suspendable.rb +1 -1
  585. data/spec/support/fixtures/plugins/wait.rb +1 -1
  586. data/spec/support/fixtures/plugins/with_options.rb +1 -1
  587. data/spec/support/fixtures/plugins_with_priorities/p0.rb +1 -1
  588. data/spec/support/fixtures/plugins_with_priorities/p00.rb +1 -1
  589. data/spec/support/fixtures/plugins_with_priorities/p1.rb +1 -1
  590. data/spec/support/fixtures/plugins_with_priorities/p2.rb +1 -1
  591. data/spec/support/fixtures/plugins_with_priorities/p22.rb +1 -1
  592. data/spec/support/fixtures/plugins_with_priorities/p222.rb +1 -1
  593. data/spec/support/fixtures/plugins_with_priorities/p_nil.rb +1 -1
  594. data/spec/support/fixtures/plugins_with_priorities/p_nil2.rb +1 -1
  595. data/spec/support/fixtures/report.afr +0 -0
  596. data/spec/support/fixtures/reporters/base_spec/plugin_formatters/with_formatters/foobar.rb +1 -1
  597. data/spec/support/fixtures/reporters/base_spec/with_formatters.rb +1 -1
  598. data/spec/support/fixtures/reporters/base_spec/with_outfile.rb +1 -1
  599. data/spec/support/fixtures/reporters/base_spec/without_outfile.rb +1 -1
  600. data/spec/support/fixtures/reporters/manager_spec/afr.rb +1 -1
  601. data/spec/support/fixtures/reporters/manager_spec/error.rb +1 -1
  602. data/spec/support/fixtures/reporters/manager_spec/foo.rb +1 -1
  603. data/spec/support/fixtures/run_check/body.rb +1 -1
  604. data/spec/support/fixtures/run_check/cookies.rb +1 -1
  605. data/spec/support/fixtures/run_check/empty.rb +1 -1
  606. data/spec/support/fixtures/run_check/flch.rb +1 -1
  607. data/spec/support/fixtures/run_check/forms.rb +1 -1
  608. data/spec/support/fixtures/run_check/headers.rb +1 -1
  609. data/spec/support/fixtures/run_check/links.rb +1 -1
  610. data/spec/support/fixtures/run_check/nil.rb +1 -1
  611. data/spec/support/fixtures/run_check/path.rb +1 -1
  612. data/spec/support/fixtures/run_check/server.rb +1 -1
  613. data/spec/support/fixtures/signature_check/signature.rb +1 -1
  614. data/spec/support/fixtures/wait_check/wait.rb +1 -1
  615. data/spec/support/helpers/browser_cluster/jobs/taint_tracer.rb +0 -3
  616. data/spec/support/helpers/framework.rb +1 -1
  617. data/spec/support/helpers/misc.rb +1 -1
  618. data/spec/support/helpers/paths.rb +1 -1
  619. data/spec/support/helpers/requires.rb +1 -1
  620. data/spec/support/helpers/resets.rb +1 -1
  621. data/spec/support/helpers/web_server.rb +1 -1
  622. data/spec/support/lib/factory.rb +1 -1
  623. data/spec/support/lib/web_server_client.rb +1 -1
  624. data/spec/support/lib/web_server_dispatcher.rb +1 -1
  625. data/spec/support/lib/web_server_manager.rb +4 -2
  626. data/spec/support/logs/Dispatcher - 1024-31864.log +10 -0
  627. data/spec/support/logs/Dispatcher - 1047-41465.log +10 -0
  628. data/spec/support/logs/Dispatcher - 1274-60799.log +64 -0
  629. data/spec/support/logs/Dispatcher - 1295-1058.log +44 -0
  630. data/spec/support/logs/Dispatcher - 1313-27076.log +40 -0
  631. data/spec/support/logs/Dispatcher - 1332-17127.log +35 -0
  632. data/spec/support/logs/Dispatcher - 1350-7351.log +29 -0
  633. data/spec/support/logs/Dispatcher - 1368-38528.log +22 -0
  634. data/spec/support/logs/Dispatcher - 1386-17419.log +14 -0
  635. data/spec/support/logs/Dispatcher - 31030-26156.log +10 -0
  636. data/spec/support/logs/Dispatcher - 321-27189.log +12 -0
  637. data/spec/support/logs/Dispatcher - 32353-50061.log +20 -0
  638. data/spec/support/logs/Dispatcher - 32450-61574.log +10 -0
  639. data/spec/support/logs/Dispatcher - 32470-53874.log +20 -0
  640. data/spec/support/logs/Dispatcher - 32491-10523.log +18 -0
  641. data/spec/support/logs/Dispatcher - 32509-8583.log +14 -0
  642. data/spec/support/logs/Dispatcher - 32536-21209.log +10 -0
  643. data/spec/support/logs/Dispatcher - 32556-53881.log +10 -0
  644. data/spec/support/logs/Dispatcher - 32579-49083.log +50 -0
  645. data/spec/support/logs/Dispatcher - 32761-20025.log +12 -0
  646. data/spec/support/logs/Dispatcher - 347-17512.log +12 -0
  647. data/spec/support/logs/Dispatcher - 3489-43230.log +24 -0
  648. data/spec/support/logs/Dispatcher - 3524-57459.log +26 -0
  649. data/spec/support/logs/Dispatcher - 3559-21544.log +20 -0
  650. data/spec/support/logs/Dispatcher - 3764-33844.log +25 -0
  651. data/spec/support/logs/Dispatcher - 3798-45350.log +26 -0
  652. data/spec/support/logs/Dispatcher - 382-15725.log +12 -0
  653. data/spec/support/logs/Dispatcher - 3836-6205.log +21 -0
  654. data/spec/support/logs/Dispatcher - 4112-45433.log +22 -0
  655. data/spec/support/logs/Dispatcher - 4148-53510.log +26 -0
  656. data/spec/support/logs/Dispatcher - 415-29873.log +14 -0
  657. data/spec/support/logs/Dispatcher - 4185-29736.log +18 -0
  658. data/spec/support/logs/Dispatcher - 4268-60912.log +25 -0
  659. data/spec/support/logs/Dispatcher - 4303-39372.log +26 -0
  660. data/spec/support/logs/Dispatcher - 4342-42190.log +21 -0
  661. data/spec/support/logs/Dispatcher - 463-55220.log +26 -0
  662. data/spec/support/logs/Dispatcher - 4649-12104.log +22 -0
  663. data/spec/support/logs/Dispatcher - 4683-32355.log +26 -0
  664. data/spec/support/logs/Dispatcher - 4724-41636.log +18 -0
  665. data/spec/support/logs/Dispatcher - 4881-57692.log +22 -0
  666. data/spec/support/logs/Dispatcher - 4961-64665.log +26 -0
  667. data/spec/support/logs/Dispatcher - 502-8742.log +25 -0
  668. data/spec/support/logs/Dispatcher - 5052-61726.log +18 -0
  669. data/spec/support/logs/Dispatcher - 536-15972.log +22 -0
  670. data/spec/support/logs/Dispatcher - 620-2220.log +20 -0
  671. data/spec/support/logs/Dispatcher - 638-17826.log +18 -0
  672. data/spec/support/logs/Dispatcher - 656-23967.log +16 -0
  673. data/spec/support/logs/Dispatcher - 700-15701.log +12 -0
  674. data/spec/support/logs/Dispatcher - 726-6080.log +10 -0
  675. data/spec/support/logs/Dispatcher - 749-56590.log +18 -0
  676. data/spec/support/logs/Dispatcher - 807-19073.log +18 -0
  677. data/spec/support/logs/Dispatcher - 871-8764.log +10 -0
  678. data/spec/support/logs/Dispatcher - 898-21496.log +12 -0
  679. data/spec/support/logs/Dispatcher - 933-64070.log +12 -0
  680. data/spec/support/logs/Instance - 1577-32284.error.log +151 -0
  681. data/spec/support/logs/Instance - 1625-58174.error.log +154 -0
  682. data/spec/support/logs/Instance - 2727-57968.error.log +151 -0
  683. data/spec/support/logs/Instance - 2898-20648.error.log +303 -0
  684. data/spec/support/logs/Instance - 2901-30845.error.log +429 -0
  685. data/spec/support/logs/Instance - 31185-37600.error.log +174 -0
  686. data/spec/support/logs/Instance - 3319-20111.error.log +175 -0
  687. data/spec/support/logs/error-3855.log +5132 -0
  688. data/spec/support/servers/arachni/browser.rb +275 -4
  689. data/spec/support/servers/arachni/browser/javascript/dom_monitor.rb +48 -0
  690. data/spec/support/servers/arachni/browser/javascript/taint_tracer.rb +15 -3
  691. data/spec/support/servers/arachni/check/auditor.rb +8 -0
  692. data/spec/support/servers/arachni/element/cookie.rb +34 -0
  693. data/spec/support/servers/arachni/element/form.rb +34 -0
  694. data/spec/support/servers/arachni/element/header.rb +36 -1
  695. data/spec/support/servers/arachni/element/json.rb +33 -0
  696. data/spec/support/servers/arachni/element/link.rb +33 -1
  697. data/spec/support/servers/arachni/element/link_template.rb +37 -5
  698. data/spec/support/servers/arachni/element/xml.rb +33 -0
  699. data/spec/support/servers/arachni/http/client.rb +43 -4
  700. data/spec/support/servers/arachni/http/client/dynamic_404_handler.rb +36 -0
  701. data/spec/support/servers/arachni/http/client/dynamic_404_handler_redirect_1.rb +18 -0
  702. data/spec/support/servers/arachni/http/client/dynamic_404_handler_redirect_2.rb +11 -0
  703. data/spec/support/servers/arachni/http/proxy_server.rb +12 -0
  704. data/spec/support/servers/arachni/session.rb +24 -1
  705. data/spec/support/servers/checks/active/csrf.rb +0 -76
  706. data/spec/support/servers/checks/active/sql_injection/java +2 -0
  707. data/spec/support/servers/checks/active/unvalidated_redirect.rb +81 -0
  708. data/spec/support/servers/checks/active/xss_event.rb +1 -1
  709. data/spec/support/servers/checks/passive/backup_files.rb +20 -1
  710. data/spec/support/servers/checks/passive/grep/cookie_set_for_parent_domain.rb +3 -5
  711. data/spec/support/servers/checks/passive/grep/insecure_cookies_https.rb +9 -0
  712. data/spec/support/servers/plugins/autologin.rb +17 -1
  713. data/spec/support/servers/plugins/webhook_notify.rb +9 -0
  714. data/spec/support/shared/element/capabilities/auditable.rb +26 -32
  715. data/spec/support/shared/element/capabilities/auditable/buffered.rb +791 -0
  716. data/spec/support/shared/element/capabilities/auditable/line_buffered.rb +797 -0
  717. data/spec/support/shared/element/capabilities/inputtable.rb +26 -0
  718. data/spec/support/shared/element/capabilities/with_node.rb +2 -2
  719. data/spec/support/shared/element/dom/submittable.rb +10 -10
  720. data/spec/support/shared/path_extractor.rb +17 -5
  721. data/ui/cli/framework.rb +24 -4
  722. data/ui/cli/framework/option_parser.rb +35 -6
  723. data/ui/cli/option_parser.rb +1 -1
  724. data/ui/cli/output.rb +10 -3
  725. data/ui/cli/reporter.rb +1 -1
  726. data/ui/cli/reporter/option_parser.rb +1 -1
  727. data/ui/cli/reproduce.rb +228 -0
  728. data/ui/cli/reproduce/option_parser.rb +90 -0
  729. data/ui/cli/rest/server.rb +1 -1
  730. data/ui/cli/rest/server/option_parser.rb +1 -1
  731. data/ui/cli/restored_framework.rb +1 -1
  732. data/ui/cli/restored_framework/option_parser.rb +1 -1
  733. data/ui/cli/rpc/client/dispatcher_monitor.rb +9 -11
  734. data/ui/cli/rpc/client/dispatcher_monitor/option_parser.rb +1 -1
  735. data/ui/cli/rpc/client/instance.rb +1 -1
  736. data/ui/cli/rpc/client/local.rb +1 -1
  737. data/ui/cli/rpc/client/local/option_parser.rb +1 -1
  738. data/ui/cli/rpc/client/remote.rb +1 -1
  739. data/ui/cli/rpc/client/remote/option_parser.rb +1 -1
  740. data/ui/cli/rpc/server/dispatcher.rb +1 -1
  741. data/ui/cli/rpc/server/dispatcher/option_parser.rb +1 -1
  742. data/ui/cli/utilities.rb +1 -1
  743. metadata +253 -49
  744. data/ACKNOWLEDGMENTS.md +0 -21
  745. data/AUTHORS.md +0 -3
  746. data/CONTRIBUTORS.md +0 -22
@@ -5,6 +5,7 @@
5
5
  <xs:complexType>
6
6
  <xs:all>
7
7
  <xs:element name="version" type="xs:string"/>
8
+ <xs:element name="seed" type="xs:string"/>
8
9
  <xs:element name="start_datetime" type="xs:dateTime" />
9
10
  <xs:element name="finish_datetime" type="xs:dateTime"/>
10
11
  <xs:element name="sitemap" type="sitemap"/>
@@ -52,6 +53,7 @@
52
53
  <xs:element name="general" type="plugin_metrics_results_general"/>
53
54
  <xs:element name="scan" type="plugin_metrics_results_scan"/>
54
55
  <xs:element name="http" type="plugin_metrics_results_http"/>
56
+ <xs:element name="browser_cluster" minOccurs="0" type="plugin_metrics_results_browser_cluster"/>
55
57
  <xs:element name="resource" type="plugin_metrics_results_resource"/>
56
58
  <xs:element name="element" type="plugin_metrics_results_element"/>
57
59
  <xs:element name="dom" type="plugin_metrics_results_dom"/>
@@ -75,20 +77,33 @@
75
77
  </xs:all>
76
78
  </xs:complexType>
77
79
 
80
+ <xs:complexType name="plugin_metrics_results_browser_cluster">
81
+ <xs:all>
82
+ <xs:element name="seconds_per_job" type="xs:float"/>
83
+ <xs:element name="total_job_time" type="xs:float"/>
84
+ <xs:element name="job_count" type="xs:integer"/>
85
+ <xs:element name="job_time_outs" type="xs:integer"/>
86
+ </xs:all>
87
+ </xs:complexType>
88
+
78
89
  <xs:complexType name="plugin_metrics_results_http">
79
90
  <xs:all>
80
- <xs:element name="requests" type="xs:integer"/>
81
- <xs:element name="response_time_min" type="xs:float"/>
82
- <xs:element name="response_time_max" type="xs:float"/>
83
- <xs:element name="response_time_average" type="xs:float"/>
91
+ <xs:element name="requests" minOccurs="0" type="xs:integer"/>
92
+
93
+ <xs:element name="request_time_outs" minOccurs="0" type="xs:integer"/>
94
+ <xs:element name="request_size_min" minOccurs="0" type="xs:float"/>
95
+ <xs:element name="request_size_max" minOccurs="0" type="xs:float"/>
96
+ <xs:element name="request_size_average" minOccurs="0" type="xs:float"/>
97
+
98
+ <xs:element name="response_time_min" minOccurs="0" type="xs:float"/>
99
+ <xs:element name="response_time_max" minOccurs="0" type="xs:float"/>
100
+ <xs:element name="response_time_average" minOccurs="0" type="xs:float"/>
84
101
 
85
- <xs:element name="response_size_min" type="xs:float"/>
86
- <xs:element name="response_size_max" type="xs:float"/>
87
- <xs:element name="response_size_average" type="xs:float"/>
102
+ <xs:element name="responses_per_second" minOccurs="0" type="xs:float"/>
88
103
 
89
- <xs:element name="request_size_min" type="xs:float"/>
90
- <xs:element name="request_size_max" type="xs:float"/>
91
- <xs:element name="request_size_average" type="xs:float"/>
104
+ <xs:element name="response_size_min" minOccurs="0" type="xs:float"/>
105
+ <xs:element name="response_size_max" minOccurs="0" type="xs:float"/>
106
+ <xs:element name="response_size_average" minOccurs="0" type="xs:float"/>
92
107
  </xs:all>
93
108
  </xs:complexType>
94
109
 
@@ -695,7 +710,7 @@
695
710
  <xs:complexType name="stackframe">
696
711
  <xs:all>
697
712
  <xs:element name="function" type="function"/>
698
- <xs:element name="line" type="xs:integer"/>
713
+ <xs:element name="line" type="xs:integer" nillable="true"/>
699
714
  <xs:element name="url" type="xs:string"/>
700
715
  </xs:all>
701
716
  </xs:complexType>
@@ -714,7 +729,7 @@
714
729
 
715
730
  <xs:complexType name="headers">
716
731
  <xs:sequence>
717
- <xs:element name="header" type="input"
732
+ <xs:element name="header" type="header"
718
733
  minOccurs="0" maxOccurs="unbounded"/>
719
734
  </xs:sequence>
720
735
  </xs:complexType>
@@ -726,7 +741,7 @@
726
741
 
727
742
  <xs:complexType name="parameters">
728
743
  <xs:sequence>
729
- <xs:element name="parameter" type="input"
744
+ <xs:element name="parameter" type="parameter"
730
745
  minOccurs="0" maxOccurs="unbounded"/>
731
746
  </xs:sequence>
732
747
  </xs:complexType>
@@ -1,5 +1,5 @@
1
1
  =begin
2
- Copyright 2010-2016 Tasos Laskos <tasos.laskos@arachni-scanner.com>
2
+ Copyright 2010-2017 Sarosys LLC <http://www.sarosys.com>
3
3
 
4
4
  This file is part of the Arachni Framework project and is subject to
5
5
  redistribution and commercial restrictions. Please see the Arachni Framework
@@ -1,5 +1,5 @@
1
1
  =begin
2
- Copyright 2010-2016 Tasos Laskos <tasos.laskos@arachni-scanner.com>
2
+ Copyright 2010-2017 Sarosys LLC <http://www.sarosys.com>
3
3
 
4
4
  This file is part of the Arachni Framework project and is subject to
5
5
  redistribution and commercial restrictions. Please see the Arachni Framework
@@ -1,5 +1,5 @@
1
1
  =begin
2
- Copyright 2010-2016 Tasos Laskos <tasos.laskos@arachni-scanner.com>
2
+ Copyright 2010-2017 Sarosys LLC <http://www.sarosys.com>
3
3
 
4
4
  This file is part of the Arachni Framework project and is subject to
5
5
  redistribution and commercial restrictions. Please see the Arachni Framework
@@ -1,5 +1,5 @@
1
1
  =begin
2
- Copyright 2010-2016 Tasos Laskos <tasos.laskos@arachni-scanner.com>
2
+ Copyright 2010-2017 Sarosys LLC <http://www.sarosys.com>
3
3
 
4
4
  This file is part of the Arachni Framework project and is subject to
5
5
  redistribution and commercial restrictions. Please see the Arachni Framework
@@ -15,7 +15,7 @@ require_relative 'browser/javascript'
15
15
 
16
16
  module Arachni
17
17
 
18
- # @note Depends on PhantomJS 1.9.2.
18
+ # @note Depends on PhantomJS 2.1.1.
19
19
  #
20
20
  # Real browser driver providing DOM/JS/AJAX support.
21
21
  #
@@ -60,15 +60,12 @@ class Browser
60
60
  end
61
61
 
62
62
  # How much time to wait for the PhantomJS process to spawn before respawning.
63
- PHANTOMJS_SPAWN_TIMEOUT = 4
63
+ BROWSER_SPAWN_TIMEOUT = 60
64
64
 
65
65
  # How much time to wait for a targeted HTML element to appear on the page
66
66
  # after the page is loaded.
67
67
  ELEMENT_APPEARANCE_TIMEOUT = 5
68
68
 
69
- # Let the browser take as long as it needs to complete an operation.
70
- WATIR_COM_TIMEOUT = 3600 # 1 hour.
71
-
72
69
  ASSET_EXTENSIONS = Set.new(%w( css js jpg jpeg png gif json ))
73
70
 
74
71
  INPUT_EVENTS = Set.new([
@@ -79,12 +76,16 @@ class Browser
79
76
  ])
80
77
 
81
78
  ASSET_EXTRACTORS = [
82
- /<\s*link.*?href=['"](.*?)['"].*?>/im,
83
- /<\s*script.*?src=['"](.*?)['"].*?>/im,
84
- /<\s*img.*?src=['"](.*?)['"].*?>/im,
85
- /<\s*input.*?src=['"](.*?)['"].*?>/im,
79
+ /<\s*link.*?href=\s*['"]?(.*?)?['"]?[\s>]/im,
80
+ /src\s*=\s*['"]?(.*?)?['"]?[\s>]/i,
86
81
  ]
87
82
 
83
+ # Unfortunately, we can't expose the HTTP user-agent for client-side
84
+ # stuff, because Selenium needs to know that we're using a Webkit-based
85
+ # browser in order to use the right JS code to trigger events etc.
86
+ USER_AGENT = 'Mozilla/5.0 AppleWebKit/538.1 (KHTML, like Gecko) ' <<
87
+ "Arachni/#{Arachni::VERSION} Safari/538.1"
88
+
88
89
  # @return [Array<Page::DOM::Transition>]
89
90
  attr_reader :transitions
90
91
 
@@ -92,6 +93,8 @@ class Browser
92
93
  # Preloaded resources, by URL.
93
94
  attr_reader :preloads
94
95
 
96
+ attr_reader :proxy
97
+
95
98
  # @return [Watir::Browser]
96
99
  # Watir driver interface.
97
100
  attr_reader :watir
@@ -179,25 +182,9 @@ class Browser
179
182
  @width = options[:width] || 1600
180
183
  @height = options[:height] || 1200
181
184
 
182
- @proxy = HTTP::ProxyServer.new(
183
- concurrency: @options[:concurrency],
184
- address: '127.0.0.1',
185
- request_handler: proc do |request, response|
186
- exception_jail { request_handler( request, response ) }
187
- end,
188
- response_handler: proc do |request, response|
189
- exception_jail { response_handler( request, response ) }
190
- end
191
- )
192
-
193
185
  @options[:store_pages] = true if !@options.include?( :store_pages )
194
186
 
195
- @proxy.start_async
196
-
197
- @watir = ::Watir::Browser.new( selenium )
198
-
199
- # User-controlled response cache, by URL.
200
- @cache = Support::Cache::LeastRecentlyUsed.new( 200 )
187
+ start_webdriver
201
188
 
202
189
  # User-controlled preloaded responses, by URL.
203
190
  @preloads = {}
@@ -216,7 +203,6 @@ class Browser
216
203
  # Captures HTTP::Response objects per URL for open windows.
217
204
  @window_responses = {}
218
205
 
219
- @elements_with_events = {}
220
206
 
221
207
  # Keeps track of resources which should be skipped -- like already fired
222
208
  # events and clicked links etc.
@@ -234,9 +220,7 @@ class Browser
234
220
 
235
221
  def clear_buffers
236
222
  synchronize do
237
- @elements_with_events.clear
238
223
  @preloads.clear
239
- @cache.clear
240
224
  @captured_pages.clear
241
225
  @page_snapshots.clear
242
226
  @page_snapshots_with_sinks.clear
@@ -262,9 +246,11 @@ class Browser
262
246
 
263
247
  case resource
264
248
  when String
249
+ @transitions = []
265
250
  goto resource, options
266
251
 
267
252
  when HTTP::Response
253
+ @transitions = []
268
254
  goto preload( resource ), options
269
255
 
270
256
  when Page
@@ -288,8 +274,7 @@ class Browser
288
274
  self
289
275
  end
290
276
 
291
- # @note The preloaded resource will be removed once used, for a persistent
292
- # cache use {#cache}.
277
+ # @note The preloaded resource will be removed once used.
293
278
  #
294
279
  # @param [HTTP::Response, Page] resource
295
280
  # Preloads a resource to be instantly available by URL via {#load}.
@@ -303,7 +288,7 @@ class Browser
303
288
 
304
289
  else
305
290
  fail Error::Load,
306
- "Can't load resource of type #{resource.class}."
291
+ "Can't preload resource of type #{resource.class}."
307
292
  end
308
293
 
309
294
  save_response( response ) if !response.url.include?( request_token )
@@ -312,28 +297,6 @@ class Browser
312
297
  response.url
313
298
  end
314
299
 
315
- # @param [HTTP::Response, Page] resource
316
- # Cache a resource in order to be instantly available by URL via {#load}.
317
- def cache( resource = nil )
318
- return @cache if !resource
319
-
320
- response = case resource
321
- when HTTP::Response
322
- resource
323
-
324
- when Page
325
- resource.response
326
-
327
- else
328
- fail Error::Load,
329
- "Can't load resource of type #{resource.class}."
330
- end
331
-
332
- save_response response
333
- @cache[response.url] = response
334
- response.url
335
- end
336
-
337
300
  # @param [String] url
338
301
  # Loads the given URL in the browser.
339
302
  # @param [Hash] options
@@ -383,7 +346,7 @@ class Browser
383
346
 
384
347
  print_info "#{css.inspect} appeared for: #{url}"
385
348
  rescue Selenium::WebDriver::Error::TimeOutError
386
- print_bad "#{css.inspect} did not appeared for: #{url}"
349
+ print_bad "#{css.inspect} did not appear for: #{url}"
387
350
  end
388
351
 
389
352
  end
@@ -406,25 +369,36 @@ class Browser
406
369
  end
407
370
 
408
371
  def wait_till_ready
409
- print_debug_level_2 'Waiting for custom JS...'
410
372
  @javascript.wait_till_ready
411
- print_debug_level_2 '...done.'
412
-
413
373
  wait_for_timers
414
-
415
374
  wait_for_pending_requests
416
375
  end
417
376
 
418
377
  def shutdown
419
- begin
420
- watir.close if alive?
421
- # Bucnh of dirrent errors can be raised here, Selenium, HTTP client,
422
- # don't try to catch them by type because we'll probably miss some.
423
- rescue
378
+ print_debug 'Shutting down...'
379
+
380
+ print_debug_level_2 'Killing process.'
381
+ if @kill_process
382
+ begin
383
+ @kill_process.close
384
+ rescue => e
385
+ print_debug_exception e
386
+ end
424
387
  end
425
388
 
426
- kill_process
389
+ print_debug_level_2 'Shutting down proxy...'
427
390
  @proxy.shutdown rescue Reactor::Error::NotRunning
391
+ print_debug_level_2 '...done.'
392
+
393
+ @proxy = nil
394
+ @kill_process = nil
395
+ @watir = nil
396
+ @selenium = nil
397
+ @lifeline_pid = nil
398
+ @browser_pid = nil
399
+ @browser_url = nil
400
+
401
+ print_debug '...shutdown complete.'
428
402
  end
429
403
 
430
404
  # @return [String]
@@ -436,7 +410,7 @@ class Browser
436
410
  # @return [String]
437
411
  # Current URL, as provided by the browser.
438
412
  def dom_url
439
- javascript.run( 'return document.URL;' )
413
+ @selenium.current_url
440
414
  end
441
415
 
442
416
  # Explores the browser's DOM tree and captures page snapshots for each
@@ -471,10 +445,10 @@ class Browser
471
445
  # @yield [ElementLocator,Array<Symbol>]
472
446
  # Element locator along with the element's applicable events along with
473
447
  # their handlers and attributes.
474
- def each_element_with_events
448
+ def each_element_with_events( whitelist = [])
475
449
  current_url = self.url
476
450
 
477
- javascript.dom_elements_with_events.each do |element|
451
+ javascript.each_dom_element_with_events whitelist do |element|
478
452
  tag_name = element['tag_name']
479
453
  attributes = element['attributes']
480
454
  events = element['events']
@@ -517,99 +491,6 @@ class Browser
517
491
  self
518
492
  end
519
493
 
520
- # @note The results will be cached, if direct access in necessary
521
- # use {#each_element_with_events}.
522
- #
523
- # @return [Hash<ElementLocator,Array<Symbol>>]
524
- # Element locator along with the element's applicable events along with
525
- # their handlers and attributes.
526
- def elements_with_events( clear_cache = false )
527
- current_url = self.url
528
-
529
- @elements_with_events.clear if clear_cache
530
-
531
- if @elements_with_events.include?( current_url )
532
- return @elements_with_events[current_url]
533
- end
534
-
535
- @elements_with_events.clear
536
- @elements_with_events[current_url] ||= {}
537
-
538
- each_element_with_events do |locator, events|
539
- @elements_with_events[current_url][locator] = events
540
- end
541
-
542
- @elements_with_events[current_url]
543
- end
544
-
545
- # @return [String]
546
- # Snapshot ID used to determine whether or not a page snapshot has already
547
- # been seen.
548
- #
549
- # Uses both elements and their DOM events and possible audit workload to
550
- # determine the ID, as page snapshots should be retained both when further
551
- # browser analysis can be performed and when new element audit workload
552
- # (but possibly without any DOM relevance) is available.
553
- def snapshot_id
554
- current_url = self.url
555
-
556
- id = Set.new
557
- javascript.dom_elements_with_events.each do |element|
558
- tag_name = element['tag_name']
559
- attributes = element['attributes']
560
- events = element['events']
561
- element_id = attributes['id'].to_s
562
-
563
- case tag_name
564
- when 'a'
565
- href = attributes['href'].to_s
566
- element_id << href
567
-
568
- if !href.empty?
569
- if href.downcase.start_with?( 'javascript:' )
570
- (events[:click] ||= []) << href
571
- else
572
- absolute = to_absolute( href, current_url )
573
- next if skip_path?( absolute )
574
-
575
- (events[:click] ||= []) << href
576
- end
577
- else
578
- (events[:click] ||= []) << current_url
579
- end
580
-
581
- when 'input', 'textarea', 'select'
582
- (events[:input] ||= []) << tag_name.to_sym
583
- element_id << attributes['name'].to_s
584
-
585
- when 'form'
586
- action = attributes['action'].to_s
587
- element_id << "#{action}#{attributes['name']}"
588
-
589
- if !action.empty?
590
- if action.downcase.start_with?( 'javascript:' )
591
- (events[:submit] ||= []) << action
592
- else
593
- absolute = to_absolute( action, current_url )
594
- if !skip_path?( absolute )
595
- (events[:submit] ||= []) << absolute
596
- end
597
- end
598
- else
599
- (events[:submit] ||= []) << current_url
600
- end
601
- end
602
-
603
- next if events.empty?
604
-
605
- id << "#{tag_name}:#{element_id}:#{events.keys.sort}".persistent_hash
606
- end
607
-
608
- id << [:cookies, cookies.map(&:name).sort].to_s.persistent_hash
609
-
610
- id.to_a.sort.map(&:to_s).join(':')
611
- end
612
-
613
494
  # Triggers all events on all elements (**once**) and captures
614
495
  # {#page_snapshots page snapshots}.
615
496
  #
@@ -617,14 +498,25 @@ class Browser
617
498
  # `self`
618
499
  def trigger_events
619
500
  dom = self.state
501
+ return self if !dom
502
+
503
+ url = normalize_url( dom.url )
620
504
 
621
- elements_with_events( true ).each do |locator, events|
622
- state = "#{locator.tag_name}:#{locator.attributes}:#{events.keys.sort}"
505
+ count = 1
506
+ each_element_with_events do |locator, events|
507
+ state = "#{url}:#{locator.tag_name}:#{locator.attributes}:#{events.keys.sort}"
623
508
  next if skip_state?( state )
624
509
  skip_state state
625
510
 
626
511
  events.each do |name, _|
512
+ if Options.scope.dom_event_limit_reached?( count )
513
+ print_debug "DOM event limit reached for: #{dom.url}"
514
+ next
515
+ end
516
+
627
517
  distribute_event( dom, locator, name.to_sym )
518
+
519
+ count += 1
628
520
  end
629
521
  end
630
522
 
@@ -654,13 +546,10 @@ class Browser
654
546
  # @param [Symbol] event
655
547
  # Event to trigger.
656
548
  def trigger_event( resource, element, event, restore = true )
657
- event = event.to_sym
658
549
  transition = fire_event( element, event )
659
550
 
660
551
  if !transition
661
- print_info "Could not trigger '#{event}' on '#{element}' because" <<
662
- ' the page has changed, capturing a new snapshot.'
663
- capture_snapshot
552
+ print_info "Could not trigger '#{event}' on: #{element}"
664
553
 
665
554
  if restore
666
555
  print_info 'Restoring page.'
@@ -729,15 +618,28 @@ class Browser
729
618
  transition = Page::DOM::Transition.new( locator, event, options ) do
730
619
  force = true
731
620
 
732
- # It's better to use the Watir helpers whenever possible instead
733
- # of firing events manually.
621
+ # It's better to use the helpers whenever possible instead of
622
+ # firing events manually.
734
623
  if tag_name == :form
735
624
  fill_in_form_inputs( element, options[:inputs] )
736
625
 
626
+ if event == :fill
627
+ force = false
628
+ end
629
+
737
630
  if event == :submit
738
631
  force = false
739
632
 
740
- element.submit
633
+ begin
634
+ element.find_elements( :css,
635
+ "input[type='submit'], button[type='submit']"
636
+ ).first.click
637
+ rescue => e
638
+ print_debug "No submit button, will trigger 'submit' event."
639
+ print_debug_exception e
640
+
641
+ element.submit
642
+ end
741
643
  end
742
644
 
743
645
  elsif event == :click
@@ -767,6 +669,11 @@ class Browser
767
669
  wait_for_pending_requests
768
670
  print_debug_level_2 "[done waiting for requests]: #{event} (#{options}) #{locator}"
769
671
 
672
+ # Maybe we switched to a different page, wait until the custom
673
+ # JS env has been put in place.
674
+ javascript.wait_till_ready
675
+ javascript.set_element_ids
676
+
770
677
  update_cookies
771
678
  end
772
679
 
@@ -784,7 +691,7 @@ class Browser
784
691
  transition
785
692
  rescue Selenium::WebDriver::Error::WebDriverError => e
786
693
 
787
- print_debug "Error when triggering event for: #{url}"
694
+ print_debug "Error when triggering event for: #{dom_url}"
788
695
  print_debug "-- '#{event}' on: #{opening_tag} -- #{locator.css}"
789
696
  print_debug
790
697
  print_debug_exception e
@@ -800,14 +707,19 @@ class Browser
800
707
  #
801
708
  # @param [Browser::ElementLocator] locator
802
709
  # @param [Symbol,String] event
803
- # @param [Bool] ret
804
- # Return JS result?
805
710
  # @param [Numeric] wait
806
711
  # Amount of time to wait (in seconds) after triggering the event.
807
- def fire_event_js( locator, event, ret: false, wait: 0.1 )
712
+ def fire_event_js( locator, event, wait: 0.1 )
808
713
  r = javascript.run <<-EOJS
809
714
  var element = document.querySelector( #{locator.css.inspect} );
810
- var event = document.createEvent( "Events" );
715
+
716
+ // Could not be found.
717
+ if( !element ) return false;
718
+
719
+ // Invisible.
720
+ if( element.offsetWidth <= 0 && element.offsetHeight <= 0 ) return false;
721
+
722
+ var event = document.createEvent( "Events" );
811
723
 
812
724
  event.initEvent( "#{event}", true, true );
813
725
 
@@ -819,10 +731,13 @@ class Browser
819
731
  event.keyCode = 0;
820
732
  event.charCode = 'a';
821
733
 
822
- #{'return' if ret} element.dispatchEvent( event );
734
+ element.dispatchEvent( event );
735
+
736
+ return true;
823
737
  EOJS
824
738
 
825
- sleep wait
739
+ sleep( wait ) if r
740
+
826
741
  r
827
742
  end
828
743
 
@@ -918,6 +833,7 @@ class Browser
918
833
  page = r.to_page
919
834
  page.body = source
920
835
  page.dom.url = d_url
836
+ page.dom.cookies = self.cookies
921
837
  page.dom.digest = @javascript.dom_digest
922
838
  page.dom.execution_flow_sinks = @javascript.execution_flow_sinks
923
839
  page.dom.data_flow_sinks = data_flow_sinks[@javascript.taint] || []
@@ -956,8 +872,22 @@ class Browser
956
872
 
957
873
  if Options.audit.cookie_doms?
958
874
  page.cookies.each do |cookie|
959
- next if data_flow_sinks.include?( cookie.name ) ||
960
- data_flow_sinks.include?( cookie.value )
875
+ if (sinks = data_flow_sinks[cookie.name] ||
876
+ data_flow_sinks[cookie.value])
877
+
878
+ # Don't be satisfied with just a taint match, make sure
879
+ # the full value is identical.
880
+ #
881
+ # For example, if a cookie has '1' as a name or value
882
+ # that's too generic and can match irrelevant data.
883
+ #
884
+ # The current approach isn't perfect of course, but it's
885
+ # the best we can do.
886
+ next if sinks.find do |sink|
887
+ sink.tainted_value == cookie.name ||
888
+ sink.tainted_value == cookie.value
889
+ end
890
+ end
961
891
 
962
892
  cookie.skip_dom = true
963
893
  end
@@ -987,7 +917,7 @@ class Browser
987
917
  # bother trying anything else.
988
918
  next if !response
989
919
 
990
- unique_id = self.snapshot_id
920
+ unique_id = javascript.dom_event_digest
991
921
  already_seen = skip_state?( unique_id )
992
922
  skip_state unique_id
993
923
 
@@ -1009,6 +939,13 @@ class Browser
1009
939
 
1010
940
  next if already_seen
1011
941
 
942
+ # Safegued against pages which generate an inf number of DOM
943
+ # states regardless of UI interactions.
944
+ transition_id ="#{page.dom.url}:#{page.dom.playable_transitions.map(&:hash)}"
945
+ transition_id_seen = skip_state?( transition_id )
946
+ skip_state transition_id
947
+ next if transition_id_seen
948
+
1012
949
  notify_on_new_page( page )
1013
950
 
1014
951
  if store_pages?
@@ -1111,9 +1048,10 @@ class Browser
1111
1048
  delay = load_delay
1112
1049
  return if !delay
1113
1050
 
1114
- print_debug_level_2 'Waiting for timers...'
1051
+ effective_delay = [Options.http.request_timeout, delay].min / 1000.0
1052
+ print_debug_level_2 "Waiting for max timer #{effective_delay}s (original was #{delay}ms)..."
1115
1053
 
1116
- sleep [Options.http.request_timeout, delay].min / 1000.0
1054
+ sleep effective_delay
1117
1055
 
1118
1056
  print_debug_level_2 '...done.'
1119
1057
  end
@@ -1125,7 +1063,7 @@ class Browser
1125
1063
  def response
1126
1064
  u = dom_url
1127
1065
 
1128
- if dom_url == 'about:blank'
1066
+ if u == 'about:blank'
1129
1067
  print_debug 'Blank page.'
1130
1068
  return
1131
1069
  end
@@ -1142,7 +1080,17 @@ class Browser
1142
1080
  if r
1143
1081
  print_debug "Origin server timed-out when requesting: #{u}"
1144
1082
  else
1145
- print_debug "Response never arrived: #{u}"
1083
+ print_debug "Response never arrived for: #{u}"
1084
+
1085
+ print_debug 'Available responses are:'
1086
+ @window_responses.each do |k, _|
1087
+ print_debug "-- #{k}"
1088
+ end
1089
+
1090
+ print_debug 'Tried:'
1091
+ print_debug "-- #{u}"
1092
+ print_debug "-- #{normalize_url( u )}"
1093
+ print_debug "-- #{normalize_watir_url( u )}"
1146
1094
  end
1147
1095
 
1148
1096
  nil
@@ -1153,8 +1101,10 @@ class Browser
1153
1101
  def selenium
1154
1102
  return @selenium if @selenium
1155
1103
 
1104
+ # For some weird reason the Typhoeus client is very slow for
1105
+ # PhantomJS 2.1.1 and causes a boatload of time-outs.
1156
1106
  client = Selenium::WebDriver::Remote::Http::Default.new
1157
- client.timeout = WATIR_COM_TIMEOUT
1107
+ client.timeout = Options.browser_cluster.job_timeout
1158
1108
 
1159
1109
  @selenium = Selenium::WebDriver.for(
1160
1110
  :remote,
@@ -1287,11 +1237,13 @@ class Browser
1287
1237
  done = false
1288
1238
  port = Utilities.available_port
1289
1239
 
1290
- print_debug "Attempt ##{i}, chose port number #{port}"
1240
+ start_proxy
1241
+
1242
+ print_debug_level_2 "Attempt ##{i}, chose port number #{port}"
1291
1243
 
1292
1244
  begin
1293
- with_timeout 10 do
1294
- print_debug "Spawning process: #{self.class.executable}"
1245
+ with_timeout BROWSER_SPAWN_TIMEOUT do
1246
+ print_debug_level_2 "Spawning process: #{self.class.executable}"
1295
1247
 
1296
1248
  r, w = IO.pipe
1297
1249
  ri, @kill_process = IO.pipe
@@ -1312,7 +1264,7 @@ class Browser
1312
1264
  w.close
1313
1265
  ri.close
1314
1266
 
1315
- print_debug 'Process spawned, waiting for it to boot-up...'
1267
+ print_debug_level_2 'Process spawned, waiting for WebDriver server...'
1316
1268
 
1317
1269
  # Wait for PhantomJS to initialize.
1318
1270
  while !output.include?( 'running on port' )
@@ -1326,7 +1278,7 @@ class Browser
1326
1278
 
1327
1279
  @browser_pid = output.scan( /^PID: (\d+)/ ).flatten.first.to_i
1328
1280
 
1329
- print_debug 'Boot-up complete.'
1281
+ print_debug_level_2 '...WebDriver server is up.'
1330
1282
  done = true
1331
1283
  end
1332
1284
  rescue Timeout::Error
@@ -1334,7 +1286,7 @@ class Browser
1334
1286
  end
1335
1287
 
1336
1288
  if !output.empty?
1337
- print_debug output
1289
+ print_debug_level_2 output
1338
1290
  end
1339
1291
 
1340
1292
  if done
@@ -1342,8 +1294,10 @@ class Browser
1342
1294
  break
1343
1295
  end
1344
1296
 
1345
- print_debug 'Killing process.'
1346
- kill_process
1297
+ print_debug_level_2 'Killing process.'
1298
+
1299
+ # Kill everything.
1300
+ shutdown
1347
1301
  end
1348
1302
 
1349
1303
  # Something went really bad, the browser couldn't be spawned even
@@ -1360,20 +1314,30 @@ class Browser
1360
1314
  @browser_url = "http://127.0.0.1:#{port}"
1361
1315
  end
1362
1316
 
1363
- def kill_process
1364
- if @kill_process
1365
- begin
1366
- @kill_process.close
1367
- rescue
1317
+ def start_proxy
1318
+ print_debug 'Booting up...'
1319
+
1320
+ print_debug_level_2 'Starting proxy...'
1321
+ @proxy = HTTP::ProxyServer.new(
1322
+ concurrency: @options[:concurrency],
1323
+ address: '127.0.0.1',
1324
+ request_handler: proc do |request, response|
1325
+ exception_jail { request_handler( request, response ) }
1326
+ end,
1327
+ response_handler: proc do |request, response|
1328
+ exception_jail { response_handler( request, response ) }
1368
1329
  end
1369
- end
1330
+ )
1331
+ @proxy.start_async
1332
+ print_debug_level_2 "... started proxy at: #{@proxy.url}"
1333
+ end
1370
1334
 
1371
- @kill_process = nil
1372
- @watir = nil
1373
- @selenium = nil
1374
- @lifeline_pid = nil
1375
- @browser_pid = nil
1376
- @browser_url = nil
1335
+ def start_webdriver
1336
+ print_debug_level_2 'Starting WebDriver...'
1337
+ @watir = ::Watir::Browser.new( selenium )
1338
+ print_debug_level_2 "... started WebDriver at: #{@browser_url}"
1339
+
1340
+ print_debug '...boot-up completed.'
1377
1341
  end
1378
1342
 
1379
1343
  def store_pages?
@@ -1397,12 +1361,33 @@ class Browser
1397
1361
  end
1398
1362
 
1399
1363
  def wait_for_pending_requests
1400
- print_debug_level_2 "Waiting for #{@proxy.pending_requests} requests to complete..."
1364
+ sleep 0.2
1365
+
1366
+ t = Time.now
1367
+ last_connections = []
1368
+ while @proxy.has_pending_requests?
1369
+ connections = @proxy.active_connections
1370
+
1371
+ if last_connections != connections
1372
+ print_debug_level_2 "Waiting for #{@proxy.pending_requests} requests to complete:"
1373
+ connections.each do |connection|
1374
+ if connection.request
1375
+ print_debug_level_2 " * #{connection.request.url}"
1376
+ else
1377
+ print_debug_level_2 ' * Still reading request data.'
1378
+ end
1379
+ end
1380
+ end
1381
+ last_connections = connections
1401
1382
 
1402
- sleep 0.1
1403
- sleep 0.01 while @proxy.has_pending_requests?
1383
+ sleep 0.1
1404
1384
 
1405
- print_debug_level_2 '...done.'
1385
+ # If the browser sends incomplete data the connection will remain
1386
+ # open indefinitely.
1387
+ next if Time.now - t < Options.browser_cluster.job_timeout
1388
+ connections.each(&:close)
1389
+ break
1390
+ end
1406
1391
  end
1407
1392
 
1408
1393
  def load_cookies( url, cookies = {} )
@@ -1437,16 +1422,16 @@ class Browser
1437
1422
  end
1438
1423
 
1439
1424
  return if set_cookies.empty? &&
1440
- Arachni::Options::browser_cluster.local_storage.empty?
1425
+ Arachni::Options.browser_cluster.local_storage.empty?
1441
1426
 
1442
1427
  set_cookie = set_cookies.values.map(&:to_set_cookie)
1443
1428
  print_debug_level_2 "Setting cookies: #{set_cookie}"
1444
1429
 
1445
1430
  body = ''
1446
- if Arachni::Options::browser_cluster.local_storage.any?
1431
+ if Arachni::Options.browser_cluster.local_storage.any?
1447
1432
  body = <<EOJS
1448
1433
  <script>
1449
- var data = #{Arachni::Options::browser_cluster.local_storage.to_json};
1434
+ var data = #{Arachni::Options.browser_cluster.local_storage.to_json};
1450
1435
 
1451
1436
  for( prop in data ) {
1452
1437
  localStorage.setItem( prop, data[prop] );
@@ -1510,10 +1495,20 @@ EOJS
1510
1495
  # parsing lots of massive JSON responses at the same time will
1511
1496
  # have a significant impact on performance.
1512
1497
  takes_screenshot: false,
1513
- 'phantomjs.page.settings.userAgent' => Options.http.user_agent,
1514
- 'phantomjs.page.customHeaders.X-Arachni-Browser-Auth' => auth_token,
1515
- 'phantomjs.page.settings.resourceTimeout' => Options.http.request_timeout,
1516
- 'phantomjs.page.settings.loadImages' => !Options.browser_cluster.ignore_images
1498
+
1499
+ # Needs to include the string Webkit:
1500
+ # https://github.com/ariya/phantomjs/issues/14198
1501
+ #
1502
+ # Default is:
1503
+ # Mozilla/5.0 (Unknown; Linux x86_64) AppleWebKit/538.1 (KHTML, like Gecko) PhantomJS/2.1.1 Safari/538.1
1504
+ 'phantomjs.page.settings.userAgent' =>
1505
+ USER_AGENT,
1506
+ 'phantomjs.page.customHeaders.X-Arachni-Browser-Auth' =>
1507
+ auth_token,
1508
+ 'phantomjs.page.settings.resourceTimeout' =>
1509
+ Options.http.request_timeout,
1510
+ 'phantomjs.page.settings.loadImages' =>
1511
+ !Options.browser_cluster.ignore_images
1517
1512
  )
1518
1513
  end
1519
1514
 
@@ -1550,13 +1545,13 @@ EOJS
1550
1545
  end
1551
1546
 
1552
1547
  if @javascript.serve( request, response )
1553
- print_debug_level_2 "Serving local JS."
1548
+ print_debug_level_2 'Serving local JS.'
1554
1549
  return
1555
1550
  end
1556
1551
 
1557
1552
  if !request.url.include?( request_token )
1558
1553
  if ignore_request?( request )
1559
- print_debug_level_2 "Out of scope, ignoring."
1554
+ print_debug_level_2 'Out of scope, ignoring.'
1560
1555
  return
1561
1556
  end
1562
1557
 
@@ -1570,8 +1565,8 @@ EOJS
1570
1565
  end
1571
1566
 
1572
1567
  # Signal the proxy to not actually perform the request if we have a
1573
- # preloaded or cached response for it.
1574
- if from_preloads( request, response ) || from_cache( request, response )
1568
+ # preloaded response for it.
1569
+ if from_preloads( request, response )
1575
1570
  print_debug_level_2 'Resource has been preloaded.'
1576
1571
 
1577
1572
  # There may be taints or custom JS code that need to be updated.
@@ -1597,6 +1592,18 @@ EOJS
1597
1592
  def response_handler( request, response )
1598
1593
  return if request.url.include?( request_token )
1599
1594
 
1595
+ # Prevent PhantomJS from caching the root page, we need to have an
1596
+ # associated response.
1597
+ if @last_url == response.url
1598
+ response.headers.delete 'Cache-control'
1599
+ response.headers.delete 'Etag'
1600
+ response.headers.delete 'Date'
1601
+ response.headers.delete 'Last-Modified'
1602
+ end
1603
+
1604
+ # Allow our own scripts to run.
1605
+ response.headers.delete 'Content-Security-Policy'
1606
+
1600
1607
  print_debug_level_2 "Got response: #{response.url}"
1601
1608
 
1602
1609
  @request_transitions.each do |transition|
@@ -1700,6 +1707,10 @@ EOJS
1700
1707
 
1701
1708
  def whitelist_asset_domains( response )
1702
1709
  synchronize do
1710
+ @whitelist_asset_domains ||= Support::LookUp::HashSet.new
1711
+ return if @whitelist_asset_domains.include? response.body
1712
+ @whitelist_asset_domains << response.body
1713
+
1703
1714
  ASSET_EXTRACTORS.each do |regexp|
1704
1715
  response.body.scan( regexp ).flatten.compact.each do |url|
1705
1716
  next if !(domain = self.class.add_asset_domain( url ))
@@ -1748,6 +1759,16 @@ EOJS
1748
1759
  )
1749
1760
 
1750
1761
  when :post
1762
+ inputs = request.parsed_url.query_parameters
1763
+ if inputs.any?
1764
+ elements[:forms] << Form.new(
1765
+ url: @last_url,
1766
+ action: request.url,
1767
+ method: :get,
1768
+ inputs: inputs
1769
+ )
1770
+ end
1771
+
1751
1772
  if !found_element && (inputs = request.body_parameters).any?
1752
1773
  elements[:forms] << Form.new(
1753
1774
  url: @last_url,
@@ -1815,16 +1836,6 @@ EOJS
1815
1836
  end
1816
1837
  end
1817
1838
 
1818
- def from_cache( request, response )
1819
- synchronize do
1820
- return if !@cache.include?( request.url )
1821
-
1822
- copy_response_data( @cache[request.url], response )
1823
- response.request = request
1824
- save_response response
1825
- end
1826
- end
1827
-
1828
1839
  def copy_response_data( source, destination )
1829
1840
  [:code, :url, :body, :headers, :ip_address, :return_code,
1830
1841
  :return_message, :headers_string, :total_time, :time].each do |m|