arachni 1.3.2 → 1.4

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 (727) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +108 -0
  3. data/Gemfile +2 -6
  4. data/LICENSE.md +1 -1
  5. data/README.md +34 -16
  6. data/Rakefile +1 -1
  7. data/arachni.gemspec +28 -20
  8. data/bin/arachni +1 -1
  9. data/bin/arachni_console +1 -1
  10. data/bin/arachni_multi +1 -1
  11. data/bin/arachni_reporter +1 -1
  12. data/bin/arachni_rest_server +13 -0
  13. data/bin/arachni_restore +1 -1
  14. data/bin/arachni_rpc +1 -1
  15. data/bin/arachni_rpcd +1 -1
  16. data/bin/arachni_rpcd_monitor +1 -1
  17. data/bin/arachni_script +1 -1
  18. data/components/checks/active/code_injection.rb +8 -10
  19. data/components/checks/active/code_injection_php_input_wrapper.rb +5 -6
  20. data/components/checks/active/code_injection_timing.rb +1 -1
  21. data/components/checks/active/csrf.rb +1 -1
  22. data/components/checks/active/file_inclusion.rb +20 -26
  23. data/components/checks/active/ldap_injection.rb +4 -5
  24. data/components/checks/active/no_sql_injection.rb +11 -20
  25. data/components/checks/active/no_sql_injection/substrings/mongodb +1 -0
  26. data/components/checks/active/no_sql_injection_differential.rb +3 -4
  27. data/components/checks/active/os_cmd_injection.rb +5 -9
  28. data/components/checks/active/os_cmd_injection_timing.rb +1 -1
  29. data/components/checks/active/path_traversal.rb +4 -17
  30. data/components/checks/active/response_splitting.rb +8 -2
  31. data/components/checks/active/rfi.rb +4 -5
  32. data/components/checks/active/session_fixation.rb +9 -3
  33. data/components/checks/active/source_code_disclosure.rb +5 -20
  34. data/components/checks/active/sql_injection.rb +30 -18
  35. data/components/checks/active/sql_injection/{regexp_ignore.txt → ignore_substrings} +0 -0
  36. data/components/checks/active/sql_injection/regexps/db2.yaml +2 -0
  37. data/components/checks/active/sql_injection/regexps/frontbase.yaml +1 -0
  38. data/components/checks/active/sql_injection/regexps/informix.yaml +1 -0
  39. data/components/checks/active/sql_injection/regexps/ingres.yaml +2 -0
  40. data/components/checks/active/sql_injection/regexps/maxdb.yaml +2 -0
  41. data/components/checks/active/sql_injection/regexps/mssql.yaml +8 -0
  42. data/components/checks/active/sql_injection/regexps/mysql.yaml +4 -0
  43. data/components/checks/active/sql_injection/regexps/oracle.yaml +4 -0
  44. data/components/checks/active/sql_injection/regexps/pgsql.yaml +3 -0
  45. data/components/checks/active/sql_injection/regexps/sqlite.yaml +2 -0
  46. data/components/checks/active/sql_injection/regexps/sybase.yaml +2 -0
  47. data/components/checks/active/sql_injection/substrings/access +3 -0
  48. data/components/checks/active/sql_injection/substrings/db2 +2 -0
  49. data/components/checks/active/sql_injection/{patterns → substrings}/emc +1 -1
  50. data/components/checks/active/sql_injection/{patterns → substrings}/firebird +0 -1
  51. data/components/checks/active/sql_injection/substrings/hsqldb +1 -0
  52. data/components/checks/active/sql_injection/{patterns → substrings}/informix +1 -2
  53. data/components/checks/active/sql_injection/substrings/ingres +1 -0
  54. data/components/checks/active/sql_injection/{patterns → substrings}/interbase +0 -0
  55. data/components/checks/active/sql_injection/substrings/mssql +17 -0
  56. data/components/checks/active/sql_injection/{patterns → substrings}/mysql +3 -6
  57. data/components/checks/active/sql_injection/substrings/oracle +2 -0
  58. data/components/checks/active/sql_injection/{patterns → substrings}/pgsql +3 -6
  59. data/components/checks/active/sql_injection/substrings/sqlite +3 -0
  60. data/components/checks/active/sql_injection/substrings/sybase +1 -0
  61. data/components/checks/active/sql_injection_differential.rb +5 -7
  62. data/components/checks/active/sql_injection_differential/payloads.txt +1 -1
  63. data/components/checks/active/sql_injection_timing.rb +1 -1
  64. data/components/checks/active/trainer.rb +5 -4
  65. data/components/checks/active/unvalidated_redirect.rb +1 -1
  66. data/components/checks/active/unvalidated_redirect_dom.rb +1 -1
  67. data/components/checks/active/xpath_injection.rb +3 -4
  68. data/components/checks/active/xss.rb +33 -12
  69. data/components/checks/active/xss_dom.rb +7 -4
  70. data/components/checks/active/xss_dom_script_context.rb +1 -1
  71. data/components/checks/active/xss_event.rb +43 -20
  72. data/components/checks/active/xss_path.rb +5 -4
  73. data/components/checks/active/xss_script_context.rb +41 -11
  74. data/components/checks/active/xss_tag.rb +14 -15
  75. data/components/checks/active/xxe.rb +5 -16
  76. data/components/checks/passive/allowed_methods.rb +1 -1
  77. data/components/checks/passive/backdoors.rb +4 -2
  78. data/components/checks/passive/backup_directories.rb +4 -2
  79. data/components/checks/passive/backup_files.rb +4 -2
  80. data/components/checks/passive/common_admin_interfaces.rb +4 -3
  81. data/components/checks/passive/common_directories.rb +3 -1
  82. data/components/checks/passive/common_files.rb +3 -1
  83. data/components/checks/passive/directory_listing.rb +4 -4
  84. data/components/checks/passive/grep/captcha.rb +1 -1
  85. data/components/checks/passive/grep/cookie_set_for_parent_domain.rb +1 -1
  86. data/components/checks/passive/grep/credit_card.rb +5 -7
  87. data/components/checks/passive/grep/cvs_svn_users.rb +1 -1
  88. data/components/checks/passive/grep/emails.rb +135 -8
  89. data/components/checks/passive/grep/form_upload.rb +1 -1
  90. data/components/checks/passive/grep/hsts.rb +4 -3
  91. data/components/checks/passive/grep/html_objects.rb +1 -1
  92. data/components/checks/passive/grep/http_only_cookies.rb +5 -3
  93. data/components/checks/passive/grep/insecure_cookies.rb +5 -3
  94. data/components/checks/passive/grep/insecure_cors_policy.rb +1 -1
  95. data/components/checks/passive/grep/mixed_resource.rb +1 -1
  96. data/components/checks/passive/grep/password_autocomplete.rb +1 -1
  97. data/components/checks/passive/grep/private_ip.rb +1 -1
  98. data/components/checks/passive/grep/ssn.rb +6 -3
  99. data/components/checks/passive/grep/unencrypted_password_forms.rb +1 -1
  100. data/components/checks/passive/grep/x_frame_options.rb +4 -3
  101. data/components/checks/passive/htaccess_limit.rb +1 -1
  102. data/components/checks/passive/http_put.rb +1 -1
  103. data/components/checks/passive/insecure_client_access_policy.rb +2 -2
  104. data/components/checks/passive/insecure_cross_domain_policy_access.rb +2 -2
  105. data/components/checks/passive/insecure_cross_domain_policy_headers.rb +2 -2
  106. data/components/checks/passive/interesting_responses.rb +1 -1
  107. data/components/checks/passive/localstart_asp.rb +1 -1
  108. data/components/checks/passive/origin_spoof_access_restriction_bypass.rb +1 -1
  109. data/components/checks/passive/webdav.rb +1 -1
  110. data/components/checks/passive/xst.rb +1 -1
  111. data/components/fingerprinters/frameworks/aspx_mvc.rb +1 -1
  112. data/components/fingerprinters/frameworks/cakephp.rb +1 -1
  113. data/components/fingerprinters/frameworks/cherrypy.rb +1 -1
  114. data/components/fingerprinters/frameworks/django.rb +1 -1
  115. data/components/fingerprinters/frameworks/jsf.rb +1 -1
  116. data/components/fingerprinters/frameworks/nette.rb +1 -1
  117. data/components/fingerprinters/frameworks/rack.rb +1 -1
  118. data/components/fingerprinters/frameworks/rails.rb +1 -1
  119. data/components/fingerprinters/frameworks/symfony.rb +1 -1
  120. data/components/fingerprinters/languages/asp.rb +1 -1
  121. data/components/fingerprinters/languages/aspx.rb +1 -1
  122. data/components/fingerprinters/languages/java.rb +1 -1
  123. data/components/fingerprinters/languages/php.rb +1 -1
  124. data/components/fingerprinters/languages/python.rb +1 -1
  125. data/components/fingerprinters/languages/ruby.rb +1 -1
  126. data/components/fingerprinters/os/bsd.rb +1 -1
  127. data/components/fingerprinters/os/linux.rb +1 -1
  128. data/components/fingerprinters/os/solaris.rb +1 -1
  129. data/components/fingerprinters/os/unix.rb +1 -1
  130. data/components/fingerprinters/os/windows.rb +1 -1
  131. data/components/fingerprinters/servers/apache.rb +1 -1
  132. data/components/fingerprinters/servers/gunicorn.rb +1 -1
  133. data/components/fingerprinters/servers/iis.rb +1 -1
  134. data/components/fingerprinters/servers/jetty.rb +1 -1
  135. data/components/fingerprinters/servers/nginx.rb +1 -1
  136. data/components/fingerprinters/servers/tomcat.rb +1 -1
  137. data/components/path_extractors/anchors.rb +1 -1
  138. data/components/path_extractors/areas.rb +1 -1
  139. data/components/path_extractors/comments.rb +1 -1
  140. data/components/path_extractors/data_url.rb +1 -1
  141. data/components/path_extractors/forms.rb +1 -1
  142. data/components/path_extractors/frames.rb +1 -1
  143. data/components/path_extractors/generic.rb +1 -1
  144. data/components/path_extractors/links.rb +1 -1
  145. data/components/path_extractors/meta_refresh.rb +3 -3
  146. data/components/path_extractors/scripts.rb +1 -1
  147. data/components/plugins/autologin.rb +16 -24
  148. data/components/plugins/beep_notify.rb +1 -1
  149. data/components/plugins/content_types.rb +1 -1
  150. data/components/plugins/cookie_collector.rb +1 -1
  151. data/components/plugins/defaults/autothrottle.rb +1 -1
  152. data/components/plugins/defaults/healthmap.rb +1 -1
  153. data/components/plugins/defaults/meta/remedies/discovery.rb +10 -9
  154. data/components/plugins/defaults/meta/remedies/timing_attacks.rb +1 -1
  155. data/components/plugins/defaults/meta/uniformity.rb +1 -1
  156. data/components/plugins/email_notify.rb +3 -5
  157. data/components/plugins/exec.rb +1 -1
  158. data/components/plugins/form_dicattack.rb +1 -1
  159. data/components/plugins/headers_collector.rb +1 -1
  160. data/components/plugins/http_dicattack.rb +1 -1
  161. data/components/plugins/login_script.rb +47 -22
  162. data/components/plugins/metrics.rb +1 -1
  163. data/components/plugins/proxy.rb +69 -44
  164. data/components/plugins/proxy/panel/help.html.erb +1 -18
  165. data/components/plugins/proxy/panel/inspect.html.erb +4 -3
  166. data/components/plugins/proxy/panel/page_accordion.html.erb +78 -43
  167. data/components/plugins/proxy/panel/panel.html.erb +2 -7
  168. data/components/plugins/proxy/template_scope.rb +1 -1
  169. data/components/plugins/restrict_to_dom_state.rb +3 -15
  170. data/components/plugins/script.rb +1 -1
  171. data/components/plugins/uncommon_headers.rb +1 -1
  172. data/components/plugins/vector_collector.rb +1 -1
  173. data/components/plugins/vector_feed.rb +3 -11
  174. data/components/plugins/waf_detector.rb +1 -1
  175. data/components/reporters/ap.rb +1 -1
  176. data/components/reporters/html.rb +2 -2
  177. data/components/reporters/json.rb +1 -1
  178. data/components/reporters/marshal.rb +1 -1
  179. data/components/reporters/plugin_formatters/html/autologin.rb +1 -1
  180. data/components/reporters/plugin_formatters/html/content_types.rb +1 -1
  181. data/components/reporters/plugin_formatters/html/cookie_collector.rb +1 -1
  182. data/components/reporters/plugin_formatters/html/exec.rb +1 -1
  183. data/components/reporters/plugin_formatters/html/form_dicattack.rb +1 -1
  184. data/components/reporters/plugin_formatters/html/healthmap.rb +1 -1
  185. data/components/reporters/plugin_formatters/html/http_dicattack.rb +1 -1
  186. data/components/reporters/plugin_formatters/html/login_script.rb +1 -1
  187. data/components/reporters/plugin_formatters/html/metrics.rb +1 -1
  188. data/components/reporters/plugin_formatters/html/uncommon_headers.rb +1 -1
  189. data/components/reporters/plugin_formatters/html/uniformity.rb +1 -1
  190. data/components/reporters/plugin_formatters/html/vector_collector.rb +1 -1
  191. data/components/reporters/plugin_formatters/html/waf_detector.rb +1 -1
  192. data/components/reporters/plugin_formatters/stdout/autologin.rb +1 -1
  193. data/components/reporters/plugin_formatters/stdout/content_types.rb +1 -1
  194. data/components/reporters/plugin_formatters/stdout/cookie_collector.rb +1 -1
  195. data/components/reporters/plugin_formatters/stdout/exec.rb +1 -1
  196. data/components/reporters/plugin_formatters/stdout/form_dicattack.rb +1 -1
  197. data/components/reporters/plugin_formatters/stdout/healthmap.rb +1 -1
  198. data/components/reporters/plugin_formatters/stdout/http_dicattack.rb +1 -1
  199. data/components/reporters/plugin_formatters/stdout/login_script.rb +1 -1
  200. data/components/reporters/plugin_formatters/stdout/metrics.rb +1 -1
  201. data/components/reporters/plugin_formatters/stdout/uncommon_headers.rb +1 -1
  202. data/components/reporters/plugin_formatters/stdout/uniformity.rb +1 -1
  203. data/components/reporters/plugin_formatters/stdout/vector_collector.rb +1 -1
  204. data/components/reporters/plugin_formatters/stdout/waf_detector.rb +1 -1
  205. data/components/reporters/plugin_formatters/xml/autologin.rb +1 -1
  206. data/components/reporters/plugin_formatters/xml/content_types.rb +1 -1
  207. data/components/reporters/plugin_formatters/xml/cookie_collector.rb +1 -1
  208. data/components/reporters/plugin_formatters/xml/exec.rb +1 -1
  209. data/components/reporters/plugin_formatters/xml/form_dicattack.rb +1 -1
  210. data/components/reporters/plugin_formatters/xml/healthmap.rb +1 -1
  211. data/components/reporters/plugin_formatters/xml/http_dicattack.rb +1 -1
  212. data/components/reporters/plugin_formatters/xml/login_script.rb +1 -1
  213. data/components/reporters/plugin_formatters/xml/metrics.rb +1 -1
  214. data/components/reporters/plugin_formatters/xml/uncommon_headers.rb +1 -1
  215. data/components/reporters/plugin_formatters/xml/uniformity.rb +1 -1
  216. data/components/reporters/plugin_formatters/xml/vector_collector.rb +1 -1
  217. data/components/reporters/plugin_formatters/xml/waf_detector.rb +1 -1
  218. data/components/reporters/stdout.rb +1 -1
  219. data/components/reporters/txt.rb +1 -1
  220. data/components/reporters/xml.rb +29 -4
  221. data/components/reporters/yaml.rb +1 -1
  222. data/lib/arachni.rb +48 -3
  223. data/lib/arachni/banner.rb +1 -1
  224. data/lib/arachni/browser.rb +601 -358
  225. data/lib/arachni/browser/element_locator.rb +25 -6
  226. data/lib/arachni/browser/javascript.rb +103 -35
  227. data/lib/arachni/browser/javascript/dom_monitor.rb +1 -1
  228. data/lib/arachni/browser/javascript/proxy.rb +28 -16
  229. data/lib/arachni/browser/javascript/proxy/stub.rb +1 -1
  230. data/lib/arachni/browser/javascript/scripts/dom_monitor.js +138 -67
  231. data/lib/arachni/browser/javascript/scripts/polyfills.js +28 -0
  232. data/lib/arachni/browser/javascript/scripts/taint_tracer.js +27 -6
  233. data/lib/arachni/browser/javascript/taint_tracer.rb +1 -1
  234. data/lib/arachni/browser/javascript/taint_tracer/frame.rb +1 -1
  235. data/lib/arachni/browser/javascript/taint_tracer/frame/called_function.rb +1 -1
  236. data/lib/arachni/browser/javascript/taint_tracer/sink/base.rb +1 -1
  237. data/lib/arachni/browser/javascript/taint_tracer/sink/data_flow.rb +1 -1
  238. data/lib/arachni/browser/javascript/taint_tracer/sink/execution_flow.rb +1 -1
  239. data/lib/arachni/browser_cluster.rb +10 -14
  240. data/lib/arachni/browser_cluster/job.rb +1 -1
  241. data/lib/arachni/browser_cluster/job/result.rb +1 -1
  242. data/lib/arachni/browser_cluster/jobs/browser_provider.rb +1 -1
  243. data/lib/arachni/browser_cluster/jobs/{resource_exploration.rb → dom_exploration.rb} +5 -5
  244. data/lib/arachni/browser_cluster/jobs/{resource_exploration → dom_exploration}/event_trigger.rb +7 -4
  245. data/lib/arachni/browser_cluster/jobs/{resource_exploration → dom_exploration}/event_trigger/result.rb +3 -3
  246. data/lib/arachni/browser_cluster/jobs/{resource_exploration → dom_exploration}/result.rb +2 -2
  247. data/lib/arachni/browser_cluster/jobs/taint_trace.rb +3 -3
  248. data/lib/arachni/browser_cluster/jobs/taint_trace/event_trigger.rb +2 -2
  249. data/lib/arachni/browser_cluster/jobs/taint_trace/event_trigger/result.rb +2 -2
  250. data/lib/arachni/browser_cluster/jobs/taint_trace/result.rb +1 -1
  251. data/lib/arachni/browser_cluster/worker.rb +12 -40
  252. data/lib/arachni/check.rb +1 -1
  253. data/lib/arachni/check/auditor.rb +15 -1
  254. data/lib/arachni/check/base.rb +1 -1
  255. data/lib/arachni/check/manager.rb +1 -1
  256. data/lib/arachni/component.rb +1 -1
  257. data/lib/arachni/component/base.rb +5 -5
  258. data/lib/arachni/component/manager.rb +39 -13
  259. data/lib/arachni/component/options.rb +1 -1
  260. data/lib/arachni/component/options/address.rb +1 -1
  261. data/lib/arachni/component/options/base.rb +1 -1
  262. data/lib/arachni/component/options/bool.rb +1 -1
  263. data/lib/arachni/component/options/float.rb +1 -1
  264. data/lib/arachni/component/options/int.rb +1 -1
  265. data/lib/arachni/component/options/multiple_choice.rb +1 -1
  266. data/lib/arachni/component/options/object.rb +1 -1
  267. data/lib/arachni/component/options/path.rb +1 -1
  268. data/lib/arachni/component/options/port.rb +1 -1
  269. data/lib/arachni/component/options/string.rb +1 -1
  270. data/lib/arachni/component/options/url.rb +1 -1
  271. data/lib/arachni/component/output.rb +1 -1
  272. data/lib/arachni/component/utilities.rb +1 -1
  273. data/lib/arachni/data.rb +1 -1
  274. data/lib/arachni/data/framework.rb +1 -1
  275. data/lib/arachni/data/framework/rpc.rb +1 -1
  276. data/lib/arachni/data/issues.rb +1 -1
  277. data/lib/arachni/data/plugins.rb +1 -1
  278. data/lib/arachni/data/session.rb +1 -1
  279. data/lib/arachni/element/base.rb +19 -5
  280. data/lib/arachni/element/body.rb +1 -1
  281. data/lib/arachni/element/capabilities/analyzable.rb +1 -1
  282. data/lib/arachni/element/capabilities/analyzable/differential.rb +15 -5
  283. data/lib/arachni/element/capabilities/analyzable/signature.rb +147 -89
  284. data/lib/arachni/element/capabilities/analyzable/timeout.rb +43 -16
  285. data/lib/arachni/element/capabilities/auditable.rb +20 -15
  286. data/lib/arachni/element/capabilities/dom_only.rb +5 -4
  287. data/lib/arachni/element/capabilities/inputtable.rb +62 -12
  288. data/lib/arachni/element/capabilities/mutable.rb +74 -13
  289. data/lib/arachni/element/capabilities/refreshable.rb +1 -1
  290. data/lib/arachni/element/capabilities/submittable.rb +5 -2
  291. data/lib/arachni/element/capabilities/with_auditor.rb +1 -1
  292. data/lib/arachni/element/capabilities/with_auditor/output.rb +5 -5
  293. data/lib/arachni/element/capabilities/with_dom.rb +1 -1
  294. data/lib/arachni/element/capabilities/with_node.rb +2 -2
  295. data/lib/arachni/element/capabilities/with_scope.rb +1 -1
  296. data/lib/arachni/element/capabilities/with_scope/scope.rb +1 -1
  297. data/lib/arachni/element/capabilities/with_source.rb +4 -4
  298. data/lib/arachni/element/cookie.rb +57 -34
  299. data/lib/arachni/element/cookie/capabilities/inputtable.rb +1 -1
  300. data/lib/arachni/element/cookie/capabilities/mutable.rb +10 -1
  301. data/lib/arachni/element/cookie/capabilities/with_dom.rb +1 -1
  302. data/lib/arachni/element/cookie/dom.rb +1 -1
  303. data/lib/arachni/element/dom.rb +1 -15
  304. data/lib/arachni/element/dom/capabilities/auditable.rb +1 -1
  305. data/lib/arachni/element/dom/capabilities/inputtable.rb +1 -1
  306. data/lib/arachni/element/dom/capabilities/locatable.rb +29 -0
  307. data/lib/arachni/element/dom/capabilities/mutable.rb +11 -1
  308. data/lib/arachni/element/dom/capabilities/submittable.rb +2 -2
  309. data/lib/arachni/element/form.rb +33 -14
  310. data/lib/arachni/element/form/capabilities/auditable.rb +1 -1
  311. data/lib/arachni/element/form/capabilities/mutable.rb +18 -17
  312. data/lib/arachni/element/form/capabilities/submittable.rb +1 -1
  313. data/lib/arachni/element/form/capabilities/with_dom.rb +2 -1
  314. data/lib/arachni/element/form/dom.rb +3 -2
  315. data/lib/arachni/element/generic_dom.rb +1 -1
  316. data/lib/arachni/element/header.rb +16 -4
  317. data/lib/arachni/element/header/capabilities/inputtable.rb +1 -1
  318. data/lib/arachni/element/header/capabilities/mutable.rb +11 -1
  319. data/lib/arachni/element/json.rb +2 -2
  320. data/lib/arachni/element/json/capabilities/inputtable.rb +1 -1
  321. data/lib/arachni/element/json/capabilities/mutable.rb +8 -2
  322. data/lib/arachni/element/link.rb +14 -7
  323. data/lib/arachni/element/link/capabilities/auditable.rb +1 -1
  324. data/lib/arachni/element/link/capabilities/submittable.rb +1 -1
  325. data/lib/arachni/element/link/capabilities/with_dom.rb +8 -1
  326. data/lib/arachni/element/link/dom.rb +2 -1
  327. data/lib/arachni/element/link/dom/capabilities/submittable.rb +1 -1
  328. data/lib/arachni/element/link_template.rb +8 -3
  329. data/lib/arachni/element/link_template/capabilities/auditable.rb +1 -1
  330. data/lib/arachni/element/link_template/capabilities/inputtable.rb +1 -1
  331. data/lib/arachni/element/link_template/capabilities/with_dom.rb +1 -1
  332. data/lib/arachni/element/link_template/dom.rb +2 -1
  333. data/lib/arachni/element/link_template/dom/capabilities/submittable.rb +1 -1
  334. data/lib/arachni/element/path.rb +1 -1
  335. data/lib/arachni/element/server.rb +3 -3
  336. data/lib/arachni/element/ui_form.rb +24 -21
  337. data/lib/arachni/element/ui_form/dom.rb +12 -3
  338. data/lib/arachni/element/ui_input.rb +17 -11
  339. data/lib/arachni/element/{input → ui_input}/dom.rb +11 -2
  340. data/lib/arachni/element/xml.rb +3 -3
  341. data/lib/arachni/element/xml/capabilities/inputtable.rb +7 -1
  342. data/lib/arachni/element/xml/capabilities/mutable.rb +7 -13
  343. data/lib/arachni/element_filter.rb +1 -1
  344. data/lib/arachni/error.rb +1 -1
  345. data/lib/arachni/ethon/easy.rb +1 -1
  346. data/lib/arachni/framework.rb +2 -5
  347. data/lib/arachni/framework/parts/audit.rb +8 -2
  348. data/lib/arachni/framework/parts/browser.rb +8 -9
  349. data/lib/arachni/framework/parts/check.rb +2 -6
  350. data/lib/arachni/framework/parts/data.rb +23 -8
  351. data/lib/arachni/framework/parts/platform.rb +1 -1
  352. data/lib/arachni/framework/parts/plugin.rb +2 -8
  353. data/lib/arachni/framework/parts/report.rb +3 -9
  354. data/lib/arachni/framework/parts/scope.rb +1 -1
  355. data/lib/arachni/framework/parts/state.rb +8 -8
  356. data/lib/arachni/http.rb +1 -1
  357. data/lib/arachni/http/client.rb +72 -68
  358. data/lib/arachni/http/client/dynamic_404_handler.rb +85 -60
  359. data/lib/arachni/http/cookie_jar.rb +48 -27
  360. data/lib/arachni/http/headers.rb +4 -3
  361. data/lib/arachni/http/message.rb +17 -3
  362. data/lib/arachni/http/message/scope.rb +1 -1
  363. data/lib/arachni/http/proxy_server.rb +46 -344
  364. data/lib/arachni/http/proxy_server/connection.rb +316 -0
  365. data/lib/arachni/http/proxy_server/ssl_interceptor.rb +102 -0
  366. data/lib/arachni/http/proxy_server/tunnel.rb +54 -0
  367. data/lib/arachni/http/request.rb +126 -29
  368. data/lib/arachni/http/request/scope.rb +1 -1
  369. data/lib/arachni/http/response.rb +42 -12
  370. data/lib/arachni/http/response/scope.rb +1 -1
  371. data/lib/arachni/issue.rb +2 -2
  372. data/lib/arachni/issue/severity.rb +1 -1
  373. data/lib/arachni/issue/severity/base.rb +1 -1
  374. data/lib/arachni/option_group.rb +1 -1
  375. data/lib/arachni/option_groups.rb +1 -1
  376. data/lib/arachni/option_groups/audit.rb +20 -4
  377. data/lib/arachni/option_groups/browser_cluster.rb +8 -4
  378. data/lib/arachni/option_groups/datastore.rb +1 -1
  379. data/lib/arachni/option_groups/dispatcher.rb +1 -1
  380. data/lib/arachni/option_groups/http.rb +2 -2
  381. data/lib/arachni/option_groups/input.rb +6 -3
  382. data/lib/arachni/option_groups/output.rb +1 -1
  383. data/lib/arachni/option_groups/paths.rb +10 -3
  384. data/lib/arachni/option_groups/rpc.rb +1 -1
  385. data/lib/arachni/option_groups/scope.rb +35 -6
  386. data/lib/arachni/option_groups/session.rb +1 -1
  387. data/lib/arachni/option_groups/snapshot.rb +1 -1
  388. data/lib/arachni/options.rb +1 -1
  389. data/lib/arachni/page.rb +26 -12
  390. data/lib/arachni/page/dom.rb +29 -22
  391. data/lib/arachni/page/dom/transition.rb +2 -2
  392. data/lib/arachni/page/scope.rb +1 -1
  393. data/lib/arachni/parser.rb +42 -5
  394. data/lib/arachni/platform.rb +1 -1
  395. data/lib/arachni/platform/fingerprinter.rb +1 -1
  396. data/lib/arachni/platform/list.rb +1 -1
  397. data/lib/arachni/platform/manager.rb +2 -2
  398. data/lib/arachni/plugin.rb +1 -1
  399. data/lib/arachni/plugin/base.rb +1 -1
  400. data/lib/arachni/plugin/formatter.rb +1 -1
  401. data/lib/arachni/plugin/manager.rb +7 -13
  402. data/lib/arachni/processes.rb +1 -1
  403. data/lib/arachni/processes/dispatchers.rb +2 -2
  404. data/lib/arachni/processes/executables/base.rb +45 -4
  405. data/lib/arachni/processes/executables/browser.rb +91 -0
  406. data/lib/arachni/processes/executables/rest_service.rb +14 -0
  407. data/lib/arachni/processes/helpers.rb +1 -1
  408. data/lib/arachni/processes/helpers/dispatchers.rb +1 -1
  409. data/lib/arachni/processes/helpers/instances.rb +1 -1
  410. data/lib/arachni/processes/helpers/processes.rb +1 -1
  411. data/lib/arachni/processes/instances.rb +5 -5
  412. data/lib/arachni/processes/manager.rb +68 -9
  413. data/lib/arachni/report.rb +1 -1
  414. data/lib/arachni/reporter.rb +1 -1
  415. data/lib/arachni/reporter/base.rb +1 -1
  416. data/lib/arachni/reporter/formatter_manager.rb +4 -2
  417. data/lib/arachni/reporter/manager.rb +3 -2
  418. data/lib/arachni/reporter/options.rb +1 -1
  419. data/lib/arachni/rest/server.rb +231 -0
  420. data/lib/arachni/rest/server/instance_helpers.rb +37 -0
  421. data/lib/arachni/rpc/client/base.rb +1 -1
  422. data/lib/arachni/rpc/client/dispatcher.rb +1 -1
  423. data/lib/arachni/rpc/client/instance.rb +1 -1
  424. data/lib/arachni/rpc/client/instance/framework.rb +1 -1
  425. data/lib/arachni/rpc/client/instance/service.rb +1 -1
  426. data/lib/arachni/rpc/serializer.rb +1 -1
  427. data/lib/arachni/rpc/server/active_options.rb +20 -3
  428. data/lib/arachni/rpc/server/base.rb +1 -1
  429. data/lib/arachni/rpc/server/check/manager.rb +1 -1
  430. data/lib/arachni/rpc/server/dispatcher.rb +4 -4
  431. data/lib/arachni/rpc/server/dispatcher/node.rb +1 -1
  432. data/lib/arachni/rpc/server/dispatcher/service.rb +1 -1
  433. data/lib/arachni/rpc/server/framework.rb +3 -1
  434. data/lib/arachni/rpc/server/framework/distributor.rb +1 -1
  435. data/lib/arachni/rpc/server/framework/master.rb +1 -1
  436. data/lib/arachni/rpc/server/framework/multi_instance.rb +1 -1
  437. data/lib/arachni/rpc/server/framework/slave.rb +1 -1
  438. data/lib/arachni/rpc/server/instance.rb +1 -3
  439. data/lib/arachni/rpc/server/output.rb +1 -1
  440. data/lib/arachni/rpc/server/plugin/manager.rb +1 -1
  441. data/lib/arachni/ruby.rb +1 -2
  442. data/lib/arachni/ruby/array.rb +1 -1
  443. data/lib/arachni/ruby/hash.rb +1 -1
  444. data/lib/arachni/ruby/object.rb +15 -1
  445. data/lib/arachni/ruby/set.rb +1 -1
  446. data/lib/arachni/ruby/string.rb +23 -4
  447. data/lib/arachni/ruby/webrick.rb +1 -1
  448. data/lib/arachni/ruby/webrick/cookie.rb +1 -1
  449. data/lib/arachni/ruby/webrick/httprequest.rb +1 -1
  450. data/lib/arachni/scope.rb +1 -1
  451. data/lib/arachni/{watir → selenium/webdriver}/element.rb +12 -13
  452. data/lib/arachni/session.rb +19 -4
  453. data/lib/arachni/snapshot.rb +9 -5
  454. data/lib/arachni/state.rb +1 -1
  455. data/lib/arachni/state/audit.rb +1 -1
  456. data/lib/arachni/state/element_filter.rb +1 -1
  457. data/lib/arachni/state/framework.rb +1 -1
  458. data/lib/arachni/state/framework/rpc.rb +1 -1
  459. data/lib/arachni/state/http.rb +1 -1
  460. data/lib/arachni/state/options.rb +1 -1
  461. data/lib/arachni/state/plugins.rb +1 -1
  462. data/lib/arachni/support.rb +2 -1
  463. data/lib/arachni/support/buffer.rb +1 -1
  464. data/lib/arachni/support/buffer/autoflush.rb +1 -1
  465. data/lib/arachni/support/buffer/base.rb +1 -1
  466. data/lib/arachni/support/cache.rb +1 -1
  467. data/lib/arachni/support/cache/base.rb +20 -8
  468. data/lib/arachni/support/cache/least_cost_replacement.rb +1 -1
  469. data/lib/arachni/support/cache/least_recently_pushed.rb +1 -1
  470. data/lib/arachni/support/cache/least_recently_used.rb +8 -9
  471. data/lib/arachni/support/cache/preference.rb +7 -20
  472. data/lib/arachni/support/cache/random_replacement.rb +1 -1
  473. data/lib/arachni/support/crypto.rb +1 -1
  474. data/lib/arachni/support/crypto/rsa_aes_cbc.rb +1 -1
  475. data/lib/arachni/support/database.rb +1 -1
  476. data/lib/arachni/support/database/base.rb +2 -2
  477. data/lib/arachni/support/database/hash.rb +1 -1
  478. data/lib/arachni/support/database/queue.rb +1 -1
  479. data/lib/arachni/support/glob.rb +35 -0
  480. data/lib/arachni/support/lookup.rb +1 -1
  481. data/lib/arachni/support/lookup/base.rb +1 -1
  482. data/lib/arachni/support/lookup/hash_set.rb +1 -1
  483. data/lib/arachni/support/lookup/moolb.rb +1 -1
  484. data/lib/arachni/support/mixins.rb +1 -1
  485. data/lib/arachni/support/mixins/observable.rb +1 -1
  486. data/lib/arachni/support/mixins/terminal.rb +1 -1
  487. data/lib/arachni/support/profiler.rb +12 -10
  488. data/lib/arachni/support/signature.rb +12 -5
  489. data/lib/arachni/trainer.rb +18 -4
  490. data/lib/arachni/ui/foo/output.rb +17 -1
  491. data/lib/arachni/uri.rb +285 -203
  492. data/lib/arachni/uri/scope.rb +13 -2
  493. data/lib/arachni/utilities.rb +22 -5
  494. data/lib/arachni/version.rb +1 -1
  495. data/lib/version +1 -1
  496. data/spec/arachni/browser/element_locator_spec.rb +42 -14
  497. data/spec/arachni/browser/javascript/dom_monitor_spec.rb +34 -304
  498. data/spec/arachni/browser/javascript/polyfills_spec.rb +35 -0
  499. data/spec/arachni/browser/javascript/taint_tracer_spec.rb +24 -4
  500. data/spec/arachni/browser/javascript_spec.rb +92 -65
  501. data/spec/arachni/browser_cluster/job_spec.rb +3 -3
  502. data/spec/arachni/browser_cluster/jobs/{resource_exploration → dom_exploration}/event_trigger/result_spec.rb +1 -1
  503. data/spec/arachni/browser_cluster/jobs/{resource_exploration → dom_exploration}/event_trigger_spec.rb +4 -4
  504. data/spec/arachni/browser_cluster/jobs/{resource_exploration → dom_exploration}/result_spec.rb +1 -1
  505. data/spec/arachni/browser_cluster/jobs/{resource_exploration_spec.rb → dom_exploration_spec.rb} +4 -4
  506. data/spec/arachni/browser_cluster/jobs/taint_tracer_spec.rb +9 -9
  507. data/spec/arachni/browser_cluster/worker_spec.rb +46 -67
  508. data/spec/arachni/browser_cluster_spec.rb +19 -17
  509. data/spec/arachni/browser_spec.rb +506 -183
  510. data/spec/arachni/check/auditor_spec.rb +70 -25
  511. data/spec/arachni/component/manager_spec.rb +19 -20
  512. data/spec/arachni/data/framework/rpc_spec.rb +1 -1
  513. data/spec/arachni/data/framework_spec.rb +1 -1
  514. data/spec/arachni/data/issues_spec.rb +3 -3
  515. data/spec/arachni/element/capabilities/analyzable/differential_spec.rb +44 -0
  516. data/spec/arachni/element/capabilities/analyzable/signature_spec.rb +33 -162
  517. data/spec/arachni/element/capabilities/analyzable/timeout_spec.rb +4 -4
  518. data/spec/arachni/element/cookie_spec.rb +98 -49
  519. data/spec/arachni/element/form/dom_spec.rb +1 -22
  520. data/spec/arachni/element/form_spec.rb +7 -7
  521. data/spec/arachni/element/header_spec.rb +2 -2
  522. data/spec/arachni/element/json_spec.rb +2 -2
  523. data/spec/arachni/element/link/dom_spec.rb +1 -22
  524. data/spec/arachni/element/link_spec.rb +17 -1
  525. data/spec/arachni/element/link_template/dom_spec.rb +1 -22
  526. data/spec/arachni/element/link_template_spec.rb +3 -3
  527. data/spec/arachni/element/ui_form/{ui_form_dom_spec.rb → dom_spec.rb} +72 -22
  528. data/spec/arachni/element/ui_form_spec.rb +1 -0
  529. data/spec/arachni/element/ui_input/dom_spec.rb +64 -22
  530. data/spec/arachni/element/ui_input_spec.rb +1 -0
  531. data/spec/arachni/element/xml_spec.rb +1 -0
  532. data/spec/arachni/framework/parts/audit_spec.rb +7 -5
  533. data/spec/arachni/framework/parts/browser_spec.rb +8 -8
  534. data/spec/arachni/framework/parts/check_spec.rb +1 -1
  535. data/spec/arachni/framework/parts/data_spec.rb +4 -4
  536. data/spec/arachni/framework/parts/scope_spec.rb +2 -2
  537. data/spec/arachni/framework_spec.rb +1 -1
  538. data/spec/arachni/http/client/dynamic_404_handlers_spec.rb +26 -13
  539. data/spec/arachni/http/client_spec.rb +80 -45
  540. data/spec/arachni/http/cookie_jar_spec.rb +6 -6
  541. data/spec/arachni/http/proxy_server_spec.rb +69 -66
  542. data/spec/arachni/http/request_spec.rb +147 -23
  543. data/spec/arachni/http/response/scope_spec.rb +12 -12
  544. data/spec/arachni/http/response_spec.rb +62 -4
  545. data/spec/arachni/issue_spec.rb +6 -6
  546. data/spec/arachni/option_groups/audit_spec.rb +25 -8
  547. data/spec/arachni/option_groups/browser_cluster_spec.rb +27 -1
  548. data/spec/arachni/option_groups/dispatcher_spec.rb +3 -3
  549. data/spec/arachni/option_groups/input_spec.rb +9 -9
  550. data/spec/arachni/option_groups/paths_spec.rb +2 -2
  551. data/spec/arachni/option_groups/scope_spec.rb +32 -16
  552. data/spec/arachni/options_spec.rb +4 -4
  553. data/spec/arachni/page/dom/transition_spec.rb +17 -10
  554. data/spec/arachni/page/dom_spec.rb +19 -0
  555. data/spec/arachni/page/scope_spec.rb +4 -4
  556. data/spec/arachni/page_spec.rb +15 -15
  557. data/spec/arachni/platform/manager_spec.rb +2 -2
  558. data/spec/arachni/plugin/base_spec.rb +1 -0
  559. data/spec/arachni/reporter/base_spec.rb +2 -2
  560. data/spec/arachni/reporter/manager_spec.rb +2 -2
  561. data/spec/arachni/rest/server_spec.rb +495 -0
  562. data/spec/arachni/rpc/server/active_options_spec.rb +63 -12
  563. data/spec/arachni/rpc/server/base_spec.rb +1 -1
  564. data/spec/arachni/rpc/server/framework/distributor_spec.rb +2 -2
  565. data/spec/arachni/rpc/server/framework_multi_spec.rb +6 -6
  566. data/spec/arachni/rpc/server/framework_spec.rb +4 -4
  567. data/spec/arachni/rpc/server/instance_spec.rb +24 -24
  568. data/spec/arachni/ruby/array_spec.rb +2 -2
  569. data/spec/arachni/ruby/string_spec.rb +52 -0
  570. data/spec/arachni/session_spec.rb +19 -2
  571. data/spec/arachni/snapshot_spec.rb +1 -1
  572. data/spec/arachni/state/audit_spec.rb +1 -1
  573. data/spec/arachni/state/framework_spec.rb +2 -2
  574. data/spec/arachni/support/cache/least_recently_used_spec.rb +0 -2
  575. data/spec/arachni/support/glob_spec.rb +75 -0
  576. data/spec/arachni/support/lookup/hash_set_spec.rb +1 -1
  577. data/spec/arachni/support/lookup/moolb_spec.rb +2 -2
  578. data/spec/arachni/support/signature_spec.rb +4 -4
  579. data/spec/arachni/trainer_spec.rb +48 -4
  580. data/spec/arachni/uri/scope_spec.rb +54 -10
  581. data/spec/arachni/uri_spec.rb +110 -89
  582. data/spec/arachni/utilities_spec.rb +8 -8
  583. data/spec/components/checks/active/code_injection_spec.rb +9 -9
  584. data/spec/components/checks/active/file_inclusion_spec.rb +20 -20
  585. data/spec/components/checks/active/ldap_injection_spec.rb +1 -1
  586. data/spec/components/checks/active/no_sql_injection_spec.rb +1 -1
  587. data/spec/components/checks/active/os_cmd_injection_spec.rb +3 -3
  588. data/spec/components/checks/active/path_traversal_spec.rb +11 -11
  589. data/spec/components/checks/active/response_splitting_spec.rb +2 -2
  590. data/spec/components/checks/active/rfi_spec.rb +3 -3
  591. data/spec/components/checks/active/session_fixation_spec.rb +1 -1
  592. data/spec/components/checks/active/source_code_disclosure_spec.rb +4 -4
  593. data/spec/components/checks/active/sql_injection_spec.rb +58 -59
  594. data/spec/components/checks/active/unvalidated_redirect_spec.rb +2 -2
  595. data/spec/components/checks/active/xpath_injection_spec.rb +3 -3
  596. data/spec/components/checks/active/xss_dom_script_context_spec.rb +1 -1
  597. data/spec/components/checks/active/xss_dom_spec.rb +1 -1
  598. data/spec/components/checks/active/xss_script_context_spec.rb +5 -5
  599. data/spec/components/checks/active/xss_spec.rb +5 -5
  600. data/spec/components/checks/passive/grep/credit_card_spec.rb +1 -1
  601. data/spec/components/checks/passive/grep/emails_spec.rb +12 -2
  602. data/spec/components/checks/passive/grep/ssn_spec.rb +1 -1
  603. data/spec/components/path_extractors/meta_refresh_spec.rb +3 -1
  604. data/spec/components/plugins/exec_spec.rb +2 -2
  605. data/spec/components/plugins/login_script_spec.rb +22 -2
  606. data/spec/components/plugins/vector_feed_spec.rb +3 -3
  607. data/spec/spec_helper.rb +10 -4
  608. data/spec/support/factories/browser_cluster/job.rb +1 -0
  609. data/spec/support/fixtures/check_with_invalid_platforms/with_invalid_platforms.rb +1 -1
  610. data/spec/support/fixtures/checks/test.rb +1 -1
  611. data/spec/support/fixtures/checks/test2.rb +1 -1
  612. data/spec/support/fixtures/checks/test3.rb +1 -1
  613. data/spec/support/fixtures/fingerprinters/test.rb +1 -1
  614. data/spec/support/fixtures/plugins/bad.rb +1 -1
  615. data/spec/support/fixtures/plugins/defaults/default.rb +1 -1
  616. data/spec/support/fixtures/plugins/distributable.rb +1 -1
  617. data/spec/support/fixtures/plugins/loop.rb +1 -1
  618. data/spec/support/fixtures/plugins/suspendable.rb +1 -1
  619. data/spec/support/fixtures/plugins/wait.rb +1 -1
  620. data/spec/support/fixtures/plugins/with_options.rb +1 -1
  621. data/spec/support/fixtures/plugins_with_priorities/p0.rb +1 -1
  622. data/spec/support/fixtures/plugins_with_priorities/p00.rb +1 -1
  623. data/spec/support/fixtures/plugins_with_priorities/p1.rb +1 -1
  624. data/spec/support/fixtures/plugins_with_priorities/p2.rb +1 -1
  625. data/spec/support/fixtures/plugins_with_priorities/p22.rb +1 -1
  626. data/spec/support/fixtures/plugins_with_priorities/p222.rb +1 -1
  627. data/spec/support/fixtures/plugins_with_priorities/p_nil.rb +1 -1
  628. data/spec/support/fixtures/plugins_with_priorities/p_nil2.rb +1 -1
  629. data/spec/support/fixtures/report.afr +0 -0
  630. data/spec/support/fixtures/reporters/base_spec/plugin_formatters/with_formatters/foobar.rb +1 -1
  631. data/spec/support/fixtures/reporters/base_spec/with_formatters.rb +1 -1
  632. data/spec/support/fixtures/reporters/base_spec/with_outfile.rb +1 -1
  633. data/spec/support/fixtures/reporters/base_spec/without_outfile.rb +1 -1
  634. data/spec/support/fixtures/reporters/manager_spec/afr.rb +1 -1
  635. data/spec/support/fixtures/reporters/manager_spec/error.rb +1 -1
  636. data/spec/support/fixtures/reporters/manager_spec/foo.rb +1 -1
  637. data/spec/support/fixtures/run_check/body.rb +1 -1
  638. data/spec/support/fixtures/run_check/cookies.rb +1 -1
  639. data/spec/support/fixtures/run_check/empty.rb +1 -1
  640. data/spec/support/fixtures/run_check/flch.rb +1 -1
  641. data/spec/support/fixtures/run_check/forms.rb +1 -1
  642. data/spec/support/fixtures/run_check/headers.rb +1 -1
  643. data/spec/support/fixtures/run_check/links.rb +1 -1
  644. data/spec/support/fixtures/run_check/nil.rb +1 -1
  645. data/spec/support/fixtures/run_check/path.rb +1 -1
  646. data/spec/support/fixtures/run_check/server.rb +1 -1
  647. data/spec/support/fixtures/signature_check/signature.rb +1 -1
  648. data/spec/support/fixtures/wait_check/wait.rb +1 -1
  649. data/spec/support/helpers/framework.rb +1 -1
  650. data/spec/support/helpers/misc.rb +1 -1
  651. data/spec/support/helpers/paths.rb +1 -1
  652. data/spec/support/helpers/request_helpers.rb +38 -0
  653. data/spec/support/helpers/requires.rb +1 -1
  654. data/spec/support/helpers/resets.rb +1 -1
  655. data/spec/support/helpers/web_server.rb +1 -1
  656. data/spec/support/lib/factory.rb +1 -1
  657. data/spec/support/lib/web_server_client.rb +1 -1
  658. data/spec/support/lib/web_server_dispatcher.rb +1 -1
  659. data/spec/support/lib/web_server_manager.rb +2 -2
  660. data/spec/support/servers/arachni/browser.rb +182 -15
  661. data/spec/support/servers/arachni/browser/javascript/angular-1.2.8.js +1 -1
  662. data/spec/support/servers/arachni/browser/javascript/angular-route.js +1 -1
  663. data/spec/support/servers/arachni/browser/javascript/dom_monitor.rb +27 -4
  664. data/spec/support/servers/arachni/element/capabilities/analyzable/differential.rb +103 -0
  665. data/spec/support/servers/arachni/element/capabilities/analyzable/timeout.rb +5 -2
  666. data/spec/support/servers/arachni/element/header.rb +1 -1
  667. data/spec/support/servers/arachni/http/client.rb +46 -0
  668. data/spec/support/servers/arachni/http/client/dynamic_404_handler.rb +7 -1
  669. data/spec/support/servers/checks/active/code_injection.rb +5 -5
  670. data/spec/support/servers/checks/active/no_sql_injection.rb +0 -6
  671. data/spec/support/servers/checks/active/no_sql_injection_differential.rb +1 -1
  672. data/spec/support/servers/checks/active/sql_injection.rb +5 -2
  673. data/spec/support/servers/checks/active/sql_injection_differential.rb +1 -1
  674. data/spec/support/servers/checks/active/trainer_check.rb +6 -6
  675. data/spec/support/servers/checks/passive/backdoors.rb +1 -0
  676. data/spec/support/servers/checks/passive/backup_directories.rb +2 -0
  677. data/spec/support/servers/checks/passive/backup_files.rb +2 -0
  678. data/spec/support/servers/checks/passive/grep/emails.rb +6 -6
  679. data/spec/support/shared/check.rb +28 -0
  680. data/spec/support/shared/element/capabilities/auditable.rb +76 -13
  681. data/spec/support/shared/element/capabilities/dom_only.rb +5 -6
  682. data/spec/support/shared/element/capabilities/inputtable.rb +74 -4
  683. data/spec/support/shared/element/capabilities/mutable.rb +86 -14
  684. data/spec/support/shared/element/capabilities/submittable.rb +12 -0
  685. data/spec/support/shared/element/capabilities/with_dom.rb +13 -4
  686. data/spec/support/shared/element/capabilities/with_node.rb +1 -1
  687. data/spec/support/shared/element/capabilities/with_source.rb +1 -6
  688. data/spec/support/shared/element/dom/locatable.rb +20 -0
  689. data/spec/support/shared/element/dom/submittable.rb +4 -17
  690. data/spec/support/shared/http/message.rb +37 -5
  691. data/spec/support/shared/support/cache.rb +5 -4
  692. data/ui/cli/framework.rb +4 -3
  693. data/ui/cli/framework/option_parser.rb +20 -8
  694. data/ui/cli/option_parser.rb +1 -1
  695. data/ui/cli/output.rb +40 -4
  696. data/ui/cli/reporter.rb +1 -1
  697. data/ui/cli/reporter/option_parser.rb +4 -4
  698. data/ui/cli/rest/server.rb +43 -0
  699. data/ui/cli/rest/server/option_parser.rb +115 -0
  700. data/ui/cli/restored_framework.rb +1 -1
  701. data/ui/cli/restored_framework/option_parser.rb +1 -1
  702. data/ui/cli/rpc/client/dispatcher_monitor.rb +1 -1
  703. data/ui/cli/rpc/client/dispatcher_monitor/option_parser.rb +1 -1
  704. data/ui/cli/rpc/client/instance.rb +1 -1
  705. data/ui/cli/rpc/client/local.rb +1 -1
  706. data/ui/cli/rpc/client/local/option_parser.rb +1 -1
  707. data/ui/cli/rpc/client/remote.rb +1 -1
  708. data/ui/cli/rpc/client/remote/option_parser.rb +1 -1
  709. data/ui/cli/rpc/server/dispatcher.rb +1 -1
  710. data/ui/cli/rpc/server/dispatcher/option_parser.rb +1 -1
  711. data/ui/cli/utilities.rb +1 -1
  712. metadata +197 -84
  713. data/components/checks/active/no_sql_injection/patterns/mongodb +0 -1
  714. data/components/checks/active/no_sql_injection/regexp_ignore.txt +0 -0
  715. data/components/checks/active/sql_injection/patterns/access +0 -3
  716. data/components/checks/active/sql_injection/patterns/db2 +0 -5
  717. data/components/checks/active/sql_injection/patterns/frontbase +0 -1
  718. data/components/checks/active/sql_injection/patterns/hsqldb +0 -1
  719. data/components/checks/active/sql_injection/patterns/ingres +0 -3
  720. data/components/checks/active/sql_injection/patterns/maxdb +0 -2
  721. data/components/checks/active/sql_injection/patterns/mssql +0 -25
  722. data/components/checks/active/sql_injection/patterns/oracle +0 -6
  723. data/components/checks/active/sql_injection/patterns/sqlite +0 -5
  724. data/components/checks/active/sql_injection/patterns/sybase +0 -3
  725. data/lib/arachni/ruby/io.rb +0 -39
  726. data/lib/arachni/selenium/webdriver/remote/http/typhoeus.rb +0 -63
  727. data/spec/arachni/ruby/io_spec.rb +0 -26
