arachni 1.3.2 → 1.4

Sign up to get free protection for your applications and to get access to all the features.
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