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,204 @@
|
|
|
1
|
+
require 'xmlrpc/client'
|
|
2
|
+
require 'openssl'
|
|
3
|
+
require 'terminal-table/import'
|
|
4
|
+
|
|
5
|
+
module Arachni
|
|
6
|
+
|
|
7
|
+
require Options.instance.dir['lib'] + 'rpc/xml/client/dispatcher'
|
|
8
|
+
require Options.instance.dir['lib'] + 'ui/cli/output'
|
|
9
|
+
|
|
10
|
+
module UI
|
|
11
|
+
|
|
12
|
+
#
|
|
13
|
+
#
|
|
14
|
+
# @author: Tasos "Zapotek" Laskos
|
|
15
|
+
# <tasos.laskos@gmail.com>
|
|
16
|
+
# <zapotek@segfault.gr>
|
|
17
|
+
# @version: 0.1.2
|
|
18
|
+
#
|
|
19
|
+
class DispatcherMonitor
|
|
20
|
+
|
|
21
|
+
include Arachni::UI::Output
|
|
22
|
+
|
|
23
|
+
def initialize( opts )
|
|
24
|
+
|
|
25
|
+
@opts = opts
|
|
26
|
+
|
|
27
|
+
debug! if @opts.debug
|
|
28
|
+
|
|
29
|
+
# print banner message
|
|
30
|
+
banner
|
|
31
|
+
|
|
32
|
+
# if the user needs help, output it and exit
|
|
33
|
+
if opts.help
|
|
34
|
+
usage
|
|
35
|
+
exit 0
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
begin
|
|
39
|
+
# start the XMLRPC client
|
|
40
|
+
@dispatcher = Arachni::RPC::XML::Client::Dispatcher.new( @opts, @opts.url.to_s )
|
|
41
|
+
|
|
42
|
+
# it seems like the XMLRPC client will connect us on the first
|
|
43
|
+
# call...so make sure that it *can* actually connect
|
|
44
|
+
@dispatcher.jobs
|
|
45
|
+
rescue Exception => e
|
|
46
|
+
print_error( "Could not connect to server." )
|
|
47
|
+
print_error( "Error: #{e.to_s}." )
|
|
48
|
+
print_debug_backtrace( e )
|
|
49
|
+
exit 0
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# trap interupts and exit cleanly when required
|
|
53
|
+
trap( 'HUP' ) { exit 0 }
|
|
54
|
+
trap( 'INT' ) { exit 0 }
|
|
55
|
+
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def run
|
|
59
|
+
|
|
60
|
+
print_line
|
|
61
|
+
|
|
62
|
+
# grab the XMLRPC server output while a scan is running
|
|
63
|
+
while( 1 )
|
|
64
|
+
stats = @dispatcher.stats
|
|
65
|
+
running_jobs = stats['running_jobs']
|
|
66
|
+
clear_screen
|
|
67
|
+
|
|
68
|
+
banner
|
|
69
|
+
print_stats( stats )
|
|
70
|
+
|
|
71
|
+
print_line
|
|
72
|
+
|
|
73
|
+
print_job_table( running_jobs )
|
|
74
|
+
|
|
75
|
+
# things will get crazy if we don't block a bit I think...
|
|
76
|
+
# we'll see...
|
|
77
|
+
::IO::select( nil, nil, nil, 1 )
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
private
|
|
83
|
+
|
|
84
|
+
def print_job_table( jobs )
|
|
85
|
+
|
|
86
|
+
headings = [ 'Parent PID', 'PID', 'Port', 'Owner', 'Birthdate (Server-side)',
|
|
87
|
+
'Start time (Server-side)', 'Current time (Server-side)', 'Age',
|
|
88
|
+
'Run-time', 'Memory', 'Priority', 'State' ]
|
|
89
|
+
|
|
90
|
+
rows = []
|
|
91
|
+
jobs.each {
|
|
92
|
+
|job|
|
|
93
|
+
rows << [ job['proc']['ppid'], job['pid'], job['port'], job['owner'],
|
|
94
|
+
job['birthdate'].to_time, job['starttime'].to_time, job['currtime'].to_time,
|
|
95
|
+
secs_to_hms( job['age'] ), secs_to_hms( job['runtime'] ),
|
|
96
|
+
proc_mem( job['proc']['rss'] ), job['proc']['priority'],
|
|
97
|
+
proc_state( job['proc']['state'] ) ]
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return if rows.empty?
|
|
101
|
+
|
|
102
|
+
print_line( table( headings, *rows ) )
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def print_stats( stats )
|
|
106
|
+
print_info( 'Number of finished instances: ' + stats['finished_jobs'].size.to_s )
|
|
107
|
+
print_info( 'Number of running instances: ' + stats['running_jobs'].size.to_s )
|
|
108
|
+
print_info( 'Initial pool size: ' + stats['init_pool_size'].to_s )
|
|
109
|
+
print_info( 'Current pool size: ' + stats['curr_pool_size'].to_s )
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def clear_screen
|
|
113
|
+
puts "\e[H\e[2J"
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def proc_mem( rss )
|
|
117
|
+
# we assume a page size of 4096
|
|
118
|
+
(rss.to_i * 4096 / 1024 / 1024).to_s + 'MB'
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def proc_state( state )
|
|
122
|
+
case state
|
|
123
|
+
when 'S'
|
|
124
|
+
return 'Sleeping'
|
|
125
|
+
|
|
126
|
+
when 'D'
|
|
127
|
+
return 'Disk Sleep'
|
|
128
|
+
|
|
129
|
+
when 'Z'
|
|
130
|
+
return 'Zombie'
|
|
131
|
+
|
|
132
|
+
when 'T'
|
|
133
|
+
return 'Traced/Stoped'
|
|
134
|
+
|
|
135
|
+
when 'W'
|
|
136
|
+
return 'Paging'
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def secs_to_hms( secs )
|
|
141
|
+
secs = secs.to_i
|
|
142
|
+
return [secs/3600, secs/60 % 60, secs % 60].map {
|
|
143
|
+
|t|
|
|
144
|
+
t.to_s.rjust( 2, '0' )
|
|
145
|
+
}.join(':')
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
#
|
|
150
|
+
# Outputs Arachni banner.<br/>
|
|
151
|
+
# Displays version number, revision number, author details etc.
|
|
152
|
+
#
|
|
153
|
+
# @see VERSION
|
|
154
|
+
# @see REVISION
|
|
155
|
+
#
|
|
156
|
+
# @return [void]
|
|
157
|
+
#
|
|
158
|
+
def banner
|
|
159
|
+
print_line 'Arachni - Web Application Security Scanner Framework
|
|
160
|
+
Author: Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
|
|
161
|
+
<zapotek@segfault.gr>
|
|
162
|
+
(With the support of the community and the Arachni Team.)
|
|
163
|
+
|
|
164
|
+
Website: http://github.com/Zapotek/arachni
|
|
165
|
+
Documentation: http://github.com/Zapotek/arachni/wiki'
|
|
166
|
+
print_line
|
|
167
|
+
print_line
|
|
168
|
+
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
#
|
|
172
|
+
# Outputs help/usage information.<br/>
|
|
173
|
+
# Displays supported options and parameters.
|
|
174
|
+
#
|
|
175
|
+
# @return [void]
|
|
176
|
+
#
|
|
177
|
+
def usage
|
|
178
|
+
print_line <<USAGE
|
|
179
|
+
Usage: arachni_xmlrpcd_monitor [server address]
|
|
180
|
+
|
|
181
|
+
Supported options:
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
SSL --------------------------
|
|
185
|
+
|
|
186
|
+
--ssl use SSL?
|
|
187
|
+
(If you want encryption without authentication
|
|
188
|
+
you can skip rest of the SSL options.)
|
|
189
|
+
|
|
190
|
+
--ssl-pkey <file> location of the SSL private key (.pem)
|
|
191
|
+
(Used to verify the the client to the servers.)
|
|
192
|
+
|
|
193
|
+
--ssl-cert <file> location of the SSL certificate (.pem)
|
|
194
|
+
(Used to verify the the client to the servers.)
|
|
195
|
+
|
|
196
|
+
--ssl-ca <file> location of the CA certificate (.pem)
|
|
197
|
+
(Used to verify the servers to the client.)
|
|
198
|
+
USAGE
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
end
|
|
204
|
+
end
|
|
@@ -0,0 +1,843 @@
|
|
|
1
|
+
require 'xmlrpc/client'
|
|
2
|
+
require 'openssl'
|
|
3
|
+
|
|
4
|
+
module Arachni
|
|
5
|
+
|
|
6
|
+
require Options.instance.dir['lib'] + 'rpc/xml/client/dispatcher'
|
|
7
|
+
require Options.instance.dir['lib'] + 'rpc/xml/client/instance'
|
|
8
|
+
|
|
9
|
+
require Options.instance.dir['lib'] + 'module/utilities'
|
|
10
|
+
require Options.instance.dir['lib'] + 'ui/cli/output'
|
|
11
|
+
require Options.instance.dir['lib'] + 'framework'
|
|
12
|
+
|
|
13
|
+
module UI
|
|
14
|
+
|
|
15
|
+
#
|
|
16
|
+
# Arachni::UI:XMLRPC class
|
|
17
|
+
#
|
|
18
|
+
# Provides an self sufficient Arachni XML-RPC client.
|
|
19
|
+
#
|
|
20
|
+
# It mimics the standard CLI interface's functionality
|
|
21
|
+
# albeit in a client-server fashion.
|
|
22
|
+
#
|
|
23
|
+
# This should be your first stop when looking into creating your own XMLRPC client. <br/>
|
|
24
|
+
# Of course you don't need to instantiate the framework or any other Arachni related classes
|
|
25
|
+
# in your own client, this is just to provide some other info to the user.
|
|
26
|
+
#
|
|
27
|
+
#
|
|
28
|
+
# @author: Tasos "Zapotek" Laskos
|
|
29
|
+
# <tasos.laskos@gmail.com>
|
|
30
|
+
# <zapotek@segfault.gr>
|
|
31
|
+
# @version: 0.1.2
|
|
32
|
+
#
|
|
33
|
+
class XMLRPC
|
|
34
|
+
|
|
35
|
+
include Arachni::UI::Output
|
|
36
|
+
include Arachni::Module::Utilities
|
|
37
|
+
|
|
38
|
+
def initialize( opts )
|
|
39
|
+
|
|
40
|
+
@opts = opts
|
|
41
|
+
|
|
42
|
+
# if we have a load profile load it and merge it with the
|
|
43
|
+
# user supplied options
|
|
44
|
+
if( @opts.load_profile )
|
|
45
|
+
load_profile( @opts.load_profile )
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
debug! if @opts.debug
|
|
49
|
+
|
|
50
|
+
# we don't need the framework for much,
|
|
51
|
+
# in this case only for report generation, version number etc.
|
|
52
|
+
@framework = Arachni::Framework.new( @opts )
|
|
53
|
+
|
|
54
|
+
# print banner message
|
|
55
|
+
banner
|
|
56
|
+
|
|
57
|
+
# if the user needs help, output it and exit
|
|
58
|
+
if opts.help
|
|
59
|
+
usage
|
|
60
|
+
exit 0
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# if the user wants to see the available reports, output them and exit
|
|
64
|
+
if !opts.lsrep.empty?
|
|
65
|
+
lsrep
|
|
66
|
+
exit
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
if opts.show_profile
|
|
70
|
+
print_profile( )
|
|
71
|
+
exit 0
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
if opts.save_profile
|
|
75
|
+
exception_jail{ save_profile( opts.save_profile ) }
|
|
76
|
+
exit 0
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
# Check for missing url
|
|
81
|
+
if( !@opts.url && !@opts.lsmod )
|
|
82
|
+
print_error( "Missing url argument." )
|
|
83
|
+
exit 0
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
begin
|
|
87
|
+
|
|
88
|
+
@dispatcher = Arachni::RPC::XML::Client::Dispatcher.new( @opts, @opts.server )
|
|
89
|
+
|
|
90
|
+
# get a new instance and assign the url we're going to audit as the
|
|
91
|
+
# 'owner'
|
|
92
|
+
@instance = @dispatcher.dispatch( @opts.url.to_s )
|
|
93
|
+
|
|
94
|
+
instance_url = URI( @opts.server.to_s )
|
|
95
|
+
instance_url.port = @instance['port']
|
|
96
|
+
|
|
97
|
+
# start the XMLRPC client
|
|
98
|
+
@server = Arachni::RPC::XML::Client::Instance.new( @opts, instance_url.to_s )
|
|
99
|
+
rescue Exception => e
|
|
100
|
+
print_error( "Could not connect to server." )
|
|
101
|
+
print_error( "Error: #{e.to_s}." )
|
|
102
|
+
print_debug_backtrace( e )
|
|
103
|
+
exit 0
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# if the user wants to see the available reports, output them and exit
|
|
107
|
+
if !opts.lsplug.empty?
|
|
108
|
+
lsplug( @server.framework.lsplug )
|
|
109
|
+
shutdown
|
|
110
|
+
exit
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# if the user wants to see the available modules
|
|
114
|
+
# grab them from the server, output them, exit and shutdown the server.
|
|
115
|
+
if !opts.lsmod.empty?
|
|
116
|
+
lsmod( @server.framework.lsmod )
|
|
117
|
+
shutdown
|
|
118
|
+
exit
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
#
|
|
122
|
+
# we could just execute pause() upon an interrupt but XMLRPC I/O
|
|
123
|
+
# needs to be synchronized otherwise we'll get an HTTP exception
|
|
124
|
+
#
|
|
125
|
+
@pause = false
|
|
126
|
+
trap( 'INT' ){ @pause = true }
|
|
127
|
+
|
|
128
|
+
begin
|
|
129
|
+
parse_opts
|
|
130
|
+
rescue Exception => e
|
|
131
|
+
print_error( 'Error: ' + e.to_s )
|
|
132
|
+
print_debug_backtrace( e )
|
|
133
|
+
begin
|
|
134
|
+
shutdown
|
|
135
|
+
rescue
|
|
136
|
+
end
|
|
137
|
+
exit
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def run
|
|
142
|
+
|
|
143
|
+
exception_jail {
|
|
144
|
+
print_status 'Running framework...'
|
|
145
|
+
@server.framework.run
|
|
146
|
+
|
|
147
|
+
print_line
|
|
148
|
+
|
|
149
|
+
# grab the XMLRPC server output while a scan is running
|
|
150
|
+
while( @server.framework.busy? )
|
|
151
|
+
output
|
|
152
|
+
|
|
153
|
+
pause if @pause
|
|
154
|
+
|
|
155
|
+
# things will get crazy if we don't block a bit I think...
|
|
156
|
+
# we'll see...
|
|
157
|
+
::IO::select( nil, nil, nil, 0.3 )
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
puts
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
report
|
|
164
|
+
shutdown
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
private
|
|
168
|
+
|
|
169
|
+
#
|
|
170
|
+
# Loads an Arachni Framework Profile file and merges it with the
|
|
171
|
+
# user supplied options.
|
|
172
|
+
#
|
|
173
|
+
# @param [String] filename the file to load
|
|
174
|
+
#
|
|
175
|
+
def load_profile( profiles )
|
|
176
|
+
exception_jail{
|
|
177
|
+
@opts.load_profile = nil
|
|
178
|
+
profiles.each {
|
|
179
|
+
|filename|
|
|
180
|
+
@opts.merge!( YAML::load( IO.read( filename ) ) )
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
#
|
|
186
|
+
# Saves options to an Arachni Framework Profile file.<br/>
|
|
187
|
+
# The file will be appended with the {PROFILE_EXT} extension.
|
|
188
|
+
#
|
|
189
|
+
# @param [String] filename
|
|
190
|
+
#
|
|
191
|
+
def save_profile( filename )
|
|
192
|
+
|
|
193
|
+
if filename = @opts.save( filename )
|
|
194
|
+
print_status( "Saved profile in '#{filename}'." )
|
|
195
|
+
print_line( )
|
|
196
|
+
else
|
|
197
|
+
banner( )
|
|
198
|
+
print_error( 'Could not save profile.' )
|
|
199
|
+
exit 0
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
#
|
|
204
|
+
# Grabs the output from the XMLRPC server and routes it to the proper output method.
|
|
205
|
+
#
|
|
206
|
+
def output
|
|
207
|
+
@server.service.output.each {
|
|
208
|
+
|out|
|
|
209
|
+
type = out.keys[0]
|
|
210
|
+
msg = out.values[0]
|
|
211
|
+
begin
|
|
212
|
+
self.send( "print_#{type}", msg )
|
|
213
|
+
rescue
|
|
214
|
+
print_line( msg )
|
|
215
|
+
end
|
|
216
|
+
}
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
#
|
|
220
|
+
# Handles Ctrl+C interrupts
|
|
221
|
+
#
|
|
222
|
+
# Once an interrupt has been trapped the system pauses and waits
|
|
223
|
+
# for user input. <br/>
|
|
224
|
+
# The user can either continue or exit.
|
|
225
|
+
#
|
|
226
|
+
# The interrupt will be handled after a module has finished.
|
|
227
|
+
#
|
|
228
|
+
def pause( )
|
|
229
|
+
|
|
230
|
+
print_status( 'Paused...' )
|
|
231
|
+
@server.framework.pause!
|
|
232
|
+
|
|
233
|
+
print_line
|
|
234
|
+
print_info( 'Results thus far:' )
|
|
235
|
+
|
|
236
|
+
#
|
|
237
|
+
# make it easier on the user, grab the report to have something
|
|
238
|
+
# to show him while the scan is paused.
|
|
239
|
+
#
|
|
240
|
+
begin
|
|
241
|
+
print_issues( YAML.load( @server.framework.report ) )
|
|
242
|
+
rescue Exception => e
|
|
243
|
+
exception_jail{ raise e }
|
|
244
|
+
exit 0
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
print_info( 'Arachni was interrupted,' +
|
|
248
|
+
' do you want to continue?' )
|
|
249
|
+
|
|
250
|
+
print_info( 'Continue? (hit \'enter\' to continue, \'e\' to exit)' )
|
|
251
|
+
|
|
252
|
+
if gets[0] == 'e'
|
|
253
|
+
print_status( 'Aborting scan...' )
|
|
254
|
+
@server.framework.abort!
|
|
255
|
+
report
|
|
256
|
+
shutdown
|
|
257
|
+
print_info( 'Exiting...' )
|
|
258
|
+
exit 0
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
@pause = false
|
|
262
|
+
@server.framework.resume!
|
|
263
|
+
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
#
|
|
267
|
+
# Laconically output the discovered issues
|
|
268
|
+
#
|
|
269
|
+
# This method is used during a pause.
|
|
270
|
+
#
|
|
271
|
+
def print_issues( audit_store )
|
|
272
|
+
|
|
273
|
+
print_line( )
|
|
274
|
+
print_info( audit_store['issues'].size.to_s +
|
|
275
|
+
' issues have been detected.' )
|
|
276
|
+
|
|
277
|
+
print_line( )
|
|
278
|
+
audit_store['issues'].each {
|
|
279
|
+
|issue|
|
|
280
|
+
|
|
281
|
+
print_ok( "#{issue['name']} (In #{issue['elem']} variable '#{issue['var']}'" +
|
|
282
|
+
" - Severity: #{issue['severity']} - Variations: #{issue['variations'].size.to_s})" )
|
|
283
|
+
|
|
284
|
+
print_info( issue['variations'][0]['url'] )
|
|
285
|
+
|
|
286
|
+
print_line( )
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
print_line( )
|
|
290
|
+
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
#
|
|
294
|
+
# Parses, sets and sends options to the XMLRPC server.
|
|
295
|
+
#
|
|
296
|
+
def parse_opts
|
|
297
|
+
|
|
298
|
+
#
|
|
299
|
+
# No modules have been specified, set the mods to '*' (all).
|
|
300
|
+
#
|
|
301
|
+
if( !@opts.mods || @opts.mods.empty? )
|
|
302
|
+
print_info( "No modules were specified." )
|
|
303
|
+
print_info( " -> Will run all mods." )
|
|
304
|
+
|
|
305
|
+
@opts.mods = ['*']
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
#
|
|
309
|
+
# The user hasn't selected any elements to audit, set it to audit links, forms and cookies.
|
|
310
|
+
#
|
|
311
|
+
if( !@opts.audit_links &&
|
|
312
|
+
!@opts.audit_forms &&
|
|
313
|
+
!@opts.audit_cookies &&
|
|
314
|
+
!@opts.audit_headers
|
|
315
|
+
)
|
|
316
|
+
print_info( "No audit options were specified." )
|
|
317
|
+
print_info( " -> Will audit links, forms and cookies." )
|
|
318
|
+
|
|
319
|
+
@opts.audit_links = true
|
|
320
|
+
@opts.audit_forms = true
|
|
321
|
+
@opts.audit_cookies = true
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
# do not send these options over the wire
|
|
325
|
+
illegal = [
|
|
326
|
+
# this is bad, do not override the server's directory structure
|
|
327
|
+
'dir',
|
|
328
|
+
|
|
329
|
+
# this is of no use to the server is a local option for this UI
|
|
330
|
+
'server',
|
|
331
|
+
|
|
332
|
+
# profiles are not to be sent over the wire
|
|
333
|
+
'load_profile',
|
|
334
|
+
|
|
335
|
+
# report options should remain local
|
|
336
|
+
# If you send this to the server it will cause a Ruby segfault.
|
|
337
|
+
'repopts',
|
|
338
|
+
'repsave',
|
|
339
|
+
|
|
340
|
+
# do not automatically send this options over
|
|
341
|
+
# we'll take care of this ourselves as soon as we get to the 'cookie_jar'
|
|
342
|
+
# option.
|
|
343
|
+
'cookies'
|
|
344
|
+
]
|
|
345
|
+
|
|
346
|
+
@server.plugins.load(
|
|
347
|
+
{
|
|
348
|
+
'content_types' => {},
|
|
349
|
+
'healthmap' => {},
|
|
350
|
+
'metamodules' => {},
|
|
351
|
+
}
|
|
352
|
+
)
|
|
353
|
+
@opts.to_h.each {
|
|
354
|
+
|opt, arg|
|
|
355
|
+
|
|
356
|
+
next if !arg
|
|
357
|
+
next if illegal.include? opt
|
|
358
|
+
|
|
359
|
+
case opt
|
|
360
|
+
|
|
361
|
+
when "arachni_verbose"
|
|
362
|
+
print_status "Enabling verbosity."
|
|
363
|
+
verbose!
|
|
364
|
+
@server.framework.verbose_on
|
|
365
|
+
|
|
366
|
+
when 'redundant'
|
|
367
|
+
print_status 'Setting redundancy rules.'
|
|
368
|
+
|
|
369
|
+
redundant = []
|
|
370
|
+
arg.each {
|
|
371
|
+
|rule|
|
|
372
|
+
rule['regexp'] = rule['regexp'].to_s
|
|
373
|
+
redundant << rule
|
|
374
|
+
}
|
|
375
|
+
@server.opts.redundant( redundant )
|
|
376
|
+
|
|
377
|
+
when 'exclude', 'include'
|
|
378
|
+
print_status "Setting #{opt} rules."
|
|
379
|
+
@server.call( "opts.#{opt}=", arg.map{ |rule| rule.to_s } )
|
|
380
|
+
|
|
381
|
+
when 'url'
|
|
382
|
+
print_status 'Setting url: ' + @server.call( "opts.url=", arg.to_s )
|
|
383
|
+
|
|
384
|
+
when 'cookie_jar'
|
|
385
|
+
print_status 'Setting cookies:'
|
|
386
|
+
@server.opts.cookies( parse_cookie_jar( arg ) ).each_pair {
|
|
387
|
+
|k, v|
|
|
388
|
+
print_info ' * ' + k + ' => ' + v
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
when 'mods'
|
|
392
|
+
print_status 'Loading modules:'
|
|
393
|
+
@server.modules.load( arg ).each {
|
|
394
|
+
|mod|
|
|
395
|
+
print_info ' * ' + mod
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
when 'plugins'
|
|
399
|
+
next if arg.empty?
|
|
400
|
+
|
|
401
|
+
ap arg
|
|
402
|
+
print_status 'Loading plug-ins:'
|
|
403
|
+
@server.plugins.load( arg ).each {
|
|
404
|
+
|mod|
|
|
405
|
+
print_info ' * ' + mod
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
when "http_req_limit"
|
|
409
|
+
print_status 'Setting HTTP request limit: ' +
|
|
410
|
+
@server.opts.http_req_limit( arg ).to_s
|
|
411
|
+
|
|
412
|
+
when 'reports'
|
|
413
|
+
arg['stdout'] = {}
|
|
414
|
+
exception_jail{ @framework.reports.load( arg.keys ) }
|
|
415
|
+
|
|
416
|
+
else
|
|
417
|
+
print_status "Setting #{opt}."
|
|
418
|
+
@server.call( "opts.#{opt}=", arg )
|
|
419
|
+
|
|
420
|
+
end
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
end
|
|
424
|
+
|
|
425
|
+
#
|
|
426
|
+
# Remote kill-switch, shuts down the server
|
|
427
|
+
#
|
|
428
|
+
def shutdown
|
|
429
|
+
print_status "Shutting down the server..."
|
|
430
|
+
@server.service.shutdown
|
|
431
|
+
end
|
|
432
|
+
|
|
433
|
+
#
|
|
434
|
+
# Grabs the report from the XMLRPC server and runs the selected Arachni report module.
|
|
435
|
+
#
|
|
436
|
+
def report
|
|
437
|
+
print_status "Grabbing scan report..."
|
|
438
|
+
|
|
439
|
+
# this will return the AuditStore as a hash
|
|
440
|
+
# ap @server.call( "framework.report" )
|
|
441
|
+
|
|
442
|
+
# this will return the AuditStore as a string in YAML format
|
|
443
|
+
audit_store = YAML.load( @server.framework.auditstore )
|
|
444
|
+
|
|
445
|
+
# run the loaded reports and get the generated filename
|
|
446
|
+
@framework.reports.run( audit_store )
|
|
447
|
+
|
|
448
|
+
print_status "Grabbing stats..."
|
|
449
|
+
|
|
450
|
+
stats = @server.framework.stats
|
|
451
|
+
print_line
|
|
452
|
+
print_info( "Sent #{stats['requests']} requests." )
|
|
453
|
+
print_info( "Received and analyzed #{stats['responses']} responses." )
|
|
454
|
+
print_info( 'In ' + stats['time'] )
|
|
455
|
+
|
|
456
|
+
avg = 'Average: ' + stats['avg'] + ' requests/second.'
|
|
457
|
+
print_info( avg )
|
|
458
|
+
|
|
459
|
+
print_line
|
|
460
|
+
|
|
461
|
+
end
|
|
462
|
+
|
|
463
|
+
def parse_cookie_jar( jar )
|
|
464
|
+
# make sure that the provided cookie-jar file exists
|
|
465
|
+
if !File.exist?( jar )
|
|
466
|
+
raise( Arachni::Exceptions::NoCookieJar,
|
|
467
|
+
'Cookie-jar \'' + jar + '\' doesn\'t exist.' )
|
|
468
|
+
end
|
|
469
|
+
|
|
470
|
+
return Arachni::Module::HTTP.parse_cookiejar( jar )
|
|
471
|
+
end
|
|
472
|
+
|
|
473
|
+
#
|
|
474
|
+
# Outputs all available modules and their info.
|
|
475
|
+
#
|
|
476
|
+
def lsmod( mods )
|
|
477
|
+
|
|
478
|
+
i = 0
|
|
479
|
+
print_info( 'Available modules:' )
|
|
480
|
+
print_line
|
|
481
|
+
|
|
482
|
+
mods.each {
|
|
483
|
+
|info|
|
|
484
|
+
|
|
485
|
+
print_status( "#{info['mod_name']}:" )
|
|
486
|
+
print_line( "--------------------" )
|
|
487
|
+
|
|
488
|
+
print_line( "Name:\t\t" + info['name'] )
|
|
489
|
+
print_line( "Description:\t" + info['description'] )
|
|
490
|
+
|
|
491
|
+
if( info['elements'] && info['elements'].size > 0 )
|
|
492
|
+
print_line( "Elements:\t" +
|
|
493
|
+
info['elements'].join( ', ' ).downcase )
|
|
494
|
+
end
|
|
495
|
+
|
|
496
|
+
if( info['dependencies'] )
|
|
497
|
+
print_line( "Dependencies:\t" +
|
|
498
|
+
info['dependencies'].join( ', ' ).downcase )
|
|
499
|
+
end
|
|
500
|
+
|
|
501
|
+
print_line( "Author:\t\t" + info['author'] )
|
|
502
|
+
print_line( "Version:\t" + info['version'] )
|
|
503
|
+
|
|
504
|
+
print_line( "References:" )
|
|
505
|
+
if info['references'].is_a?( Hash )
|
|
506
|
+
info['references'].keys.each {
|
|
507
|
+
|key|
|
|
508
|
+
print_info( key + "\t\t" + info['references'][key] )
|
|
509
|
+
}
|
|
510
|
+
end
|
|
511
|
+
|
|
512
|
+
print_line( "Targets:" )
|
|
513
|
+
info['targets'].keys.each {
|
|
514
|
+
|key|
|
|
515
|
+
print_info( key + "\t\t" + info['targets'][key] )
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
if( info['issue'] &&
|
|
519
|
+
( sploit = info['issue']['metasploitable'] ) )
|
|
520
|
+
print_line( "Metasploitable:\t" + sploit )
|
|
521
|
+
end
|
|
522
|
+
|
|
523
|
+
print_line( "Path:\t" + info['path'] )
|
|
524
|
+
|
|
525
|
+
i+=1
|
|
526
|
+
|
|
527
|
+
# pause every 3 modules to give the user time to read
|
|
528
|
+
# (cheers to aungkhant@yehg.net for suggesting it)
|
|
529
|
+
if( i % 3 == 0 && i != mods.size )
|
|
530
|
+
print_line
|
|
531
|
+
print_line( 'Hit <space> <enter> to continue, any other key to exit. ' )
|
|
532
|
+
|
|
533
|
+
if gets[0] != " "
|
|
534
|
+
print_line
|
|
535
|
+
return
|
|
536
|
+
end
|
|
537
|
+
|
|
538
|
+
end
|
|
539
|
+
|
|
540
|
+
print_line
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
end
|
|
544
|
+
|
|
545
|
+
#
|
|
546
|
+
# Outputs all available reports and their info.
|
|
547
|
+
#
|
|
548
|
+
def lsrep
|
|
549
|
+
i = 0
|
|
550
|
+
print_info( 'Available reports:' )
|
|
551
|
+
print_line
|
|
552
|
+
|
|
553
|
+
@framework.lsrep().each {
|
|
554
|
+
|info|
|
|
555
|
+
|
|
556
|
+
print_status( "#{info[:rep_name]}:" )
|
|
557
|
+
print_line( "--------------------" )
|
|
558
|
+
|
|
559
|
+
print_line( "Name:\t\t" + info[:name] )
|
|
560
|
+
print_line( "Description:\t" + info[:description] )
|
|
561
|
+
|
|
562
|
+
if( info[:options] && info[:options].size > 0 )
|
|
563
|
+
print_line( "Options:\t" )
|
|
564
|
+
|
|
565
|
+
info[:options].each {
|
|
566
|
+
|option|
|
|
567
|
+
print_info( "\t#{option.name} - #{option.desc}" )
|
|
568
|
+
print_info( "\tType: #{option.type}" )
|
|
569
|
+
print_info( "\tDefault: #{option.default}" )
|
|
570
|
+
print_info( "\tRequired?: #{option.required?}" )
|
|
571
|
+
|
|
572
|
+
print_line( )
|
|
573
|
+
}
|
|
574
|
+
end
|
|
575
|
+
|
|
576
|
+
print_line( "Author:\t\t" + info[:author] )
|
|
577
|
+
print_line( "Version:\t" + info[:version] )
|
|
578
|
+
print_line( "Path:\t" + info[:path] )
|
|
579
|
+
|
|
580
|
+
i+=1
|
|
581
|
+
|
|
582
|
+
print_line
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
end
|
|
586
|
+
|
|
587
|
+
#
|
|
588
|
+
# Outputs all available reports and their info.
|
|
589
|
+
#
|
|
590
|
+
def lsplug( plugins )
|
|
591
|
+
print_line
|
|
592
|
+
print_line
|
|
593
|
+
print_info( 'Available plugins:' )
|
|
594
|
+
print_line
|
|
595
|
+
|
|
596
|
+
plugins.each {
|
|
597
|
+
|info|
|
|
598
|
+
|
|
599
|
+
print_status( "#{info['plug_name']}:" )
|
|
600
|
+
print_line( "--------------------" )
|
|
601
|
+
|
|
602
|
+
print_line( "Name:\t\t" + info['name'] )
|
|
603
|
+
print_line( "Description:\t" + info['description'] )
|
|
604
|
+
|
|
605
|
+
if( info['options'] && !info['options'].empty? )
|
|
606
|
+
print_line( "Options:\t" )
|
|
607
|
+
|
|
608
|
+
info['options'].each {
|
|
609
|
+
|option|
|
|
610
|
+
print_info( "\t#{option['name']} - #{option['desc']}" )
|
|
611
|
+
print_info( "\tType: #{option['type']}" )
|
|
612
|
+
print_info( "\tDefault: #{option['default']}" )
|
|
613
|
+
print_info( "\tRequired?: #{option['required']}" )
|
|
614
|
+
|
|
615
|
+
print_line( )
|
|
616
|
+
}
|
|
617
|
+
end
|
|
618
|
+
|
|
619
|
+
print_line( "Author:\t\t" + info['author'] )
|
|
620
|
+
print_line( "Version:\t" + info['version'] )
|
|
621
|
+
print_line( "Path:\t" + info['path'] )
|
|
622
|
+
|
|
623
|
+
print_line
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
end
|
|
627
|
+
|
|
628
|
+
|
|
629
|
+
#
|
|
630
|
+
# Outputs Arachni banner.<br/>
|
|
631
|
+
# Displays version number, revision number, author details etc.
|
|
632
|
+
#
|
|
633
|
+
# @see VERSION
|
|
634
|
+
# @see REVISION
|
|
635
|
+
#
|
|
636
|
+
# @return [void]
|
|
637
|
+
#
|
|
638
|
+
def banner
|
|
639
|
+
print_line 'Arachni - Web Application Security Scanner Framework v' +
|
|
640
|
+
@framework.version + ' [' + @framework.revision + ']
|
|
641
|
+
Author: Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
|
|
642
|
+
<zapotek@segfault.gr>
|
|
643
|
+
(With the support of the community and the Arachni Team.)
|
|
644
|
+
|
|
645
|
+
Website: http://github.com/Zapotek/arachni
|
|
646
|
+
Documentation: http://github.com/Zapotek/arachni/wiki'
|
|
647
|
+
print_line
|
|
648
|
+
print_line
|
|
649
|
+
|
|
650
|
+
end
|
|
651
|
+
|
|
652
|
+
def print_profile( )
|
|
653
|
+
print_info( 'Running profile:' )
|
|
654
|
+
print_info( @opts.to_args )
|
|
655
|
+
end
|
|
656
|
+
|
|
657
|
+
#
|
|
658
|
+
# Outputs help/usage information.<br/>
|
|
659
|
+
# Displays supported options and parameters.
|
|
660
|
+
#
|
|
661
|
+
# @return [void]
|
|
662
|
+
#
|
|
663
|
+
def usage
|
|
664
|
+
print_line <<USAGE
|
|
665
|
+
Usage: arachni_xmlrpc --server http[s]://host:port/ \[options\] url
|
|
666
|
+
|
|
667
|
+
Supported options:
|
|
668
|
+
|
|
669
|
+
|
|
670
|
+
SSL --------------------------
|
|
671
|
+
(Do *not* use encrypted keys!)
|
|
672
|
+
|
|
673
|
+
--ssl use SSL?
|
|
674
|
+
(If you want encryption without authentication
|
|
675
|
+
you can skip rest of the SSL options.)
|
|
676
|
+
|
|
677
|
+
--ssl-pkey <file> location of the SSL private key (.pem)
|
|
678
|
+
(Used to verify the the client to the servers.)
|
|
679
|
+
|
|
680
|
+
--ssl-cert <file> location of the SSL certificate (.pem)
|
|
681
|
+
(Used to verify the the client to the servers.)
|
|
682
|
+
|
|
683
|
+
--ssl-ca <file> location of the CA certificate (.pem)
|
|
684
|
+
(Used to verify the servers to the client.)
|
|
685
|
+
|
|
686
|
+
|
|
687
|
+
General ----------------------
|
|
688
|
+
|
|
689
|
+
-h
|
|
690
|
+
--help output this
|
|
691
|
+
|
|
692
|
+
-v be verbose
|
|
693
|
+
|
|
694
|
+
--debug show what is happening internally
|
|
695
|
+
(You should give it a shot sometime ;) )
|
|
696
|
+
|
|
697
|
+
--only-positives echo positive results *only*
|
|
698
|
+
|
|
699
|
+
--http-req-limit concurent HTTP requests limit
|
|
700
|
+
(Be carefull not to kill your server.)
|
|
701
|
+
(Default: 60)
|
|
702
|
+
(*NOTE*: If your scan seems unresponsive try lowering the limit.)
|
|
703
|
+
|
|
704
|
+
--http-harvest-last build up the HTTP request queue of the audit for the whole site
|
|
705
|
+
and harvest the HTTP responses at the end of the crawl.
|
|
706
|
+
(In some test cases this option has split the scan time in half.)
|
|
707
|
+
(Default: responses will be harvested for each page)
|
|
708
|
+
(*NOTE*: If you are scanning a high-end server and
|
|
709
|
+
you are using a powerful machine with enough bandwidth
|
|
710
|
+
*and* you feel dangerous you can use
|
|
711
|
+
this flag with an increased '--http-req-limit'
|
|
712
|
+
to get maximum performance out of your scan.)
|
|
713
|
+
(*WARNING*: When scanning large websites with hundreads
|
|
714
|
+
of pages this could eat up all your memory pretty quickly.)
|
|
715
|
+
|
|
716
|
+
--cookie-jar=<cookiejar> netscape HTTP cookie file, use curl to create it
|
|
717
|
+
|
|
718
|
+
|
|
719
|
+
--user-agent=<user agent> specify user agent
|
|
720
|
+
|
|
721
|
+
--authed-by=<who> who authorized the scan, include name and e-mail address
|
|
722
|
+
(It'll make it easier on the sys-admins during log reviews.)
|
|
723
|
+
(Will be appended to the user-agent string.)
|
|
724
|
+
|
|
725
|
+
|
|
726
|
+
Profiles -----------------------
|
|
727
|
+
|
|
728
|
+
--save-profile=<file> save the current run profile/options to <file>
|
|
729
|
+
|
|
730
|
+
--load-profile=<file> load a run profile from <file>
|
|
731
|
+
(Can be used multiple times.)
|
|
732
|
+
(You can complement it with more options, except for:
|
|
733
|
+
* --mods
|
|
734
|
+
* --redundant)
|
|
735
|
+
|
|
736
|
+
--show-profile will output the running profile as CLI arguments
|
|
737
|
+
|
|
738
|
+
|
|
739
|
+
Crawler -----------------------
|
|
740
|
+
|
|
741
|
+
-e <regex>
|
|
742
|
+
--exclude=<regex> exclude urls matching regex
|
|
743
|
+
(Can be used multiple times.)
|
|
744
|
+
|
|
745
|
+
-i <regex>
|
|
746
|
+
--include=<regex> include urls matching this regex only
|
|
747
|
+
(Can be used multiple times.)
|
|
748
|
+
|
|
749
|
+
--redundant=<regex>:<count> limit crawl on redundant pages like galleries or catalogs
|
|
750
|
+
(URLs matching <regex> will be crawled <count> links deep.)
|
|
751
|
+
(Can be used multiple times.)
|
|
752
|
+
|
|
753
|
+
-f
|
|
754
|
+
--follow-subdomains follow links to subdomains (default: off)
|
|
755
|
+
|
|
756
|
+
--obey-robots-txt obey robots.txt file (default: off)
|
|
757
|
+
|
|
758
|
+
--depth=<number> depth limit (default: inf)
|
|
759
|
+
(How deep Arachni should go into the site structure.)
|
|
760
|
+
|
|
761
|
+
--link-count=<number> how many links to follow (default: inf)
|
|
762
|
+
|
|
763
|
+
--redirect-limit=<number> how many redirects to follow (default: inf)
|
|
764
|
+
|
|
765
|
+
--spider-first spider first, audit later
|
|
766
|
+
|
|
767
|
+
|
|
768
|
+
Auditor ------------------------
|
|
769
|
+
|
|
770
|
+
-g
|
|
771
|
+
--audit-links audit link variables (GET)
|
|
772
|
+
|
|
773
|
+
-p
|
|
774
|
+
--audit-forms audit form variables
|
|
775
|
+
(usually POST, can also be GET)
|
|
776
|
+
|
|
777
|
+
-c
|
|
778
|
+
--audit-cookies audit cookies (COOKIE)
|
|
779
|
+
|
|
780
|
+
--exclude-cookie=<name> cookies not to audit
|
|
781
|
+
(You should exclude session cookies.)
|
|
782
|
+
(Can be used multiple times.)
|
|
783
|
+
|
|
784
|
+
--audit-headers audit HTTP headers
|
|
785
|
+
(*NOTE*: Header audits use brute force.
|
|
786
|
+
Almost all valid HTTP request headers will be audited
|
|
787
|
+
even if there's no indication that the web app uses them.)
|
|
788
|
+
(*WARNING*: Enabling this option will result in increased requests,
|
|
789
|
+
maybe by an order of magnitude.)
|
|
790
|
+
|
|
791
|
+
|
|
792
|
+
Modules ------------------------
|
|
793
|
+
|
|
794
|
+
--lsmod=<regexp> list available modules based on the provided regular expression
|
|
795
|
+
(If no regexp is provided all modules will be listed.)
|
|
796
|
+
(Can be used multiple times.)
|
|
797
|
+
|
|
798
|
+
|
|
799
|
+
-m <modname,modname..>
|
|
800
|
+
--mods=<modname,modname..> comma separated list of modules to deploy
|
|
801
|
+
(Use '*' as a module name to deploy all modules or inside module names like so:
|
|
802
|
+
xss_* to load all xss modules
|
|
803
|
+
sqli_* to load all sql injection modules
|
|
804
|
+
etc.
|
|
805
|
+
|
|
806
|
+
You can exclude modules by prefixing their name with a dash:
|
|
807
|
+
--mods=*,-backup_files,-xss
|
|
808
|
+
The above will load all modules except for the 'backup_files' and 'xss' modules.
|
|
809
|
+
|
|
810
|
+
Or mix and match:
|
|
811
|
+
-xss_* to unload all xss modules. )
|
|
812
|
+
|
|
813
|
+
|
|
814
|
+
Reports ------------------------
|
|
815
|
+
|
|
816
|
+
--lsrep list available reports
|
|
817
|
+
|
|
818
|
+
--repload=<file> load audit results from an .afr file
|
|
819
|
+
(Allows you to create new reports from finished scans.)
|
|
820
|
+
|
|
821
|
+
--report='<report>:<optname>=<val>,<optname2>=<val2>,...'
|
|
822
|
+
|
|
823
|
+
<report>: the name of the report as displayed by '--lsrep'
|
|
824
|
+
(Default: stdout)
|
|
825
|
+
(Can be used multiple times.)
|
|
826
|
+
|
|
827
|
+
|
|
828
|
+
Plugins ------------------------
|
|
829
|
+
|
|
830
|
+
--lsplug list available plugins
|
|
831
|
+
|
|
832
|
+
--plugin='<plugin>:<optname>=<val>,<optname2>=<val2>,...'
|
|
833
|
+
|
|
834
|
+
<plugin>: the name of the plugin as displayed by '--lsplug'
|
|
835
|
+
(Can be used multiple times.)
|
|
836
|
+
|
|
837
|
+
USAGE
|
|
838
|
+
end
|
|
839
|
+
|
|
840
|
+
end
|
|
841
|
+
|
|
842
|
+
end
|
|
843
|
+
end
|