@@ -1,5 +1,5 @@
1
1
  =begin
2
- Copyright 2010-2015 Tasos Laskos <tasos.laskos@arachni-scanner.com>
2
+ Copyright 2010-2016 Tasos Laskos <tasos.laskos@arachni-scanner.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-2015 Tasos Laskos <tasos.laskos@arachni-scanner.com>
2
+ Copyright 2010-2016 Tasos Laskos <tasos.laskos@arachni-scanner.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-2015 Tasos Laskos <tasos.laskos@arachni-scanner.com>
2
+ Copyright 2010-2016 Tasos Laskos <tasos.laskos@arachni-scanner.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
@@ -19,6 +19,7 @@ class Profiler
19
19
 
20
20
  def self.write_samples_to_disk( file, options = {} )
21
21
  profiler = Support::Profiler.new
22
+ # profiler.trace_allocations
22
23
 
23
24
  Thread.new do
24
25
  begin
@@ -42,11 +43,11 @@ class Profiler
42
43
  ap 'Object ID: ' + o.object_id.to_s
43
44
  ap 'Source file: ' + ObjectSpace.allocation_sourcefile(o)
44
45
  ap 'Source line: ' + ObjectSpace.allocation_sourceline(o).to_s
45
- ap 'Generation: ' + ObjectSpace.allocation_generation(o).to_s
46
- ap 'Class path: ' + ObjectSpace.allocation_class_path(o).to_s
46
+ # ap 'Generation: ' + ObjectSpace.allocation_generation(o).to_s
47
+ # ap 'Class path: ' + ObjectSpace.allocation_class_path(o).to_s
47
48
  ap 'Method: ' + ObjectSpace.allocation_method_id(o).to_s
