arachni 0.2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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