arachni 0.2.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (262) hide show
  1. data/ACKNOWLEDGMENTS.md +14 -0
  2. data/AUTHORS.md +6 -0
  3. data/CHANGELOG.md +162 -0
  4. data/CONTRIBUTORS.md +10 -0
  5. data/EXPLOITATION.md +429 -0
  6. data/HACKING.md +101 -0
  7. data/LICENSE.md +341 -0
  8. data/README.md +350 -0
  9. data/Rakefile +86 -0
  10. data/bin/arachni +22 -0
  11. data/bin/arachni_web +77 -0
  12. data/bin/arachni_xmlrpc +21 -0
  13. data/bin/arachni_xmlrpcd +82 -0
  14. data/bin/arachni_xmlrpcd_monitor +74 -0
  15. data/conf/README.webui.yaml.txt +44 -0
  16. data/conf/webui.yaml +11 -0
  17. data/external/metasploit/LICENSE +24 -0
  18. data/external/metasploit/modules/exploits/unix/webapp/arachni_exec.rb +142 -0
  19. data/external/metasploit/modules/exploits/unix/webapp/arachni_path_traversal.rb +113 -0
  20. data/external/metasploit/modules/exploits/unix/webapp/arachni_php_eval.rb +150 -0
  21. data/external/metasploit/modules/exploits/unix/webapp/arachni_php_include.rb +141 -0
  22. data/external/metasploit/modules/exploits/unix/webapp/arachni_sqlmap.rb +92 -0
  23. data/external/metasploit/plugins/arachni.rb +536 -0
  24. data/getoptslong.rb +241 -0
  25. data/lib/anemone.rb +2 -0
  26. data/lib/anemone/cookie_store.rb +35 -0
  27. data/lib/anemone/core.rb +371 -0
  28. data/lib/anemone/exceptions.rb +5 -0
  29. data/lib/anemone/http.rb +144 -0
  30. data/lib/anemone/page.rb +337 -0
  31. data/lib/anemone/page_store.rb +160 -0
  32. data/lib/anemone/storage.rb +34 -0
  33. data/lib/anemone/storage/base.rb +75 -0
  34. data/lib/anemone/storage/exceptions.rb +15 -0
  35. data/lib/anemone/storage/mongodb.rb +89 -0
  36. data/lib/anemone/storage/pstore.rb +50 -0
  37. data/lib/anemone/storage/redis.rb +90 -0
  38. data/lib/anemone/storage/tokyo_cabinet.rb +57 -0
  39. data/lib/anemone/tentacle.rb +40 -0
  40. data/lib/arachni.rb +16 -0
  41. data/lib/audit_store.rb +346 -0
  42. data/lib/component_manager.rb +293 -0
  43. data/lib/component_options.rb +395 -0
  44. data/lib/exceptions.rb +76 -0
  45. data/lib/framework.rb +637 -0
  46. data/lib/http.rb +809 -0
  47. data/lib/issue.rb +302 -0
  48. data/lib/module.rb +4 -0
  49. data/lib/module/auditor.rb +455 -0
  50. data/lib/module/base.rb +188 -0
  51. data/lib/module/element_db.rb +158 -0
  52. data/lib/module/key_filler.rb +87 -0
  53. data/lib/module/manager.rb +87 -0
  54. data/lib/module/output.rb +68 -0
  55. data/lib/module/trainer.rb +240 -0
  56. data/lib/module/utilities.rb +110 -0
  57. data/lib/options.rb +547 -0
  58. data/lib/parser.rb +2 -0
  59. data/lib/parser/auditable.rb +522 -0
  60. data/lib/parser/elements.rb +296 -0
  61. data/lib/parser/page.rb +149 -0
  62. data/lib/parser/parser.rb +717 -0
  63. data/lib/plugin.rb +4 -0
  64. data/lib/plugin/base.rb +110 -0
  65. data/lib/plugin/manager.rb +162 -0
  66. data/lib/report.rb +4 -0
  67. data/lib/report/base.rb +119 -0
  68. data/lib/report/manager.rb +92 -0
  69. data/lib/rpc/xml/client/base.rb +71 -0
  70. data/lib/rpc/xml/client/dispatcher.rb +49 -0
  71. data/lib/rpc/xml/client/instance.rb +88 -0
  72. data/lib/rpc/xml/server/base.rb +90 -0
  73. data/lib/rpc/xml/server/dispatcher.rb +357 -0
  74. data/lib/rpc/xml/server/framework.rb +206 -0
  75. data/lib/rpc/xml/server/instance.rb +191 -0
  76. data/lib/rpc/xml/server/module/manager.rb +46 -0
  77. data/lib/rpc/xml/server/options.rb +124 -0
  78. data/lib/rpc/xml/server/output.rb +299 -0
  79. data/lib/rpc/xml/server/plugin/manager.rb +58 -0
  80. data/lib/ruby.rb +5 -0
  81. data/lib/ruby/object.rb +32 -0
  82. data/lib/ruby/string.rb +74 -0
  83. data/lib/ruby/xmlrpc/server.rb +27 -0
  84. data/lib/spider.rb +200 -0
  85. data/lib/typhoeus/request.rb +91 -0
  86. data/lib/typhoeus/response.rb +34 -0
  87. data/lib/ui/cli/cli.rb +744 -0
  88. data/lib/ui/cli/output.rb +279 -0
  89. data/lib/ui/web/log.rb +82 -0
  90. data/lib/ui/web/output_stream.rb +94 -0
  91. data/lib/ui/web/report_manager.rb +222 -0
  92. data/lib/ui/web/server.rb +903 -0
  93. data/lib/ui/web/server/db/placeholder +0 -0
  94. data/lib/ui/web/server/public/banner.png +0 -0
  95. data/lib/ui/web/server/public/bodybg-small.png +0 -0
  96. data/lib/ui/web/server/public/bodybg.png +0 -0
  97. data/lib/ui/web/server/public/css/smoothness/images/pbar-ani.gif +0 -0
  98. data/lib/ui/web/server/public/css/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  99. data/lib/ui/web/server/public/css/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  100. data/lib/ui/web/server/public/css/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  101. data/lib/ui/web/server/public/css/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  102. data/lib/ui/web/server/public/css/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  103. data/lib/ui/web/server/public/css/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  104. data/lib/ui/web/server/public/css/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  105. data/lib/ui/web/server/public/css/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  106. data/lib/ui/web/server/public/css/smoothness/images/ui-icons_222222_256x240.png +0 -0
  107. data/lib/ui/web/server/public/css/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
  108. data/lib/ui/web/server/public/css/smoothness/images/ui-icons_454545_256x240.png +0 -0
  109. data/lib/ui/web/server/public/css/smoothness/images/ui-icons_888888_256x240.png +0 -0
  110. data/lib/ui/web/server/public/css/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
  111. data/lib/ui/web/server/public/css/smoothness/jquery-ui-1.8.9.custom.css +573 -0
  112. data/lib/ui/web/server/public/favicon.ico +0 -0
  113. data/lib/ui/web/server/public/footer.jpg +0 -0
  114. data/lib/ui/web/server/public/icons/error.png +0 -0
  115. data/lib/ui/web/server/public/icons/info.png +0 -0
  116. data/lib/ui/web/server/public/icons/ok.png +0 -0
  117. data/lib/ui/web/server/public/icons/status.png +0 -0
  118. data/lib/ui/web/server/public/js/jquery-1.4.4.min.js +167 -0
  119. data/lib/ui/web/server/public/js/jquery-ui-1.8.9.custom.min.js +781 -0
  120. data/lib/ui/web/server/public/logo.png +0 -0
  121. data/lib/ui/web/server/public/nav-left.jpg +0 -0
  122. data/lib/ui/web/server/public/nav-right.jpg +0 -0
  123. data/lib/ui/web/server/public/nav-selected-left.jpg +0 -0
  124. data/lib/ui/web/server/public/nav-selected-right.jpg +0 -0
  125. data/lib/ui/web/server/public/reports/placeholder +1 -0
  126. data/lib/ui/web/server/public/sidebar-bottom.jpg +0 -0
  127. data/lib/ui/web/server/public/sidebar-h4.jpg +0 -0
  128. data/lib/ui/web/server/public/sidebar-top.jpg +0 -0
  129. data/lib/ui/web/server/public/spider.png +0 -0
  130. data/lib/ui/web/server/public/style.css +604 -0
  131. data/lib/ui/web/server/tmp/placeholder +0 -0
  132. data/lib/ui/web/server/views/dispatcher.erb +85 -0
  133. data/lib/ui/web/server/views/dispatcher_error.erb +14 -0
  134. data/lib/ui/web/server/views/error.erb +1 -0
  135. data/lib/ui/web/server/views/flash.erb +18 -0
  136. data/lib/ui/web/server/views/home.erb +14 -0
  137. data/lib/ui/web/server/views/instance.erb +213 -0
  138. data/lib/ui/web/server/views/layout.erb +95 -0
  139. data/lib/ui/web/server/views/log.erb +40 -0
  140. data/lib/ui/web/server/views/modules.erb +71 -0
  141. data/lib/ui/web/server/views/options.erb +23 -0
  142. data/lib/ui/web/server/views/output_results.erb +51 -0
  143. data/lib/ui/web/server/views/plugins.erb +42 -0
  144. data/lib/ui/web/server/views/report_formats.erb +30 -0
  145. data/lib/ui/web/server/views/reports.erb +55 -0
  146. data/lib/ui/web/server/views/settings.erb +120 -0
  147. data/lib/ui/web/server/views/welcome.erb +38 -0
  148. data/lib/ui/xmlrpc/dispatcher_monitor.rb +204 -0
  149. data/lib/ui/xmlrpc/xmlrpc.rb +843 -0
  150. data/logs/placeholder +0 -0
  151. data/metamodules/autothrottle.rb +74 -0
  152. data/metamodules/timeout_notice.rb +118 -0
  153. data/metamodules/uniformity.rb +98 -0
  154. data/modules/audit/code_injection.rb +136 -0
  155. data/modules/audit/code_injection_timing.rb +115 -0
  156. data/modules/audit/code_injection_timing/payloads.txt +4 -0
  157. data/modules/audit/csrf.rb +301 -0
  158. data/modules/audit/ldapi.rb +103 -0
  159. data/modules/audit/ldapi/errors.txt +26 -0
  160. data/modules/audit/os_cmd_injection.rb +103 -0
  161. data/modules/audit/os_cmd_injection/payloads.txt +2 -0
  162. data/modules/audit/os_cmd_injection_timing.rb +104 -0
  163. data/modules/audit/os_cmd_injection_timing/payloads.txt +3 -0
  164. data/modules/audit/path_traversal.rb +141 -0
  165. data/modules/audit/response_splitting.rb +105 -0
  166. data/modules/audit/rfi.rb +193 -0
  167. data/modules/audit/sqli.rb +120 -0
  168. data/modules/audit/sqli/regexp_ids.txt +90 -0
  169. data/modules/audit/sqli_blind_rdiff.rb +321 -0
  170. data/modules/audit/sqli_blind_timing.rb +103 -0
  171. data/modules/audit/sqli_blind_timing/payloads.txt +51 -0
  172. data/modules/audit/trainer.rb +89 -0
  173. data/modules/audit/unvalidated_redirect.rb +90 -0
  174. data/modules/audit/xpath.rb +104 -0
  175. data/modules/audit/xpath/errors.txt +26 -0
  176. data/modules/audit/xss.rb +99 -0
  177. data/modules/audit/xss_event.rb +134 -0
  178. data/modules/audit/xss_path.rb +125 -0
  179. data/modules/audit/xss_script_tag.rb +112 -0
  180. data/modules/audit/xss_tag.rb +112 -0
  181. data/modules/audit/xss_uri.rb +125 -0
  182. data/modules/recon/allowed_methods.rb +104 -0
  183. data/modules/recon/backdoors.rb +131 -0
  184. data/modules/recon/backdoors/filenames.txt +16 -0
  185. data/modules/recon/backup_files.rb +177 -0
  186. data/modules/recon/backup_files/extensions.txt +28 -0
  187. data/modules/recon/common_directories.rb +138 -0
  188. data/modules/recon/common_directories/directories.txt +265 -0
  189. data/modules/recon/common_files.rb +138 -0
  190. data/modules/recon/common_files/filenames.txt +17 -0
  191. data/modules/recon/directory_listing.rb +171 -0
  192. data/modules/recon/grep/captcha.rb +62 -0
  193. data/modules/recon/grep/credit_card.rb +85 -0
  194. data/modules/recon/grep/cvs_svn_users.rb +73 -0
  195. data/modules/recon/grep/emails.rb +59 -0
  196. data/modules/recon/grep/html_objects.rb +53 -0
  197. data/modules/recon/grep/private_ip.rb +54 -0
  198. data/modules/recon/grep/ssn.rb +53 -0
  199. data/modules/recon/htaccess_limit.rb +82 -0
  200. data/modules/recon/http_put.rb +95 -0
  201. data/modules/recon/interesting_responses.rb +118 -0
  202. data/modules/recon/unencrypted_password_forms.rb +119 -0
  203. data/modules/recon/webdav.rb +126 -0
  204. data/modules/recon/xst.rb +107 -0
  205. data/path_extractors/anchors.rb +35 -0
  206. data/path_extractors/forms.rb +35 -0
  207. data/path_extractors/frames.rb +38 -0
  208. data/path_extractors/generic.rb +39 -0
  209. data/path_extractors/links.rb +35 -0
  210. data/path_extractors/meta_refresh.rb +39 -0
  211. data/path_extractors/scripts.rb +37 -0
  212. data/path_extractors/sitemap.rb +31 -0
  213. data/plugins/autologin.rb +137 -0
  214. data/plugins/content_types.rb +90 -0
  215. data/plugins/cookie_collector.rb +99 -0
  216. data/plugins/form_dicattack.rb +185 -0
  217. data/plugins/healthmap.rb +94 -0
  218. data/plugins/http_dicattack.rb +133 -0
  219. data/plugins/metamodules.rb +118 -0
  220. data/plugins/proxy.rb +248 -0
  221. data/plugins/proxy/server.rb +66 -0
  222. data/plugins/waf_detector.rb +184 -0
  223. data/profiles/comprehensive.afp +74 -0
  224. data/profiles/full.afp +75 -0
  225. data/reports/afr.rb +59 -0
  226. data/reports/ap.rb +55 -0
  227. data/reports/html.rb +179 -0
  228. data/reports/html/default.erb +967 -0
  229. data/reports/metareport.rb +139 -0
  230. data/reports/metareport/arachni_metareport.rb +174 -0
  231. data/reports/plugin_formatters/html/content_types.rb +82 -0
  232. data/reports/plugin_formatters/html/cookie_collector.rb +66 -0
  233. data/reports/plugin_formatters/html/form_dicattack.rb +54 -0
  234. data/reports/plugin_formatters/html/healthmap.rb +76 -0
  235. data/reports/plugin_formatters/html/http_dicattack.rb +54 -0
  236. data/reports/plugin_formatters/html/metaformatters/timeout_notice.rb +65 -0
  237. data/reports/plugin_formatters/html/metaformatters/uniformity.rb +71 -0
  238. data/reports/plugin_formatters/html/metamodules.rb +93 -0
  239. data/reports/plugin_formatters/html/waf_detector.rb +54 -0
  240. data/reports/plugin_formatters/stdout/content_types.rb +73 -0
  241. data/reports/plugin_formatters/stdout/cookie_collector.rb +61 -0
  242. data/reports/plugin_formatters/stdout/form_dicattack.rb +52 -0
  243. data/reports/plugin_formatters/stdout/healthmap.rb +72 -0
  244. data/reports/plugin_formatters/stdout/http_dicattack.rb +53 -0
  245. data/reports/plugin_formatters/stdout/metaformatters/timeout_notice.rb +55 -0
  246. data/reports/plugin_formatters/stdout/metaformatters/uniformity.rb +68 -0
  247. data/reports/plugin_formatters/stdout/metamodules.rb +89 -0
  248. data/reports/plugin_formatters/stdout/waf_detector.rb +48 -0
  249. data/reports/plugin_formatters/xml/content_types.rb +91 -0
  250. data/reports/plugin_formatters/xml/cookie_collector.rb +70 -0
  251. data/reports/plugin_formatters/xml/form_dicattack.rb +57 -0
  252. data/reports/plugin_formatters/xml/healthmap.rb +82 -0
  253. data/reports/plugin_formatters/xml/http_dicattack.rb +57 -0
  254. data/reports/plugin_formatters/xml/metaformatters/timeout_notice.rb +67 -0
  255. data/reports/plugin_formatters/xml/metaformatters/uniformity.rb +82 -0
  256. data/reports/plugin_formatters/xml/metamodules.rb +91 -0
  257. data/reports/plugin_formatters/xml/waf_detector.rb +58 -0
  258. data/reports/stdout.rb +182 -0
  259. data/reports/txt.rb +77 -0
  260. data/reports/xml.rb +231 -0
  261. data/reports/xml/buffer.rb +98 -0
  262. metadata +516 -0