48
49
  ap 'Memsize: ' + ObjectSpace.memsize_of(o).to_s
49
- #ap 'Reachable: ' + ObjectSpace.reachable_objects_from(o).to_s #=> [referenced, objects, ...]
50
+ ap 'Reachable: ' + ObjectSpace.reachable_objects_from(o).to_s #=> [referenced, objects, ...]
50
51
  ap '-' * 200
51
52
  end
52
53
 
@@ -103,11 +104,12 @@ class Profiler
103
104
  ObjectSpace.each_object do |o|
104
105
  next if o.class != klass && !object_within_namespace?( o, namespaces )
105
106
 
106
- # if o.class == Thread
107
- # ap ObjectSpace.allocation_class_path( o ).to_s
108
- # ap "#{ObjectSpace.allocation_sourcefile( o )}:#{ObjectSpace.allocation_sourceline( o )}"
109
- # ap Utilities.bytes_to_megabytes( ObjectSpace.memsize_of( o ) )
110
- # ap '-' * 120
107
+ # if o.class == Page
108
+ # print_object_allocations( o )
109
+ #
110
+ # # ap ObjectSpace.allocation_class_path( o ).to_s
111
+ # # ap "#{ObjectSpace.allocation_sourcefile( o )}:#{ObjectSpace.allocation_sourceline( o )}"
112
+ # # ap '-' * 120
111
113
  # end
