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.
- data/ACKNOWLEDGMENTS.md +14 -0
- data/AUTHORS.md +6 -0
- data/CHANGELOG.md +162 -0
- data/CONTRIBUTORS.md +10 -0
- data/EXPLOITATION.md +429 -0
- data/HACKING.md +101 -0
- data/LICENSE.md +341 -0
- data/README.md +350 -0
- data/Rakefile +86 -0
- data/bin/arachni +22 -0
- data/bin/arachni_web +77 -0
- data/bin/arachni_xmlrpc +21 -0
- data/bin/arachni_xmlrpcd +82 -0
- data/bin/arachni_xmlrpcd_monitor +74 -0
- data/conf/README.webui.yaml.txt +44 -0
- data/conf/webui.yaml +11 -0
- data/external/metasploit/LICENSE +24 -0
- data/external/metasploit/modules/exploits/unix/webapp/arachni_exec.rb +142 -0
- data/external/metasploit/modules/exploits/unix/webapp/arachni_path_traversal.rb +113 -0
- data/external/metasploit/modules/exploits/unix/webapp/arachni_php_eval.rb +150 -0
- data/external/metasploit/modules/exploits/unix/webapp/arachni_php_include.rb +141 -0
- data/external/metasploit/modules/exploits/unix/webapp/arachni_sqlmap.rb +92 -0
- data/external/metasploit/plugins/arachni.rb +536 -0
- data/getoptslong.rb +241 -0
- data/lib/anemone.rb +2 -0
- data/lib/anemone/cookie_store.rb +35 -0
- data/lib/anemone/core.rb +371 -0
- data/lib/anemone/exceptions.rb +5 -0
- data/lib/anemone/http.rb +144 -0
- data/lib/anemone/page.rb +337 -0
- data/lib/anemone/page_store.rb +160 -0
- data/lib/anemone/storage.rb +34 -0
- data/lib/anemone/storage/base.rb +75 -0
- data/lib/anemone/storage/exceptions.rb +15 -0
- data/lib/anemone/storage/mongodb.rb +89 -0
- data/lib/anemone/storage/pstore.rb +50 -0
- data/lib/anemone/storage/redis.rb +90 -0
- data/lib/anemone/storage/tokyo_cabinet.rb +57 -0
- data/lib/anemone/tentacle.rb +40 -0
- data/lib/arachni.rb +16 -0
- data/lib/audit_store.rb +346 -0
- data/lib/component_manager.rb +293 -0
- data/lib/component_options.rb +395 -0
- data/lib/exceptions.rb +76 -0
- data/lib/framework.rb +637 -0
- data/lib/http.rb +809 -0
- data/lib/issue.rb +302 -0
- data/lib/module.rb +4 -0
- data/lib/module/auditor.rb +455 -0
- data/lib/module/base.rb +188 -0
- data/lib/module/element_db.rb +158 -0
- data/lib/module/key_filler.rb +87 -0
- data/lib/module/manager.rb +87 -0
- data/lib/module/output.rb +68 -0
- data/lib/module/trainer.rb +240 -0
- data/lib/module/utilities.rb +110 -0
- data/lib/options.rb +547 -0
- data/lib/parser.rb +2 -0
- data/lib/parser/auditable.rb +522 -0
- data/lib/parser/elements.rb +296 -0
- data/lib/parser/page.rb +149 -0
- data/lib/parser/parser.rb +717 -0
- data/lib/plugin.rb +4 -0
- data/lib/plugin/base.rb +110 -0
- data/lib/plugin/manager.rb +162 -0
- data/lib/report.rb +4 -0
- data/lib/report/base.rb +119 -0
- data/lib/report/manager.rb +92 -0
- data/lib/rpc/xml/client/base.rb +71 -0
- data/lib/rpc/xml/client/dispatcher.rb +49 -0
- data/lib/rpc/xml/client/instance.rb +88 -0
- data/lib/rpc/xml/server/base.rb +90 -0
- data/lib/rpc/xml/server/dispatcher.rb +357 -0
- data/lib/rpc/xml/server/framework.rb +206 -0
- data/lib/rpc/xml/server/instance.rb +191 -0
- data/lib/rpc/xml/server/module/manager.rb +46 -0
- data/lib/rpc/xml/server/options.rb +124 -0
- data/lib/rpc/xml/server/output.rb +299 -0
- data/lib/rpc/xml/server/plugin/manager.rb +58 -0
- data/lib/ruby.rb +5 -0
- data/lib/ruby/object.rb +32 -0
- data/lib/ruby/string.rb +74 -0
- data/lib/ruby/xmlrpc/server.rb +27 -0
- data/lib/spider.rb +200 -0
- data/lib/typhoeus/request.rb +91 -0
- data/lib/typhoeus/response.rb +34 -0
- data/lib/ui/cli/cli.rb +744 -0
- data/lib/ui/cli/output.rb +279 -0
- data/lib/ui/web/log.rb +82 -0
- data/lib/ui/web/output_stream.rb +94 -0
- data/lib/ui/web/report_manager.rb +222 -0
- data/lib/ui/web/server.rb +903 -0
- data/lib/ui/web/server/db/placeholder +0 -0
- data/lib/ui/web/server/public/banner.png +0 -0
- data/lib/ui/web/server/public/bodybg-small.png +0 -0
- data/lib/ui/web/server/public/bodybg.png +0 -0
- data/lib/ui/web/server/public/css/smoothness/images/pbar-ani.gif +0 -0
- data/lib/ui/web/server/public/css/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- data/lib/ui/web/server/public/css/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
- data/lib/ui/web/server/public/css/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
- data/lib/ui/web/server/public/css/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/lib/ui/web/server/public/css/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
- data/lib/ui/web/server/public/css/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- data/lib/ui/web/server/public/css/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- data/lib/ui/web/server/public/css/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- data/lib/ui/web/server/public/css/smoothness/images/ui-icons_222222_256x240.png +0 -0
- data/lib/ui/web/server/public/css/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
- data/lib/ui/web/server/public/css/smoothness/images/ui-icons_454545_256x240.png +0 -0
- data/lib/ui/web/server/public/css/smoothness/images/ui-icons_888888_256x240.png +0 -0
- data/lib/ui/web/server/public/css/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
- data/lib/ui/web/server/public/css/smoothness/jquery-ui-1.8.9.custom.css +573 -0
- data/lib/ui/web/server/public/favicon.ico +0 -0
- data/lib/ui/web/server/public/footer.jpg +0 -0
- data/lib/ui/web/server/public/icons/error.png +0 -0
- data/lib/ui/web/server/public/icons/info.png +0 -0
- data/lib/ui/web/server/public/icons/ok.png +0 -0
- data/lib/ui/web/server/public/icons/status.png +0 -0
- data/lib/ui/web/server/public/js/jquery-1.4.4.min.js +167 -0
- data/lib/ui/web/server/public/js/jquery-ui-1.8.9.custom.min.js +781 -0
- data/lib/ui/web/server/public/logo.png +0 -0
- data/lib/ui/web/server/public/nav-left.jpg +0 -0
- data/lib/ui/web/server/public/nav-right.jpg +0 -0
- data/lib/ui/web/server/public/nav-selected-left.jpg +0 -0
- data/lib/ui/web/server/public/nav-selected-right.jpg +0 -0
- data/lib/ui/web/server/public/reports/placeholder +1 -0
- data/lib/ui/web/server/public/sidebar-bottom.jpg +0 -0
- data/lib/ui/web/server/public/sidebar-h4.jpg +0 -0
- data/lib/ui/web/server/public/sidebar-top.jpg +0 -0
- data/lib/ui/web/server/public/spider.png +0 -0
- data/lib/ui/web/server/public/style.css +604 -0
- data/lib/ui/web/server/tmp/placeholder +0 -0
- data/lib/ui/web/server/views/dispatcher.erb +85 -0
- data/lib/ui/web/server/views/dispatcher_error.erb +14 -0
- data/lib/ui/web/server/views/error.erb +1 -0
- data/lib/ui/web/server/views/flash.erb +18 -0
- data/lib/ui/web/server/views/home.erb +14 -0
- data/lib/ui/web/server/views/instance.erb +213 -0
- data/lib/ui/web/server/views/layout.erb +95 -0
- data/lib/ui/web/server/views/log.erb +40 -0
- data/lib/ui/web/server/views/modules.erb +71 -0
- data/lib/ui/web/server/views/options.erb +23 -0
- data/lib/ui/web/server/views/output_results.erb +51 -0
- data/lib/ui/web/server/views/plugins.erb +42 -0
- data/lib/ui/web/server/views/report_formats.erb +30 -0
- data/lib/ui/web/server/views/reports.erb +55 -0
- data/lib/ui/web/server/views/settings.erb +120 -0
- data/lib/ui/web/server/views/welcome.erb +38 -0
- data/lib/ui/xmlrpc/dispatcher_monitor.rb +204 -0
- data/lib/ui/xmlrpc/xmlrpc.rb +843 -0
- data/logs/placeholder +0 -0
- data/metamodules/autothrottle.rb +74 -0
- data/metamodules/timeout_notice.rb +118 -0
- data/metamodules/uniformity.rb +98 -0
- data/modules/audit/code_injection.rb +136 -0
- data/modules/audit/code_injection_timing.rb +115 -0
- data/modules/audit/code_injection_timing/payloads.txt +4 -0
- data/modules/audit/csrf.rb +301 -0
- data/modules/audit/ldapi.rb +103 -0
- data/modules/audit/ldapi/errors.txt +26 -0
- data/modules/audit/os_cmd_injection.rb +103 -0
- data/modules/audit/os_cmd_injection/payloads.txt +2 -0
- data/modules/audit/os_cmd_injection_timing.rb +104 -0
- data/modules/audit/os_cmd_injection_timing/payloads.txt +3 -0
- data/modules/audit/path_traversal.rb +141 -0
- data/modules/audit/response_splitting.rb +105 -0
- data/modules/audit/rfi.rb +193 -0
- data/modules/audit/sqli.rb +120 -0
- data/modules/audit/sqli/regexp_ids.txt +90 -0
- data/modules/audit/sqli_blind_rdiff.rb +321 -0
- data/modules/audit/sqli_blind_timing.rb +103 -0
- data/modules/audit/sqli_blind_timing/payloads.txt +51 -0
- data/modules/audit/trainer.rb +89 -0
- data/modules/audit/unvalidated_redirect.rb +90 -0
- data/modules/audit/xpath.rb +104 -0
- data/modules/audit/xpath/errors.txt +26 -0
- data/modules/audit/xss.rb +99 -0
- data/modules/audit/xss_event.rb +134 -0
- data/modules/audit/xss_path.rb +125 -0
- data/modules/audit/xss_script_tag.rb +112 -0
- data/modules/audit/xss_tag.rb +112 -0
- data/modules/audit/xss_uri.rb +125 -0
- data/modules/recon/allowed_methods.rb +104 -0
- data/modules/recon/backdoors.rb +131 -0
- data/modules/recon/backdoors/filenames.txt +16 -0
- data/modules/recon/backup_files.rb +177 -0
- data/modules/recon/backup_files/extensions.txt +28 -0
- data/modules/recon/common_directories.rb +138 -0
- data/modules/recon/common_directories/directories.txt +265 -0
- data/modules/recon/common_files.rb +138 -0
- data/modules/recon/common_files/filenames.txt +17 -0
- data/modules/recon/directory_listing.rb +171 -0
- data/modules/recon/grep/captcha.rb +62 -0
- data/modules/recon/grep/credit_card.rb +85 -0
- data/modules/recon/grep/cvs_svn_users.rb +73 -0
- data/modules/recon/grep/emails.rb +59 -0
- data/modules/recon/grep/html_objects.rb +53 -0
- data/modules/recon/grep/private_ip.rb +54 -0
- data/modules/recon/grep/ssn.rb +53 -0
- data/modules/recon/htaccess_limit.rb +82 -0
- data/modules/recon/http_put.rb +95 -0
- data/modules/recon/interesting_responses.rb +118 -0
- data/modules/recon/unencrypted_password_forms.rb +119 -0
- data/modules/recon/webdav.rb +126 -0
- data/modules/recon/xst.rb +107 -0
- data/path_extractors/anchors.rb +35 -0
- data/path_extractors/forms.rb +35 -0
- data/path_extractors/frames.rb +38 -0
- data/path_extractors/generic.rb +39 -0
- data/path_extractors/links.rb +35 -0
- data/path_extractors/meta_refresh.rb +39 -0
- data/path_extractors/scripts.rb +37 -0
- data/path_extractors/sitemap.rb +31 -0
- data/plugins/autologin.rb +137 -0
- data/plugins/content_types.rb +90 -0
- data/plugins/cookie_collector.rb +99 -0
- data/plugins/form_dicattack.rb +185 -0
- data/plugins/healthmap.rb +94 -0
- data/plugins/http_dicattack.rb +133 -0
- data/plugins/metamodules.rb +118 -0
- data/plugins/proxy.rb +248 -0
- data/plugins/proxy/server.rb +66 -0
- data/plugins/waf_detector.rb +184 -0
- data/profiles/comprehensive.afp +74 -0
- data/profiles/full.afp +75 -0
- data/reports/afr.rb +59 -0
- data/reports/ap.rb +55 -0
- data/reports/html.rb +179 -0
- data/reports/html/default.erb +967 -0
- data/reports/metareport.rb +139 -0
- data/reports/metareport/arachni_metareport.rb +174 -0
- data/reports/plugin_formatters/html/content_types.rb +82 -0
- data/reports/plugin_formatters/html/cookie_collector.rb +66 -0
- data/reports/plugin_formatters/html/form_dicattack.rb +54 -0
- data/reports/plugin_formatters/html/healthmap.rb +76 -0
- data/reports/plugin_formatters/html/http_dicattack.rb +54 -0
- data/reports/plugin_formatters/html/metaformatters/timeout_notice.rb +65 -0
- data/reports/plugin_formatters/html/metaformatters/uniformity.rb +71 -0
- data/reports/plugin_formatters/html/metamodules.rb +93 -0
- data/reports/plugin_formatters/html/waf_detector.rb +54 -0
- data/reports/plugin_formatters/stdout/content_types.rb +73 -0
- data/reports/plugin_formatters/stdout/cookie_collector.rb +61 -0
- data/reports/plugin_formatters/stdout/form_dicattack.rb +52 -0
- data/reports/plugin_formatters/stdout/healthmap.rb +72 -0
- data/reports/plugin_formatters/stdout/http_dicattack.rb +53 -0
- data/reports/plugin_formatters/stdout/metaformatters/timeout_notice.rb +55 -0
- data/reports/plugin_formatters/stdout/metaformatters/uniformity.rb +68 -0
- data/reports/plugin_formatters/stdout/metamodules.rb +89 -0
- data/reports/plugin_formatters/stdout/waf_detector.rb +48 -0
- data/reports/plugin_formatters/xml/content_types.rb +91 -0
- data/reports/plugin_formatters/xml/cookie_collector.rb +70 -0
- data/reports/plugin_formatters/xml/form_dicattack.rb +57 -0
- data/reports/plugin_formatters/xml/healthmap.rb +82 -0
- data/reports/plugin_formatters/xml/http_dicattack.rb +57 -0
- data/reports/plugin_formatters/xml/metaformatters/timeout_notice.rb +67 -0
- data/reports/plugin_formatters/xml/metaformatters/uniformity.rb +82 -0
- data/reports/plugin_formatters/xml/metamodules.rb +91 -0
- data/reports/plugin_formatters/xml/waf_detector.rb +58 -0
- data/reports/stdout.rb +182 -0
- data/reports/txt.rb +77 -0
- data/reports/xml.rb +231 -0
- data/reports/xml/buffer.rb +98 -0
- 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
|