@@ -0,0 +1,76 @@
1
+ =begin
2
+ Arachni
3
+ Copyright (c) 2010-2011 Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
4
+
5
+ This is free software; you can copy and distribute and modify
6
+ this program under the term of the GPL v2.0 License
7
+ (See LICENSE file for details)
8
+
9
+ =end
10
+
11
+ module Arachni
12
+
13
+ #
14
+ # Arachni::Exceptions module<br/>
15
+ # It holds the framework's exceptions.
16
+ #
17
+ # @author: Tasos "Zapotek" Laskos
18
+ # <tasos.laskos@gmail.com>
19
+ # <zapotek@segfault.gr>
20
+ # @version: 0.1
21
+ #
22
+ module Exceptions
23
+
24
+ def initialize( msg )
25
+ super( msg )
26
+ end
27
+
28
+
29
+ class NoAuditOpts < StandardError
30
+ include Exceptions
31
+
32
+ end
33
+
34
+ class NoMods < StandardError
35
+ include Exceptions
36
+
37
+ end
38
+
39
+ class ComponentNotFound < StandardError
40
+ include Exceptions
41
+
42
+ end
43
+
44
+ class ModNotFound < StandardError
45
+ include Exceptions
46
+
47
+ end
48
+
49
+ class DepModNotFound < StandardError
50
+ include Exceptions
51
+
52
+ end
53
+
54
+ class ReportNotFound < StandardError
55
+ include Exceptions
56
+
57
+ end
58
+
59
+ class NoURL < StandardError
60
+ include Exceptions
61
+
62
+ end
63
+
64
+ class InvalidURL < StandardError
65
+ include Exceptions
66
+
67
+ end
68
+
69
+ class NoCookieJar < StandardError
70
+ include Exceptions
71
+
72
+ end
73
+
74
+ end
75
+
76
+ end
@@ -0,0 +1,637 @@
1
+ =begin
2
+ Arachni
3
+ Copyright (c) 2010-2011 Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
4
+
5
+ This is free software; you can copy and distribute and modify
6
+ this program under the term of the GPL v2.0 License
7
+ (See LICENSE file for details)
8
+
9
+ =end
10
+
11
+
12
+ require 'rubygems'
13
+
14
+ require File.expand_path( File.dirname( __FILE__ ) ) + '/options'
15
+ opts = Arachni::Options.instance
16
+
17
+ require opts.dir['lib'] + 'arachni'
18
+ require opts.dir['lib'] + 'ruby'
19
+ require opts.dir['lib'] + 'exceptions'
20
+ require opts.dir['lib'] + 'spider'
21
+ require opts.dir['lib'] + 'parser'
22
+ require opts.dir['lib'] + 'audit_store'
23
+ require opts.dir['lib'] + 'module'
24
+ require opts.dir['lib'] + 'plugin'
25
+ require opts.dir['lib'] + 'http'
26
+ require opts.dir['lib'] + 'report'
27
+ require opts.dir['lib'] + 'component_manager'
28
+ require 'yaml'
29
+ require 'ap'
30
+ require 'pp'
31
+
32
+
33
+ module Arachni
34
+
35
+ #
36
+ # Resets the Framework providing a clean slate.
37
+ #
38
+ # This is useful to user interfaces that require the framework to be reused.
39
+ #
40
+ def self.reset
41
+ Element::Auditable.reset
42
+ Module::Manager.reset
43
+ Report::Manager.reset
44
+ Arachni::HTTP.instance.reset
45
+ end
46
+
47
+ #
48
+ # Arachni::Framework class
49
+ #
50
+ # The Framework class ties together all the components.<br/>
51
+ # It should be wrapped by a UI class.
52
+ #
53
+ # It's the brains of the operation, it bosses the rest of the classes around.<br/>
54
+ # It runs the audit, loads modules and reports and runs them according to
55
+ # user options.
56
+ #
57
+ # @author: Tasos "Zapotek" Laskos
58
+ # <tasos.laskos@gmail.com>
59
+ # <zapotek@segfault.gr>
60
+ # @version: 0.2.1
61
+ #
62
+ class Framework
63
+
64
+ #
65
+ # include the output interface but try to use it as little as possible
66
+ #
67
+ # the UI classes should take care of communicating with the user
68
+ #
69
+ include Arachni::UI::Output
70
+ include Arachni::Module::Utilities
71
+
72
+ # the version of *this* class
73
+ REVISION = '0.2.1'
74
+
75
+ #
76
+ # Instance options
77
+ #
78
+ # @return [Options]
79
+ #
80
+ attr_reader :opts
81
+
82
+ #
83
+ # @return [Arachni::Report::Manager] report manager
84
+ #
85
+ attr_reader :reports
86
+
87
+ #
88
+ # @return [Arachni::Module::Manager] module manager
89
+ #
90
+ attr_reader :modules
91
+
92
+ #
93
+ # @return [Arachni::Plugin::Manager] plugin manager
94
+ #
95
+ attr_reader :plugins
96
+
97
+ #
98
+ # @return [Arachni::Spider] spider
99
+ #
100
+ attr_reader :spider
101
+
102
+ #
103
+ # @return [Arachni::HTTP]
104
+ #
105
+ attr_reader :http
106
+
107
+ attr_reader :sitemap
108
+ attr_reader :auditmap
109
+
110
+ #
111
+ # Holds candidate pages to be audited.
112
+ #
113
+ # Pages in the queue are pushed in by the trainer, the queue doesn't hold
114
+ # pages returned by the spider.
115
+ #
116
+ # Plug-ins can push their own pages to be audited if they wish to...
117
+ #
118
+ # @return [Queue<Arachni::Parser::Page>] page queue
119
+ #
120
+ attr_reader :page_queue
121
+
122
+
123
+ #
124
+ # Initializes system components.
125
+ #
126
+ # @param [Options] opts
127
+ #
128
+ def initialize( opts )
129
+
130
+ Encoding.default_external = "BINARY"
131
+ Encoding.default_internal = "BINARY"
132
+
133
+ @opts = opts
134
+
135
+ @modules = Arachni::Module::Manager.new( @opts )
136
+ @reports = Arachni::Report::Manager.new( @opts )
137
+ @plugins = Arachni::Plugin::Manager.new( self )
138
+
139
+ @page_queue = Queue.new
140
+
141
+ prepare_cookie_jar( )
142
+ prepare_user_agent( )
143
+
144
+ # deep clone the redundancy rules to preserve their counter
145
+ # for the reports
146
+ @orig_redundant = @opts.redundant.deep_clone
147
+
148
+ @running = false
149
+ @paused = []
150
+
151
+ @plugin_store = {}
152
+
153
+ @current_url = ''
154
+ end
155
+
156
+ def http
157
+ Arachni::HTTP.instance
158
+ end
159
+
160
+ #
161
+ # Runs the system
162
+ #
163
+ # It parses the instanse options and runs the audit
164
+ #
165
+ # @param [Block] &block a block to call after the audit has finished
166
+ # but before running the reports
167
+ #
168
+ def run( &block )
169
+ @running = true
170
+
171
+ @opts.start_datetime = Time.now
172
+
173
+ # run all plugins
174
+ @plugins.run
175
+
176
+ # catch exceptions so that if something breaks down or the user opted to
177
+ # exit the reports will still run with whatever results
178
+ # Arachni managed to gather
179
+ begin
180
+ # start the audit
181
+ audit( )
182
+ rescue Exception
183
+ end
184
+
185
+ clean_up!
186
+ begin
187
+ block.call if block
188
+ rescue Exception
189
+ end
190
+
191
+ # run reports
192
+ if( @opts.reports && !@opts.reports.empty? )
193
+ exception_jail{ @reports.run( audit_store( ) ) }
194
+ end
195
+
196
+ return true
197
+ end
198
+
199
+ def stats( refresh_time = false )
200
+ req_cnt = http.request_count
201
+ res_cnt = http.response_count
202
+
203
+ @auditmap ||= []
204
+ @sitemap ||= []
205
+ if !refresh_time || @auditmap.size == @sitemap.size
206
+ @opts.delta_time ||= Time.now - @opts.start_datetime
207
+ else
208
+ @opts.delta_time = Time.now - @opts.start_datetime
209
+ end
210
+
211
+ curr_avg = 0
212
+ if http.curr_res_cnt > 0
213
+ curr_avg = (http.curr_res_cnt / http.curr_res_time).to_i.to_s
214
+ end
215
+
216
+ return {
217
+ :requests => req_cnt,
218
+ :responses => res_cnt,
219
+ :time => audit_store.delta_time,
220
+ :avg => ( res_cnt / @opts.delta_time ).to_i.to_s,
221
+ :sitemap_size => @sitemap.size,
222
+ :auditmap_size => @auditmap.size,
223
+ :curr_res_time => http.curr_res_time,
224
+ :curr_res_cnt => http.curr_res_cnt,
225
+ :curr_avg => curr_avg,
226
+ :average_res_time => http.average_res_time,
227
+ :max_concurrency => http.max_concurrency,
228
+ :current_page => @current_url
229
+ }
230
+ end
231
+
232
+ #
233
+ # Audits the site.
234
+ #
235
+ # Runs the spider, analyzes each page as it appears and passes it
236
+ # to (#run_mods} to be audited.
237
+ #
238
+ def audit
239
+
240
+ wait_if_paused
241
+
242
+ @spider = Arachni::Spider.new( @opts )
243
+
244
+ @sitemap ||= []
245
+ @auditmap ||= []
246
+
247
+ # initiates the crawl
248
+ @spider.run {
249
+ |page|
250
+
251
+ @sitemap |= @spider.pages
252
+
253
+ @page_queue << page
254
+ audit_queue if !@opts.spider_first
255
+ }
256
+
257
+ audit_queue
258
+
259
+ if( @opts.http_harvest_last )
260
+ harvest_http_responses( )
261
+ end
262
+
263
+ end
264
+
265
+ def audit_queue
266
+
267
+ # this will run until no new elements appear for the given page
268
+ while( !@page_queue.empty? && page = @page_queue.pop )
269
+
270
+ # audit the page
271
+ exception_jail{ run_mods( page ) }
272
+
273
+ # run all the queued HTTP requests and harvest the responses
274
+ http.run
275
+
276
+ # check to see if the page was updated
277
+ page = http.trainer.page
278
+ # and push it in the queue to be audited as well
279
+ @page_queue << page if page
280
+
281
+ end
282
+ end
283
+
284
+
285
+ #
286
+ # Returns the results of the audit as an {AuditStore} instance
287
+ #
288
+ # @see AuditStore
289
+ #
290
+ # @return [AuditStore]
291
+ #
292
+ def audit_store( fresh = false )
293
+
294
+ # restore the original redundacy rules and their counters
295
+ @opts.redundant = @orig_redundant
296
+ opts = @opts.to_h
297
+ opts['mods'] = @modules.keys
298
+
299
+ if( !fresh && @store )
300
+ return @store
301
+ else
302
+ return @store = AuditStore.new( {
303
+ :version => version( ),
304
+ :revision => REVISION,
305
+ :options => opts,
306
+ :sitemap => @sitemap ? @sitemap.sort : ['N/A'],
307
+ :issues => @modules.results( ).deep_clone,
308
+ :plugins => @plugin_store
309
+ }, self )
310
+ end
311
+ end
312
+
313
+ def plugin_store( plugin, obj )
314
+ name = ''
315
+ @plugins.each_pair {
316
+ |k, v|
317
+
318
+ if plugin.class.name == v.name
319
+ name = k
320
+ break
321
+ end
322
+ }
323
+
324
+ @plugin_store[name] = {
325
+ :results => obj
326
+ }.merge( plugin.class.info )
327
+ end
328
+
329
+ #
330
+ # Returns an array of hashes with information
331
+ # about all available modules
332
+ #
333
+ # @return [Array<Hash>]
334
+ #
335
+ def lsmod
336
+
337
+ mod_info = []
338
+ @modules.available( ).each {
339
+ |name|
340
+
341
+ path = @modules.name_to_path( name )
342
+ next if !lsmod_match?( path )
343
+
344
+ info = @modules[name].info( )
345
+
346
+ info[:mod_name] = name
347
+ info[:name] = info[:name].strip
348
+ info[:description] = info[:description].strip
349
+
350
+ if( !info[:dependencies] )
351
+ info[:dependencies] = []
352
+ end
353
+
354
+ info[:author] = info[:author].strip
355
+ info[:version] = info[:version].strip
356
+ info[:path] = path.strip
357
+
358
+ mod_info << info
359
+ }
360
+
361
+ # unload all modules
362
+ @modules.clear( )
363
+
364
+ return mod_info
365
+
366
+ end
367
+
368
+ #
369
+ # Returns an array of hashes with information
370
+ # about all available reports
371
+ #
372
+ # @return [Array<Hash>]
373
+ #
374
+ def lsrep
375
+
376
+ rep_info = []
377
+ @reports.available( ).each {
378
+ |report|
379
+
380
+ info = @reports[report].info
381
+
382
+ info[:rep_name] = report
383
+ info[:path] = @reports.name_to_path( report )
384
+
385
+ rep_info << info
386
+ }
387
+ @reports.clear( )
388
+
389
+ return rep_info
390
+ end
391
+
392
+ #
393
+ # Returns an array of hashes with information
394
+ # about all available reports
395
+ #
396
+ # @return [Array<Hash>]
397
+ #
398
+ def lsplug
399
+
400
+ plug_info = []
401
+
402
+ @plugins.available( ).each {
403
+ |plugin|
404
+
405
+ info = @plugins[plugin].info
406
+
407
+ info[:plug_name] = plugin
408
+ info[:path] = @plugins.name_to_path( plugin )
409
+
410
+ plug_info << info
411
+ }
412
+
413
+ @plugins.clear( )
414
+
415
+ return plug_info
416
+ end
417
+
418
+ def running?
419
+ @running
420
+ end
421
+
422
+ def paused?
423
+ !@paused.empty?
424
+ end
425
+
426
+ def pause!
427
+ @paused << caller
428
+ return true
429
+ end
430
+
431
+ def resume!
432
+ @paused.delete( caller )
433
+ return true
434
+ end
435
+
436
+ #
437
+ # Returns the version of the framework
438
+ #
439
+ # @return [String]
440
+ #
441
+ def version
442
+ Arachni::VERSION
443
+ end
444
+
445
+ #
446
+ # Returns the revision of the {Framework} (this) class
447
+ #
448
+ # @return [String]
449
+ #
450
+ def revision
451
+ REVISION
452
+ end
453
+
454
+ private
455
+
456
+ def clean_up!
457
+ @opts.finish_datetime = Time.now
458
+ @opts.delta_time = @opts.finish_datetime - @opts.start_datetime
459
+
460
+ # make sure this is disabled or it'll break report output
461
+ @@only_positives = false
462
+
463
+ @running = false
464
+
465
+ # wait for the plugins to finish
466
+ @plugins.block!
467
+
468
+ # a plug-in may have updated the page queue, rock it!
469
+ audit_queue
470
+
471
+ # refresh the audit store
472
+ audit_store( true )
473
+
474
+ return true
475
+ end
476
+
477
+ def caller
478
+ if /^(.+?):(\d+)(?::in `(.*)')?/ =~ ::Kernel.caller[1]
479
+ return Regexp.last_match[1]
480
+ end
481
+ end
482
+
483
+ def wait_if_paused
484
+ while( paused? )
485
+ ::IO::select( nil, nil, nil, 1 )
486
+ end
487
+ end
488
+
489
+
490
+ #
491
+ # Prepares the user agent to be used throughout the system.
492
+ #
493
+ def prepare_user_agent
494
+ if( !@opts.user_agent )
495
+ @opts.user_agent = 'Arachni/' + version( )
496
+ end
497
+
498
+ if( @opts.authed_by )
499
+ authed_by = " (Scan authorized by: #{@opts.authed_by})"
500
+ @opts.user_agent += authed_by
501
+ end
502
+
503
+ end
504
+
505
+ def prepare_cookie_jar( )
506
+ return if !@opts.cookie_jar || !@opts.cookie_jar.is_a?( String )
507
+
508
+ # make sure that the provided cookie-jar file exists
509
+ if !File.exist?( @opts.cookie_jar )
510
+ raise( Arachni::Exceptions::NoCookieJar,
511
+ 'Cookie-jar \'' + @opts.cookie_jar + '\' doesn\'t exist.' )
512
+ end
513
+
514
+ end
515
+
516
+
517
+ #
518
+ # Takes care of page audit and module execution
519
+ #
520
+ # It will audit one page at a time as discovered by the spider <br/>
521
+ # and recursively check for new elements that may have <br/>
522
+ # appeared during the audit.
523
+ #
524
+ # When no new elements appear the recursion will stop and a new page<br/>
525
+ # will be accepted.
526
+ #
527
+ # @see Page
528
+ #
529
+ # @param [Page] page
530
+ #
531
+ def run_mods( page )
532
+ return if !page
533
+
534
+ @current_url = page.url.to_s
535
+
536
+ @modules.each_pair {
537
+ |name, mod|
538
+
539
+ wait_if_paused
540
+ run_mod( mod, page.deep_clone )
541
+ }
542
+
543
+ @auditmap << page.url
544
+ @auditmap.uniq!
545
+ @sitemap |= @auditmap
546
+ @sitemap.uniq!
547
+
548
+
549
+ if( !@opts.http_harvest_last )
550
+ harvest_http_responses( )
551
+ end
552
+
553
+ end
554
+
555
+ def harvest_http_responses
556
+
557
+ print_status( 'Harvesting HTTP responses...' )
558
+ print_info( 'Depending on server responsiveness and network' +
559
+ ' conditions this may take a while.' )
560
+
561
+ # run all the queued HTTP requests and harvest the responses
562
+ http.run
563
+
564
+ # try to get an updated page from the Trainer
565
+ page = http.trainer.page
566
+
567
+ # if there was an updated page push it in the queue
568
+ @page_queue << page if page
569
+ audit_queue
570
+ end
571
+
572
+ #
573
+ # Passes a page to the module and runs it.<br/>
574
+ # It also handles any exceptions thrown by the module at runtime.
575
+ #
576
+ # @see Page
577
+ #
578
+ # @param [Class] mod the module to run
579
+ # @param [Page] page
580
+ #
581
+ def run_mod( mod, page )
582
+ return if !run_mod?( mod, page )
583
+
584
+ begin
585
+
586
+ # instantiate the module
587
+ mod_new = mod.new( page )
588
+
589
+ mod_new.prepare
590
+ mod_new.run
591
+ mod_new.clean_up
592
+ rescue Exception => e
593
+ print_error( 'Error in ' + mod.to_s + ': ' + e.to_s )
594
+ print_debug_backtrace( e )
595
+ end
596
+ end
597
+
598
+ #
599
+ # Determines whether or not to run the module against the given page
600
+ # depending on which elements exist in the page, which elements the module
601
+ # is configured to audit and user options.
602
+ #
603
+ # @param [Class] mod the module to run
604
+ # @param [Page] page
605
+ #
606
+ # @return [Bool]
607
+ #
608
+ def run_mod?( mod, page )
609
+ return true if( !mod.info[:elements] || mod.info[:elements].empty? )
610
+
611
+ elems = {
612
+ Issue::Element::LINK => page.links && page.links.size > 0 && @opts.audit_links,
613
+ Issue::Element::FORM => page.forms && page.forms.size > 0 && @opts.audit_forms,
614
+ Issue::Element::COOKIE => page.cookies && page.cookies.size > 0 && @opts.audit_cookies,
615
+ Issue::Element::HEADER => page.headers && page.headers.size > 0 && @opts.audit_headers,
616
+ }
617
+
618
+ elems.each_pair {
619
+ |elem, expr|
620
+ return true if mod.info[:elements].include?( elem ) && expr
621
+ }
622
+
623
+ return false
624
+ end
625
+
626
+ def lsmod_match?( path )
627
+ cnt = 0
628
+ @opts.lsmod.each {
629
+ |filter|
630
+ cnt += 1 if path =~ filter
631
+ }
632
+ return true if cnt == @opts.lsmod.size
633
+ end
634
+
635
+ end
636
+
637
+ end