112
114
 
113
115
  object_space[o.class] ||= {
@@ -119,7 +121,7 @@ class Profiler
119
121
  object_space[o.class][:count] += 1
120
122
  end
121
123
 
122
- object_space = Hash[object_space.sort_by { |_, v| v[:memsize] }.reverse[0..max_entries]]
124
+ object_space = Hash[object_space.sort_by { |_, v| v[:count] }.reverse[0..max_entries]]
123
125
 
124
126
  with_deltas = {}
125
127
  object_space.each do |k, v|
@@ -1,5 +1,5 @@
1
1
  =begin
2
- Copyright 2010-2015 Tasos Laskos <tasos.laskos@arachni-scanner.com>
2
+ Copyright 2010-2016 Tasos Laskos <tasos.laskos@arachni-scanner.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
@@ -109,15 +109,14 @@ class Signature
109
109
  # @param [Signature, String] data
110
110
  #
111
111
  # @return [Array<String,Integer>]
112
- # Words as tokens represented by either the words themselves or their
113
- # hashes, depending on which is smaller in size.
112
+ # Words as tokens.
114
113
  def tokenize( data )
115
114
  return data.tokens if data.is_a? self.class
116
115
 
117
116
  if CACHE[:tokens][data]
118
117
  CACHE[:tokens][data].dup
119
118
  else
120
- CACHE[:tokens][data] = compress( data.split( /(?![\w])/ ) )
119
+ CACHE[:tokens][data] = compress( data.split( /\W/ ) )
121
120
  end
122
121
  end
123
122
 
@@ -125,7 +124,15 @@ class Signature
125
124
  # Seems kinda silly but this can actually save us GB of RAM when comparing
126
125
  # large signatures, not to mention CPU cycles.
127
126
  def compress( tokens )
128
- Set.new( tokens.map(&:hash) )
127
+ s = Set.new
128
+ tokens.each do |token|
129
+ # Left-over non-word characters will be on their own, this is a
130
+ # low-overhead way to dispose of them.
131
+ next if token.empty?
132
+
133
+ s << token.hash
134
+ end
135
+ s
129
136
  end
130
137
 
131
138
  end
@@ -1,5 +1,5 @@
1
1
  =begin
2
- Copyright 2010-2015 Tasos Laskos <tasos.laskos@arachni-scanner.com>
2
+ Copyright 2010-2016 Tasos Laskos <tasos.laskos@arachni-scanner.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
@@ -34,6 +34,8 @@ class Trainer
34
34
  @framework = framework
35
35
  @updated = false
36
36
 
37
+ @seen_pages = Support::LookUp::HashSet.new
38
+
37
39
  @trainings_per_url = Hash.new( 0 )
38
40
 
39
41
  # get us setup using the page that is being audited as a seed page
@@ -73,8 +75,6 @@ class Trainer
73
75
  return
74
76
  end
75
77
 
76
- return false if !response.text?
77
-
78
78
  skip_message = nil
79
79
  if @trainings_per_url[response.url] >= MAX_TRAININGS_PER_URL
80
80
  skip_message = "Reached maximum trainings (#{MAX_TRAININGS_PER_URL})"
@@ -89,6 +89,20 @@ class Trainer
89
89
  return false
90
90
  end
91
91
 
92
+ param_names = response.parsed_url.query_parameters.keys
93
+ cookies = Cookie.from_headers( response.url, response.headers ).map(&:name)
94
+
95
+ k = "#{param_names.hash}:#{cookies.hash}:#{response.body}"
96
+
97
+ # Naive optimization but it works a lot of the time. :)
98
+ if @seen_pages.include? k
99
+ print_debug "Already seen response for request ID: ##{response.request.id}"
100
+ return
101
+ end
102
+ @seen_pages << k
103
+
104
+ return false if !response.text?
105
+
92
106
  analyze response
93
107
  true
94
108
  rescue => e
@@ -102,7 +116,7 @@ class Trainer
102
116
  # @param [Arachni::Page] page
103
117
  def page=( page )
104
118
  ElementFilter.update_from_page page
105
- @page = page.dup
119
+ @page = page
106
120
  end
107
121
 
108
122
  private
@@ -1,5 +1,5 @@
1
1
  =begin
2
- Copyright 2010-2015 Tasos Laskos <tasos.laskos@arachni-scanner.com>
2
+ Copyright 2010-2016 Tasos Laskos <tasos.laskos@arachni-scanner.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
@@ -63,12 +63,28 @@ module Output
63
63
  def print_debug_level_3(*)
64
64
  end
65
65
 
66
+ def print_debug_level_4(*)
67
+ end
68
+
66
69
  def print_debug_backtrace(*)
67
70
  end
68
71
 
69
72
  def print_error_backtrace(*)
70
73
  end
71
74
 
75
+ def debug_level_1?
76
+ debug? 1
77
+ end
78
+ def debug_level_2?
79
+ debug? 2
80
+ end
81
+ def debug_level_3?
82
+ debug? 3
83
+ end
84
+ def debug_level_4?
85
+ debug? 4
86
+ end
87
+
72
88
  def print_verbose(*)
73
89
  end
74
90
 
@@ -1,5 +1,5 @@
1
1
  =begin
2
- Copyright 2010-2015 Tasos Laskos <tasos.laskos@arachni-scanner.com>
2
+ Copyright 2010-2016 Tasos Laskos <tasos.laskos@arachni-scanner.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
@@ -21,16 +21,13 @@ module Arachni
21
21
  end
22
22
 
23
23
  # The URI class automatically normalizes the URLs it is passed to parse
24
- # while maintaining compatibility with Ruby's URI core class by delegating
25
- # missing methods to it -- thus, you can treat it like a Ruby URI and enjoy some
26
- # extra perks along the way.
24
+ # while maintaining compatibility with Ruby's URI core class.
27
25
  #
28
26
  # It also provides *cached* (to maintain a low latency) helper class methods to
29
27
  # ease common operations such as:
30
28
  #
31
29
  # * {.normalize Normalization}.
32
- # * Parsing to {.parse Arachni::URI} (see also {.URI}), {.ruby_parse ::URI} or
33
- # {.fast_parse Hash} objects.
30
+ # * Parsing to {.parse Arachni::URI} (see also {.URI}) or {.fast_parse Hash} objects.
34
31
  # * Conversion to {.to_absolute absolute URLs}.
35
32
  #
36
33
  # @author Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com>
@@ -50,13 +47,12 @@ class URI
50
47
  end
51
48
 
52
49
  CACHE_SIZES = {
53
- parse: 1000,
54
- ruby_parse: 1000,
55
- fast_parse: 1000,
56
- encode: 1000,
57
- decode: 1000,
58
- normalize: 1000,
59
- to_absolute: 1000
50
+ parse: 5_000,
51
+ fast_parse: 5_000,
52
+ encode: 10_000,
53
+ decode: 10_000,
54
+ normalize: 10_000,
55
+ to_absolute: 10_000
60
56
  }
61
57
 
62
58
  CACHE = {
@@ -66,6 +62,8 @@ class URI
66
62
  CACHE[name] = Support::Cache::LeastRecentlyPushed.new( size )
67
63
  end
68
64
 
65
+ QUERY_CHARACTER_CLASS = Addressable::URI::CharacterClasses::QUERY.sub( '\\&', '' )
66
+
69
67
  class <<self
70
68
 
71
69
  # @return [URI::Parser] cached URI parser
@@ -83,8 +81,9 @@ class URI
83
81
  # @return [String]
84
82
  # Encoded string.
85
83
  def encode( string, good_characters = nil )
86
- CACHE[__method__][[string, good_characters]] ||=
84
+ CACHE[__method__].fetch [string, good_characters] do
87
85
  Addressable::URI.encode_component( *[string, good_characters].compact )
86
+ end
88
87
  end
89
88
 
90
89
  # URL decodes a string.
@@ -93,7 +92,7 @@ class URI
93
92
  #
94
93
  # @return [String]
95
94
  def decode( string )
96
- CACHE[__method__][string] ||= Addressable::URI.unencode( string )
95
+ CACHE[__method__].fetch( string ) { Addressable::URI.unencode( string ) }
97
96
  end
98
97
 
99
98
  # @note This method's results are cached for performance reasons.
@@ -106,35 +105,10 @@ class URI
106
105
  # @see URI#initialize
107
106
  def parse( url )
108
107
  return url if !url || url.is_a?( Arachni::URI )
109
- CACHE[__method__][url] ||= begin
110
- new( url )
111
- rescue => e
112
- print_debug "Failed to parse '#{url}'."
113
- print_debug "Error: #{e}"
114
- print_debug_backtrace( e )
115
- nil
116
- end
117
- end
118
108
 
119
- # @note This method's results are cached for performance reasons.
120
- # If you plan on doing something destructive with its return value
121
- # duplicate it first because there may be references to it elsewhere.
122
- #
123
- # {.normalize Normalizes} `url` and uses Ruby's core URI lib to parse it.
124
- #
125
- # @param [String] url
126
- # URL to parse
127
- #
128
- # @return [URI]
129
- def ruby_parse( url )
130
- return url if url.to_s.empty? || url.is_a?( ::URI )
131
- return if url.downcase.start_with? 'javascript:'
132
-
133
- CACHE[__method__][url] ||= begin
134
- ::URI::Generic.build( fast_parse( url ) )
135
- rescue
109
+ CACHE[__method__].fetch url do
136
110
  begin
137
- parser.parse( normalize( url ).dup )
111
+ new( url )
138
112
  rescue => e
139
113
  print_debug "Failed to parse '#{url}'."
140
114
  print_debug "Error: #{e}"
@@ -148,11 +122,6 @@ class URI
148
122
  # If you plan on doing something destructive with its return value
149
123
  # duplicate it first because there may be references to it elsewhere.
150
124
  #
151
- # @note The Hash is suitable for passing to `::URI::Generic.build` -- if
152
- # however you plan on doing that you'll be better off just using
153
- # {.ruby_parse} which does the same thing and caches the results for some
154
- # extra schnell.
155
- #
156
125
  # Performs a parse that is less resource intensive than Ruby's URI lib's
157
126
  # method while normalizing the URL (will also discard the fragment and
158
127
  # path parameters).
@@ -170,18 +139,19 @@ class URI
170
139
  # * `:query`
171
140
  def fast_parse( url )
172
141
  return if !url || url.empty?
173
- return if url.downcase.start_with? 'javascript:'
142
+ return if url.downcase.start_with?( 'javascript:' ) ||
143
+ url.start_with?( '#' )
174
144
 
175
145
  cache = CACHE[__method__]
176
146
 
177
- url = url.to_s.dup
147
+ # One to rip apart.
148
+ url = url.dup
178
149
 
179
150
  # Remove the fragment if there is one.
180
- if url.include?( '#' )
181
- url = url.split( '#', 2 )[0...-1].join
182
- end
151
+ url.sub!( /#.*/, '' )
183
152
 
184
- c_url = url.dup
153
+ # One for reference.
154
+ c_url = url
185
155
 
186
156
  components = {
187
157
  scheme: nil,
@@ -201,14 +171,14 @@ class URI
201
171
  return v
202
172
  end
203
173
 
204
- # We're not smart enough for scheme-less URLs and if we're to go
205
- # into heuristics then there's no reason to not just use
206
- # Addressable's parser.
207
- if url.start_with?( '//' )
208
- return cache[c_url] = addressable_parse( c_url ).freeze
174
+ # Parsing the URL in its schemeless form is trickier, so we
175
+ # fake it, pass a valid scheme to get through the parsing and
176
+ # then remove it at the other end.
177
+ if (schemeless = url.start_with?( '//' ))
178
+ url = "http:#{url}"
209
179
  end
210
180
 
211
- url = url.recode!
181
+ # url.recode!
212
182
  url = html_decode( url )
213
183
 
214
184
  dupped_url = url.dup
@@ -216,41 +186,39 @@ class URI
216
186
 
217
187
  splits = url.split( ':' )
218
188
  if !splits.empty? && valid_schemes.include?( splits.first.downcase )
189
+
219
190
  splits = url.split( '://', 2 )
220
191
  components[:scheme] = splits.shift
221
192
  components[:scheme].downcase! if components[:scheme]
222
193
 
223
- if url = splits.shift
224
- splits = url.to_s.split( '?' ).first.to_s.split( '@', 2 )
194
+ if (url = splits.shift)
195
+ userinfo_host, url = url.to_s.split( '?' ).first.to_s.split( '/', 2 )
196
+ url = url.to_s
197
+ splits = userinfo_host.to_s.split( '@', 2 )
225
198
 
226
199
  if splits.size > 1
227
200
  components[:userinfo] = splits.first
228
- url = splits.shift
229
201
  end
230
202
 
231
203
  if !splits.empty?
232
204
  splits = splits.last.split( '/', 2 )
233
- url = splits.last
234
205
 
235
206
  splits = splits.first.split( ':', 2 )
236
207
  if splits.size == 2
237
208
  host = splits.first
238
209
 
239
210
  if splits.last && !splits.last.empty?
240
- components[:port] = Integer( splits.last )
211
+ components[:port] = splits.last.to_i
241
212
  end
242
213
 
243
214
  if components[:port] == 80
244
215
  components[:port] = nil
245
216
  end
246
-
247
- url.gsub!( ':' + components[:port].to_s, '' )
248
217
  else
249
218
  host = splits.last
250
219
  end
251
220
 
252
- if components[:host] = host
253
- url.gsub!( host, '' )
221
+ if (components[:host] = host)
254
222
  components[:host].downcase!
255
223
  end
256
224
  else
@@ -265,20 +233,20 @@ class URI
265
233
  splits = url.split( '?', 2 )
266
234
  if (components[:path] = splits.shift)
267
235
  if components[:scheme]
268
- components[:path] = '/' + components[:path]
236
+ components[:path] = "/#{components[:path]}"
269
237
  end
270
238
 
271
239
  components[:path].gsub!( /\/+/, '/' )
272
240
 
273
241
  # Remove path params
274
- components[:path] = components[:path].split( ';', 2 ).first
242
+ components[:path].sub!( /\;.*/, '' )
275
243
 
276
244
  if components[:path]
277
245
  components[:path] =
278
246
  encode( decode( components[:path] ),
279
- Addressable::URI::CharacterClasses::PATH )
247
+ Addressable::URI::CharacterClasses::PATH ).dup
280
248
 
281
- components[:path] = ::URI.encode( components[:path], ';' )
249
+ components[:path].gsub!( ';', '%3B' )
282
250
  end
283
251
  end
284
252
 
@@ -286,68 +254,33 @@ class URI
286
254
  !(query = dupped_url.split( '?', 2 ).last).empty?
287
255
 
288
256
  components[:query] = (query.split( '&', -1 ).map do |pair|
289
- encode( decode( pair ),
290
- Addressable::URI::CharacterClasses::QUERY.sub( '\\&', '' ) )
257
+ encode( decode( pair ), QUERY_CHARACTER_CLASS )
291
258
  end).join( '&' )
292
259
  end
293
260
  end
294
261
 
262
+ if schemeless
263
+ components.delete :scheme
264
+ end
265
+
295
266
  components[:path] ||= components[:scheme] ? '/' : nil
296
267
 
297
268
  components.values.each(&:freeze)
298
269
 
299
270
  cache[c_url] = components.freeze
300
271
  rescue => e
301
- begin
302
- print_debug "Failed to fast-parse '#{c_url}', falling back to slow-parse."
303
- print_debug "Error: #{e}"
304
- print_debug_backtrace( e )
272
+ ap e
273
+ ap e.backtrace
274
+ ap c_url
275
+ ap url
305
276
 
306
- cache[c_url] = addressable_parse( c_url.recode! ).freeze
307
- rescue => ex
308
- print_debug "Failed to parse '#{c_url}'."
309
- print_debug "Error: #{ex}"
310
- print_debug_backtrace( ex )
311
-
312
- cache[c_url] = :err
313
- nil
314
- end
315
- end
316
- end
277
+ print_debug "Failed to parse '#{c_url}'."
278
+ print_debug "Error: #{e}"
279
+ print_debug_backtrace( e )
317
280
 
318
- # @note The Hash is suitable for passing to `::URI::Generic.build` -- if
319
- # however you plan on doing that you'll be better off just using
320
- # {.ruby_parse} which does the same thing and caches the results for
321
- # some extra schnell.
322
- #
323
- # Performs a parse using the `URI::Addressable` lib while normalizing the
324
- # URL (will also discard the fragment).
325
- #
326
- # This method is not cached and solely exists as a fallback used by {.fast_parse}.
327
- #
328
- # @param [String] url
329
- #
330
- # @return [Hash]
331
- # URL components:
332
- #
333
- # * `:scheme` -- HTTP or HTTPS
334
- # * `:userinfo` -- `username:password`
335
- # * `:host`
336
- # * `:port`
337
- # * `:path`
338
- # * `:query`
339
- #
340
- def addressable_parse( url )
341
- u = Addressable::URI.parse( html_decode( url.to_s ) ).normalize
342
- u.fragment = nil
343
- h = u.to_hash
344
-
345
- h[:path].gsub!( /\/+/, '/' ) if h[:path]
346
- if h[:user]
347
- h[:userinfo] = h.delete( :user )
348
- h[:userinfo] << ":#{h.delete( :password )}" if h[:password]
281
+ cache[c_url] = :err
282
+ nil
349
283
  end
350
- h
351
284
  end
352
285
 
353
286
  # @note This method's results are cached for performance reasons.
@@ -366,8 +299,8 @@ class URI
366
299
  # @return [String]
367
300
  # Absolute URL (frozen).
368
301
  def to_absolute( relative, reference = Options.instance.url.to_s )
369
- return reference if !relative || relative.empty?
370
- key = relative + ' :: ' + reference
302
+ return normalize( reference ) if !relative || relative.empty?
303
+ key = [relative, reference].hash
371
304
 
372
305
  cache = CACHE[__method__]
373
306
  begin
@@ -385,7 +318,13 @@ class URI
385
318
  relative = "#{parsed_ref.scheme}:#{relative}"
386
319
  end
387
320
 
388
- cache[key] = parse( relative ).to_absolute( parsed_ref ).to_s.freeze
321
+ parsed = parse( relative )
322
+
323
+ # Doesn't contain anything or interest (javascript: or fragment only),
324
+ # return the ref.
325
+ return parsed_ref.to_s if !parsed
326
+
327
+ cache[key] = parsed.to_absolute( parsed_ref ).to_s.freeze
389
328
  rescue
390
329
  cache[key] = :err
391
330
  nil
@@ -418,25 +357,7 @@ class URI
418
357
  return v
419
358
  end
420
359
 
421
- components = fast_parse( url )
422
-
423
- normalized = ''
424
- normalized << components[:scheme] + '://' if components[:scheme]
425
-
426
- if components[:userinfo]
427
- normalized << components[:userinfo]
428
- normalized << '@'
429
- end
430
-
431
- if components[:host]
432
- normalized << components[:host]
433
- normalized << ':' + components[:port].to_s if components[:port]
434
- end
435
-
436
- normalized << components[:path] if components[:path]
437
- normalized << '?' + components[:query] if components[:query]
438
-
439
- cache[c_url] = normalized.freeze
360
+ cache[c_url] = parse( url ).to_s.freeze
440
361
  rescue => e
441
362
  print_debug "Failed to normalize '#{c_url}'."
442
363
  print_debug "Error: #{e}"
@@ -488,35 +409,19 @@ class URI
488
409
  #
489
410
  # {.normalize Normalizes} and parses the provided URL.
490
411
  #
491
- # @param [Arachni::URI, String, URI, Hash] url
412
+ # @param [String] url
492
413
  # {String} URL to parse, `URI` to convert, or a `Hash` holding URL components
493
414
  # (for `URI::Generic.build`). Also accepts {Arachni::URI} for convenience.
494
415
  def initialize( url )
495
- @parsed_url = case url
496
- when String
497
- self.class.ruby_parse( url )
498
-
499
- when ::URI
500
- url
501
-
502
- when Hash
503
- ::URI::Generic.build( url )
416
+ @data = self.class.fast_parse( url )
504
417
 
505
- when Arachni::URI
506
- self.parsed_url = url.parsed_url
418
+ fail Error, 'Failed to parse URL.' if !@data
507
419
 
508
- else
509
- to_string = url.to_s rescue ''
510
- msg = 'Argument must either be String, URI or Hash'
511
- msg << " -- #{url.class.name} '#{to_string}' passed."
512
- fail ArgumentError.new( msg )
513
- end
514
-
515
- fail Error, 'Failed to parse URL.' if !@parsed_url
420
+ %w(scheme userinfo host port path query).each do |part|
421
+ instance_variable_set( "@#{part}", @data[part.to_sym] )
422
+ end
516
423
 
517
- # We probably got it from the cache, dup it to avoid corrupting the cache
518
- # entries.
519
- @parsed_url = @parsed_url.dup
424
+ reset_userpass
520
425
  end
521
426
 
522
427
  # @return [Scope]
@@ -528,25 +433,106 @@ class URI
528
433
  to_s == other.to_s
529
434
  end
530
435
 
436
+ def absolute?
437
+ !!@scheme
438
+ end
439
+
440
+ def relative?
441
+ !absolute?
442
+ end
443
+
531
444
  # Converts self into an absolute URL using `reference` to fill in the
532
445
  # missing data.
533
446
  #
534
- # @param [Arachni::URI, URI, String] reference
447
+ # @param [Arachni::URI, #to_s] reference
535
448
  # Full, absolute URL.
536
449
  #
537
450
  # @return [Arachni::URI]
538
- # Self, as an absolute URL.
539
- def to_absolute( reference )
540
- absolute = case reference
541
- when Arachni::URI
542
- reference.parsed_url
543
- when ::URI
544
- reference
545
- else
546
- self.class.new( reference.to_s ).parsed_url
547
- end.merge( @parsed_url )
451
+ # Copy of self, as an absolute URL.
452
+ def to_absolute!( reference )
453
+ if !reference.is_a?( self.class )
454
+ reference = self.class.new( reference.to_s )
455
+ end
456
+
457
+ %w(scheme userinfo host port).each do |part|
458
+ next if send( part )
459
+
460
+ ref_part = reference.send( "#{part}" )
461
+ next if !ref_part
548
462
 
549
- self.class.new( absolute )
463
+ send( "#{part}=", ref_part )
464
+ end
465
+
466
+ base_path = reference.path.split( %r{/+}, -1 )
467
+ rel_path = path.split( %r{/+}, -1 )
468
+
469
+ # RFC2396, Section 5.2, 6), a)
470
+ base_path << '' if base_path.last == '..'
471
+ while (i = base_path.index( '..' ))
472
+ base_path.slice!( i - 1, 2 )
473
+ end
474
+
475
+ if (first = rel_path.first) && first.empty?
476
+ base_path.clear
477
+ rel_path.shift
478
+ end
479
+
480
+ # RFC2396, Section 5.2, 6), c)
481
+ # RFC2396, Section 5.2, 6), d)
482
+ rel_path.push('') if rel_path.last == '.' || rel_path.last == '..'
483
+ rel_path.delete('.')
484
+
485
+ # RFC2396, Section 5.2, 6), e)
486
+ tmp = []
487
+ rel_path.each do |x|
488
+ if x == '..' &&
489
+ !(tmp.empty? || tmp.last == '..')
490
+ tmp.pop
491
+ else
492
+ tmp << x
493
+ end
494
+ end
495
+
496
+ add_trailer_slash = !tmp.empty?
497
+ if base_path.empty?
498
+ base_path = [''] # keep '/' for root directory
499
+ elsif add_trailer_slash
500
+ base_path.pop
501
+ end
502
+
503
+ while (x = tmp.shift)
504
+ if x == '..'
505
+ # RFC2396, Section 4
506
+ # a .. or . in an absolute path has no special meaning
507
+ base_path.pop if base_path.size > 1
508
+ else
509
+ # if x == '..'
510
+ # valid absolute (but abnormal) path "/../..."
511
+ # else
512
+ # valid absolute path
513
+ # end
514
+ base_path << x
515
+ tmp.each {|t| base_path << t}
516
+ add_trailer_slash = false
517
+ break
518
+ end
519
+ end
520
+
521
+ base_path.push('') if add_trailer_slash
522
+ @path = base_path.join('/')
523
+
524
+ self
525
+ end
526
+
527
+ # @return [Bool]
528
+ # `true` if the scan #{Utilities.random_seed seed} is included in the
529
+ # domain, `false` otherwise.
530
+ def seed_in_host?
531
+ host.to_s.include?( Utilities.random_seed )
532
+ end
533
+
534
+ def to_absolute( reference )
535
+ dup.to_absolute!( reference )
550
536
  end
551
537
 
552
538
  # @return [String]
@@ -580,9 +566,19 @@ class URI
580
566
 
581
567
  uri_path << '/' if uri_path[-1] != '/'
582
568
 
569
+ up_to_port << uri_path
570
+ end
571
+
572
+ # @return [String]
573
+ # Scheme, host & port only.
574
+ def up_to_port
583
575
  uri_str = "#{scheme}://#{host}"
584
- uri_str << ':' + port.to_s if port && port != 80
585
- uri_str << uri_path
576
+
577
+ if port && ((scheme == 'http' && port != 80) || (scheme == 'https' && port != 443))
578
+ uri_str << ':' + port.to_s
579
+ end
580
+
581
+ uri_str
586
582
  end
587
583
 
588
584
  # @return [String]
@@ -621,15 +617,15 @@ class URI
621
617
  !(IPAddr.new( host ) rescue nil).nil?
622
618
  end
623
619
 
624
- def mailto?
625
- scheme == 'mailto'
620
+ def query
621
+ @query
626
622
  end
627
623
 
628
624
  def query=( q )
629
625
  q = q.to_s
630
626
  q = nil if q.empty?
631
627
 
632
- @parsed_url.query = q
628
+ @query = q
633
629
  end
634
630
 
635
631
  # @return [Hash]
@@ -645,9 +641,95 @@ class URI
645
641
  end
646
642
  end
647
643
 
644
+ def userinfo=( ui )
645
+ @userinfo = ui
646
+ ensure
647
+ reset_userpass
648
+ end
649
+
650
+ def userinfo
651
+ @userinfo
652
+ end
653
+
654
+ def user
655
+ @user
656
+ end
657
+
658
+ def password
659
+ @password
660
+ end
661
+
662
+ def port
663
+ @port
664
+ end
665
+
666
+ def port=( p )
667
+ if p
668
+ @port = p.to_i
669
+ else
670
+ @port = nil
671
+ end
672
+ end
673
+
674
+ def host
675
+ @host
676
+ end
677
+
678
+ def host=( h )
679
+ @host = h
680
+ end
681
+
682
+ def path
683
+ @path
684
+ end
685
+
686
+ def path=( p )
687
+ @path = p
688
+ end
689
+
690
+ def scheme
691
+ @scheme
692
+ end
693
+
694
+ def scheme=( s )
695
+ @scheme = s
696
+ end
697
+
648
698
  # @return [String]
649
699
  def to_s
650
- @parsed_url.to_s
700
+ s = ''
701
+
702
+ if @scheme
703
+ s << @scheme
704
+ s << '://'
705
+ end
706
+
707
+ if @userinfo
708
+ s << @userinfo
709
+ s << '@'
710
+ end
711
+
712
+ if @host
713
+ s << @host
714
+
715
+ if @port
716
+ if (@scheme == 'http' && @port != 80) ||
717
+ (@scheme == 'https' && @port != 443)
718
+
719
+ s << ':'
720
+ s << @port.to_s
721
+ end
722
+ end
723
+ end
724
+
725
+ s << @path.to_s
726
+
727
+ if @query
728
+ s << '?'
729
+ s << @query
730
+ end
731
+
732
+ s
651
733
  end
652
734
 
653
735
  def dup
@@ -670,29 +752,29 @@ class URI
670
752
  to_s.persistent_hash
671
753
  end
672
754
 
673
- # Delegates unimplemented methods to Ruby's `URI::Generic` class for
674
- # compatibility.
675
- def method_missing( sym, *args, &block )
676
- if @parsed_url.respond_to?( sym )
677
- @parsed_url.send( sym, *args, &block )
755
+ private
756
+
757
+ def reset_userpass
758
+ if @userinfo
759
+ @user, @password = @userinfo.split( ':', -1 )
678
760
  else
679
- super
761
+ @user = @password = nil
680
762
  end
681
763
  end
682
764
 
683
- def respond_to?( *args )
684
- super || @parsed_url.respond_to?( *args )
685
- end
686
-
687
- protected
688
-
689
- def parsed_url
690
- @parsed_url
691
- end
692
-
693
- def parsed_url=( url )
694
- @parsed_url = url
695
- end
765
+ # Delegates unimplemented methods to Ruby's `URI::Generic` class for
766
+ # compatibility.
767
+ # def method_missing( sym, *args, &block )
768
+ # if @data.respond_to?( sym )
769
+ # @parsed_url.send( sym, *args, &block )
770
+ # else
771
+ # super
772
+ # end
773
+ # end
774
+ #
775
+ # def respond_to?( *args )
776
+ # super || @parsed_url.respond_to?( *args )
777
+ # end
696
778
 
697
779
  end
698
780
  end