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,71 @@
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
+ require 'xmlrpc/client'
12
+ require 'openssl'
13
+
14
+ module Arachni
15
+ module RPC
16
+ module XML
17
+ module Client
18
+
19
+ #
20
+ # Basic self-configuring XMLRPC client supporting cert-based SSL client/server authentication
21
+ #
22
+ # @author: Tasos "Zapotek" Laskos
23
+ # <tasos.laskos@gmail.com>
24
+ # <zapotek@segfault.gr>
25
+ # @version: 0.1
26
+ #
27
+ class Base
28
+
29
+ def initialize( opts, url )
30
+
31
+ @opts = opts
32
+
33
+ # start the XMLRPC client
34
+ @server = ::XMLRPC::Client.new2( url )
35
+
36
+ # there'll be a HELL of lot of output so things might get..laggy.
37
+ # a big timeout is required to avoid Timeout exceptions...
38
+ @server.timeout = 9999999
39
+
40
+
41
+ if @opts.ssl_ca || @opts.ssl_pkey || @opts.ssl_cert
42
+
43
+ pkey = ::OpenSSL::PKey::RSA.new( File.read( opts.ssl_pkey ) ) if @opts.ssl_pkey
44
+ cert = ::OpenSSL::X509::Certificate.new( File.read( opts.ssl_cert ) ) if @opts.ssl_cert
45
+
46
+ @server.instance_variable_get( :@http ).instance_variable_set( :@key, pkey )
47
+ @server.instance_variable_get( :@http ).instance_variable_set( :@cert, cert )
48
+
49
+ @server.instance_variable_get( :@http ).instance_variable_set( :@ca_file, @opts.ssl_ca )
50
+ @server.instance_variable_get( :@http ).instance_variable_set( :@verify_mode,
51
+ OpenSSL::SSL::VERIFY_PEER | OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT )
52
+
53
+ else
54
+ @server.instance_variable_get( :@http ).instance_variable_set( :@verify_mode, OpenSSL::SSL::VERIFY_NONE )
55
+ end
56
+
57
+ end
58
+
59
+ #
60
+ # Used to make old school XMLRPC calls
61
+ #
62
+ def call( method, *args )
63
+ @server.call( method, *args )
64
+ end
65
+
66
+ end
67
+
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,49 @@
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
+ require 'xmlrpc/client'
12
+ require 'openssl'
13
+
14
+ module Arachni
15
+
16
+ require Arachni::Options.instance.dir['lib'] + 'rpc/xml/client/base'
17
+
18
+ module RPC
19
+ module XML
20
+ module Client
21
+
22
+ #
23
+ # XMLRPC Dispatcher client
24
+ #
25
+ # @author: Tasos "Zapotek" Laskos
26
+ # <tasos.laskos@gmail.com>
27
+ # <zapotek@segfault.gr>
28
+ # @version: 0.1.2
29
+ #
30
+ class Dispatcher < Base
31
+
32
+ def initialize( opts, url )
33
+ super( opts, url )
34
+ end
35
+
36
+ private
37
+ #
38
+ # Used to provide the illusion of locality for remote methods
39
+ #
40
+ def method_missing( sym, *args, &block )
41
+ call( "dispatcher.#{sym.to_s}", *args )
42
+ end
43
+
44
+ end
45
+
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,88 @@
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
+ require 'xmlrpc/client'
12
+ require 'openssl'
13
+
14
+ module Arachni
15
+
16
+ require Arachni::Options.instance.dir['lib'] + 'rpc/xml/client/base'
17
+
18
+ module RPC
19
+ module XML
20
+ module Client
21
+
22
+ #
23
+ # XMLRPC client for remote instances spawned by a remote dispatcher
24
+ #
25
+ # @author: Tasos "Zapotek" Laskos
26
+ # <tasos.laskos@gmail.com>
27
+ # <zapotek@segfault.gr>
28
+ # @version: 0.1.1
29
+ #
30
+ class Instance < Base
31
+
32
+ attr_reader :opts
33
+ attr_reader :framework
34
+ attr_reader :modules
35
+ attr_reader :plugins
36
+ attr_reader :service
37
+
38
+ #
39
+ # Maps the methods of remote objects to local ones
40
+ #
41
+ class Mapper
42
+
43
+ def initialize( server, remote )
44
+ @server = server
45
+ @remote = remote
46
+ end
47
+
48
+ private
49
+ #
50
+ # Used to provide the illusion of locality for remote methods
51
+ #
52
+ def method_missing( sym, *args, &block )
53
+ call = "#{@remote}.#{sym.to_s}"
54
+ @server.call( call, *args )
55
+ end
56
+
57
+ end
58
+
59
+ #
60
+ # Used to make remote option attributes look like setter methods
61
+ #
62
+ class OptsMapper < Mapper
63
+
64
+ def method_missing( sym, *args, &block )
65
+ return super( sym, *args, &block ) if sym == :set
66
+
67
+ call = "#{@remote}.#{sym.to_s}="
68
+ @server.call( call, *args )
69
+ end
70
+
71
+ end
72
+
73
+ def initialize( opts, url )
74
+ super( opts, url )
75
+
76
+ @opts = OptsMapper.new( @server, 'opts' )
77
+ @framework = Mapper.new( @server, 'framework' )
78
+ @modules = Mapper.new( @server, 'modules' )
79
+ @plugins = Mapper.new( @server, 'plugins' )
80
+ @service = Mapper.new( @server, 'service' )
81
+ end
82
+
83
+ end
84
+
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,90 @@
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
+ require 'socket'
12
+ require 'sys/proctable'
13
+
14
+ module Arachni
15
+ module RPC
16
+ module XML
17
+ module Server
18
+
19
+ #
20
+ # Dispatcher class
21
+ #
22
+ # @author: Tasos "Zapotek" Laskos
23
+ # <tasos.laskos@gmail.com>
24
+ # <zapotek@segfault.gr>
25
+ # @version: 0.1
26
+ #
27
+ class Base
28
+
29
+ def initialize( opts )
30
+
31
+ pkey = ::OpenSSL::PKey::RSA.new( File.read( opts.ssl_pkey ) ) if opts.ssl_pkey
32
+ cert = ::OpenSSL::X509::Certificate.new( File.read( opts.ssl_cert ) ) if opts.ssl_cert
33
+
34
+ if opts.ssl_pkey || opts.ssl_cert || opts.ssl_ca
35
+ verification = OpenSSL::SSL::VERIFY_PEER | OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
36
+ else
37
+ verification = ::OpenSSL::SSL::VERIFY_NONE
38
+ end
39
+
40
+ @server = ::WEBrick::HTTPServer.new(
41
+ :Port => opts.rpc_port,
42
+ :SSLEnable => opts.ssl || false,
43
+ :SSLVerifyClient => verification,
44
+ :SSLCertName => [ [ "CN", ::WEBrick::Utils::getservername ] ],
45
+ :SSLCertificate => cert,
46
+ :SSLPrivateKey => pkey,
47
+ :SSLCACertificateFile => opts.ssl_ca
48
+ )
49
+
50
+ print_status( 'Initing XMLRPC Server...' )
51
+ @service = ::XMLRPC::WEBrickServlet.new( )
52
+ @service.add_introspection
53
+ @server.mount( "/RPC2", @service )
54
+ end
55
+
56
+ def add_handler( name, klass )
57
+ @service.add_handler( ::XMLRPC::iPIMethods( name ), klass )
58
+ end
59
+
60
+ def run
61
+ @server.start
62
+ end
63
+
64
+ def alive?
65
+ return true
66
+ end
67
+ alias :is_alive :alive?
68
+
69
+ def shutdown
70
+ @server.shutdown
71
+ end
72
+
73
+ private
74
+
75
+ def remove_nils( hash )
76
+ hash.each_pair {
77
+ |k, v|
78
+ hash[k] = '' if v.nil?
79
+ hash[k] = remove_nils( v ) if v.is_a? Hash
80
+ }
81
+
82
+ return hash
83
+ end
84
+
85
+ end
86
+
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,357 @@
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
+ require 'socket'
12
+ require 'sys/proctable'
13
+
14
+ module Arachni
15
+
16
+ require Options.instance.dir['lib'] + 'rpc/xml/server/base'
17
+ require Options.instance.dir['lib'] + 'rpc/xml/server/instance'
18
+ require Options.instance.dir['lib'] + 'rpc/xml/server/output'
19
+
20
+ module RPC
21
+ module XML
22
+ module Server
23
+
24
+ #
25
+ # Dispatcher class
26
+ #
27
+ # Dispatches XML-RPC servers on demand providing a centralised environment
28
+ # for multiple XMLRPC clients and allows for extensive process monitoring.
29
+ #
30
+ # The process goes something like this:
31
+ # * a client issues a 'dispatch' call
32
+ # * the dispatcher starts a new XMLRPC server on a random port
33
+ # * the dispatcher returns the port of the XMLRPC server to the client
34
+ # * the client connects to the XMLRPC server listening on that port and does his business
35
+ #
36
+ # Once the client finishes using the XMLRPC server it *must* shut it down.<br/>
37
+ # If it doesn't the system will be eaten away by idle instances of XMLRPC servers.
38
+ #
39
+ # @author: Tasos "Zapotek" Laskos
40
+ # <tasos.laskos@gmail.com>
41
+ # <zapotek@segfault.gr>
42
+ # @version: 0.1.1
43
+ #
44
+ class Dispatcher < Base
45
+
46
+ include Arachni::Module::Utilities
47
+ include Arachni::UI::Output
48
+ include ::Sys
49
+
50
+ private :shutdown, :alive?
51
+ public :shutdown, :alive?
52
+
53
+ def initialize( opts )
54
+
55
+ banner
56
+
57
+ @opts = opts
58
+ @opts.rpc_port ||= 7331
59
+ @opts.pool_size ||= 5
60
+
61
+ if opts.help
62
+ print_help
63
+ exit 0
64
+ end
65
+
66
+ super( @opts )
67
+
68
+ prep_logging
69
+
70
+ print_status( 'Initing XMLRPC Server...' )
71
+
72
+ add_handler( "dispatcher", self )
73
+
74
+ # trap interupts and exit cleanly when required
75
+ trap( 'HUP' ) { shutdown }
76
+ trap( 'INT' ) { shutdown }
77
+
78
+ @jobs = []
79
+ @pool = Queue.new
80
+
81
+ print_status( 'Warming up the pool...' )
82
+ prep_pool
83
+ print_status( 'Done.' )
84
+
85
+ print_status( 'Initialization complete.' )
86
+
87
+ end
88
+
89
+ # Starts the dispatcher's server
90
+ def run
91
+ print_status( 'Starting the server...' )
92
+ super
93
+ end
94
+
95
+ def shutdown
96
+ print_status( 'Shutting down...' )
97
+ super
98
+ print_status( 'Done.' )
99
+ end
100
+
101
+ #
102
+ # Dispatches an XMLRPC server instance from the pool
103
+ #
104
+ # @param [String] owner an owner assign to the dispatched XMLRPC server
105
+ #
106
+ # @return [Hash] includes port number, owner, clock info and proc info
107
+ #
108
+ def dispatch( owner = 'unknown' )
109
+
110
+ # just to make sure...
111
+ owner = owner.to_s
112
+ cjob = @pool.pop
113
+ cjob['owner'] = owner
114
+ cjob['starttime'] = Time.now
115
+
116
+ print_status( "Server dispatched -- PID: #{cjob['pid']} - " +
117
+ "Port: #{cjob['port']} - Owner: #{cjob['owner']}" )
118
+
119
+ prep_pool
120
+
121
+ @jobs << cjob
122
+
123
+ return job( cjob['pid'] )
124
+ end
125
+
126
+ #
127
+ # Returns proc info for a given pid
128
+ #
129
+ # @param [Fixnum] pid
130
+ #
131
+ # @return [Hash]
132
+ #
133
+ def job( pid )
134
+ @jobs.each {
135
+ |i|
136
+ cjob = i.dup
137
+ if cjob['pid'] == pid
138
+ cjob['currtime'] = Time.now
139
+ cjob['age'] = cjob['currtime'] - cjob['birthdate']
140
+ cjob['runtime'] = cjob['currtime'] - cjob['starttime']
141
+ cjob['proc'] = proc( cjob['pid'] )
142
+
143
+ return remove_nils( cjob )
144
+ end
145
+ }
146
+ end
147
+
148
+ #
149
+ # Returns proc info for all jobs
150
+ #
151
+ # @return [Array<Hash>]
152
+ #
153
+ def jobs
154
+ jobs = []
155
+ @jobs.each {
156
+ |cjob|
157
+ proc_info = job( cjob['pid'] )
158
+ jobs << proc_info if proc_info
159
+ }
160
+ return jobs
161
+ end
162
+
163
+ #
164
+ # Returns server stats regarding the jobs and pool
165
+ #
166
+ # @return [Hash]
167
+ #
168
+ def stats
169
+ cjobs = jobs( )
170
+ running = cjobs.reject{ |job| job['proc'].empty? }
171
+ finished = cjobs - running
172
+
173
+ return {
174
+ 'running_jobs' => running,
175
+ 'finished_jobs' => finished,
176
+ 'init_pool_size' => @opts.pool_size,
177
+ 'curr_pool_size' => @pool.size
178
+ }
179
+ end
180
+
181
+ #
182
+ # Outputs the Arachni banner.<br/>
183
+ # Displays version number, revision number, author details etc.
184
+ #
185
+ def banner
186
+
187
+ puts 'Arachni - Web Application Security Scanner Framework
188
+ Author: Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
189
+ <zapotek@segfault.gr>
190
+ (With the support of the community and the Arachni Team.)
191
+
192
+ Website: http://github.com/Zapotek/arachni
193
+ Documentation: http://github.com/Zapotek/arachni/wiki'
194
+ puts
195
+ puts
196
+
197
+ end
198
+
199
+ def print_help
200
+ puts <<USAGE
201
+ Usage: arachni_xmlrpcd \[options\]
202
+
203
+ Supported options:
204
+
205
+ -h
206
+ --help output this
207
+
208
+ --port specify port to listen to
209
+ (Default: #{@opts.rpc_port})
210
+
211
+ --reroute-to-logfile reroute all output to a logfile under 'logs/'
212
+
213
+ --pool-size how many server workers/processes should be available
214
+ at any given moment (Default: #{@opts.pool_size})
215
+
216
+ --debug
217
+
218
+
219
+ SSL --------------------------
220
+
221
+ (All SSL options will be honored by the dispatched XMLRPC instances as well.)
222
+ (Do *not* use encrypted keys!)
223
+
224
+ --ssl use SSL?
225
+ (If you want encryption without authentication
226
+ you can skip rest of the SSL options.)
227
+
228
+ --ssl-pkey <file> location of the SSL private key (.pem)
229
+ (Used to verify the server to the clients.)
230
+
231
+ --ssl-cert <file> location of the SSL certificate (.pem)
232
+ (Used to verify the server to the clients.)
233
+
234
+ --ssl-ca <file> location of the CA certificate (.pem)
235
+ (Used to verify the clients to the server.)
236
+ USAGE
237
+ end
238
+
239
+
240
+ private
241
+
242
+ #
243
+ # Initializes and updates the pool making sure that the number of
244
+ # available server processes stays constant for any given moment
245
+ #
246
+ def prep_pool
247
+
248
+ owner = 'dispatcher'
249
+
250
+ (@pool.size - @opts.pool_size).abs.times {
251
+ exception_jail{
252
+
253
+ # get an available port for the child
254
+ @opts.rpc_port = avail_port( )
255
+
256
+ pid = Kernel.fork {
257
+ exception_jail {
258
+ server = Arachni::RPC::XML::Server::Instance.new( @opts )
259
+ trap( "INT", "IGNORE" )
260
+ server.run
261
+ }
262
+
263
+ # restore logging
264
+ reroute_to_file( @logfile )
265
+
266
+ print_status( "Server shutdown -- PID: #{Process.pid} - " +
267
+ "Port: #{@opts.rpc_port}" )
268
+ }
269
+
270
+ print_status( "Server added to pool -- PID: #{pid} - " +
271
+ "Port: #{@opts.rpc_port} - Owner: #{owner}" )
272
+
273
+ @pool << {
274
+ 'pid' => pid,
275
+ 'port' => @opts.rpc_port,
276
+ 'owner' => owner,
277
+ 'birthdate' => Time.now
278
+ }
279
+
280
+ # let the child go about his business
281
+ Process.detach( pid )
282
+ }
283
+ }
284
+
285
+ end
286
+
287
+ def prep_logging
288
+ # reroute all output to a logfile
289
+ @logfile ||= reroute_to_file( @opts.dir['root'] +
290
+ "logs/XMLRPC-Dispatcher - #{Process.pid}:#{@opts.rpc_port} - #{Time.now.asctime}.log" )
291
+ end
292
+
293
+ def proc( pid )
294
+ struct_to_h( ProcTable.ps( pid ) )
295
+ end
296
+
297
+ def struct_to_h( struct )
298
+ hash = {}
299
+
300
+ return hash if !struct
301
+
302
+ struct.each_pair {
303
+ |k, v|
304
+ v = v.to_s if v.is_a?( Bignum ) || v.is_a?( Fixnum )
305
+ hash[k.to_s] = v
306
+ }
307
+
308
+ return hash
309
+ end
310
+
311
+ #
312
+ # Returns a random available port
313
+ #
314
+ # @return Fixnum port number
315
+ #
316
+ def avail_port
317
+
318
+ port = rand_port
319
+ while !avail_port?( port )
320
+ port = rand_port
321
+ end
322
+
323
+ return port
324
+ end
325
+
326
+ #
327
+ # Returns a random port
328
+ #
329
+ def rand_port
330
+ range = (1025..65535).to_a
331
+ range[ rand( 65535 - 1025 ) ]
332
+ end
333
+
334
+ #
335
+ # Checks whether the port number is available
336
+ #
337
+ # @param Fixnum port
338
+ #
339
+ # @return Bool
340
+ #
341
+ def avail_port?( port )
342
+ begin
343
+ socket = Socket.new( :INET, :STREAM, 0 )
344
+ socket.bind( Addrinfo.tcp( "127.0.0.1", port ) )
345
+ socket.close
346
+ return true
347
+ rescue
348
+ return false
349
+ end
350
+ end
351
+
352
+ end
353
+
354
+ end
355
+ end
356
+ end
357
+ end