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,293 @@
|
|
|
1
|
+
=begin
|
|
2
|
+
Arachni
|
|
3
|
+
Copyright (c) 2010-2011 Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
|
|
4
|
+
|
|
5
|
+
This is free software; you can copy and distribute and modify
|
|
6
|
+
this program under the term of the GPL v2.0 License
|
|
7
|
+
(See LICENSE file for details)
|
|
8
|
+
|
|
9
|
+
=end
|
|
10
|
+
|
|
11
|
+
module Arachni
|
|
12
|
+
|
|
13
|
+
require Options.instance.dir['lib'] + 'component_options'
|
|
14
|
+
|
|
15
|
+
#
|
|
16
|
+
# Component Manager
|
|
17
|
+
#
|
|
18
|
+
# Handles modules, reports, path extrator modules, plug-ins, pretty much
|
|
19
|
+
# every modular aspect of the framework.
|
|
20
|
+
#
|
|
21
|
+
# It is usually extended to fill-in for system specific functionality.
|
|
22
|
+
#
|
|
23
|
+
# @author: Tasos "Zapotek" Laskos
|
|
24
|
+
# <tasos.laskos@gmail.com>
|
|
25
|
+
# <zapotek@segfault.gr>
|
|
26
|
+
# @version: 0.1
|
|
27
|
+
#
|
|
28
|
+
class ComponentManager < Hash
|
|
29
|
+
|
|
30
|
+
include Arachni::UI::Output
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
#
|
|
34
|
+
# The following are used by {#parse}:
|
|
35
|
+
# * '*' means all modules
|
|
36
|
+
# * module names prefixed with '-' will be excluded
|
|
37
|
+
#
|
|
38
|
+
WILDCARD = '*'
|
|
39
|
+
EXCLUDE = '-'
|
|
40
|
+
|
|
41
|
+
#
|
|
42
|
+
# @param [String] lib the path to the component library/folder
|
|
43
|
+
# @param [Module] parent the parent module of the components
|
|
44
|
+
#
|
|
45
|
+
def initialize( lib, parent )
|
|
46
|
+
@lib = lib
|
|
47
|
+
@parent = parent
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
#
|
|
51
|
+
# Loads components.
|
|
52
|
+
#
|
|
53
|
+
# @param [Array] components array of names of components to load
|
|
54
|
+
#
|
|
55
|
+
def load( components )
|
|
56
|
+
parse( components ).each {
|
|
57
|
+
|component|
|
|
58
|
+
self.[]( component )
|
|
59
|
+
}
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
#
|
|
63
|
+
# Validates and prepares options for a given component.
|
|
64
|
+
#
|
|
65
|
+
# @param [String] component_name the name of the component
|
|
66
|
+
# @param [Class] component the component
|
|
67
|
+
# @param [Hash] user_opts the user options
|
|
68
|
+
#
|
|
69
|
+
# @return [Hash] the prepared options to be passed to the component
|
|
70
|
+
#
|
|
71
|
+
def prep_opts( component_name, component, user_opts = {} )
|
|
72
|
+
info = component.info
|
|
73
|
+
return {} if !info.include?( :options ) || info[:options].empty?
|
|
74
|
+
|
|
75
|
+
user_opts ||= {}
|
|
76
|
+
options = { }
|
|
77
|
+
errors = { }
|
|
78
|
+
info[:options].each {
|
|
79
|
+
|opt|
|
|
80
|
+
|
|
81
|
+
name = opt.name
|
|
82
|
+
val = user_opts[name]
|
|
83
|
+
|
|
84
|
+
if( opt.empty_required_value?( val ) )
|
|
85
|
+
errors[name] = {
|
|
86
|
+
:opt => opt,
|
|
87
|
+
:value => val,
|
|
88
|
+
:type => :empty_required_value
|
|
89
|
+
}
|
|
90
|
+
elsif( !opt.valid?( val ) )
|
|
91
|
+
errors[name] = {
|
|
92
|
+
:opt => opt,
|
|
93
|
+
:value => val,
|
|
94
|
+
:type => :invalid
|
|
95
|
+
}
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
val = !val.nil? ? val : opt.default
|
|
99
|
+
options[name] = opt.normalize( val )
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if( !errors.empty? )
|
|
103
|
+
print_errors( component_name, errors )
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
return options
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
#
|
|
111
|
+
# It parses the component array making sure that its structure is valid
|
|
112
|
+
#
|
|
113
|
+
# @param [Array] components array of component names
|
|
114
|
+
#
|
|
115
|
+
# @return [Array] array of modules to load
|
|
116
|
+
#
|
|
117
|
+
def parse( components )
|
|
118
|
+
unload = []
|
|
119
|
+
load = []
|
|
120
|
+
|
|
121
|
+
return load if components[0] == EXCLUDE
|
|
122
|
+
|
|
123
|
+
components.each {
|
|
124
|
+
|component|
|
|
125
|
+
if component[0] == EXCLUDE
|
|
126
|
+
component[0] = ''
|
|
127
|
+
|
|
128
|
+
if component[WILDCARD]
|
|
129
|
+
unload |= wilcard_to_names( component )
|
|
130
|
+
else
|
|
131
|
+
unload << component
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
end
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if( !components.include?( WILDCARD ) )
|
|
138
|
+
|
|
139
|
+
avail_components = available( )
|
|
140
|
+
|
|
141
|
+
components.each {
|
|
142
|
+
|component|
|
|
143
|
+
|
|
144
|
+
if component.substring?( WILDCARD )
|
|
145
|
+
load |= wilcard_to_names( component )
|
|
146
|
+
else
|
|
147
|
+
|
|
148
|
+
if( avail_components.include?( component ) )
|
|
149
|
+
load << component
|
|
150
|
+
else
|
|
151
|
+
raise( Arachni::Exceptions::ComponentNotFound,
|
|
152
|
+
"Error: Component #{component} wasn't found." )
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
}
|
|
157
|
+
load.flatten!
|
|
158
|
+
|
|
159
|
+
else
|
|
160
|
+
available( ).map {
|
|
161
|
+
|component|
|
|
162
|
+
load << component
|
|
163
|
+
}
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
return load - unload
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
#
|
|
170
|
+
# Returns a component class object by name, loading it on the fly need be.
|
|
171
|
+
#
|
|
172
|
+
# @param [String] name component name
|
|
173
|
+
#
|
|
174
|
+
# @return [Class]
|
|
175
|
+
#
|
|
176
|
+
def []( name )
|
|
177
|
+
|
|
178
|
+
return fetch( name ) if include?( name )
|
|
179
|
+
|
|
180
|
+
paths.each {
|
|
181
|
+
|path|
|
|
182
|
+
|
|
183
|
+
next if name != path_to_name( path )
|
|
184
|
+
self[path_to_name( path )] = load_from_path( path )
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return fetch( name ) rescue nil
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def wilcard_to_names( name )
|
|
191
|
+
if name[WILDCARD]
|
|
192
|
+
return paths.map {
|
|
193
|
+
|path|
|
|
194
|
+
path_to_name( path ) if path.match( Regexp.new( name ) )
|
|
195
|
+
}.compact
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
return
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
#
|
|
202
|
+
# Returns array of available component names.
|
|
203
|
+
#
|
|
204
|
+
# @return [Array]
|
|
205
|
+
#
|
|
206
|
+
def available
|
|
207
|
+
components = []
|
|
208
|
+
paths.each {
|
|
209
|
+
|path|
|
|
210
|
+
name = path_to_name( path )
|
|
211
|
+
components << name
|
|
212
|
+
}
|
|
213
|
+
return components
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
#
|
|
217
|
+
# Converts the name of a component to a file-path.
|
|
218
|
+
#
|
|
219
|
+
# @param [String] name the name of the component
|
|
220
|
+
#
|
|
221
|
+
# @return [String]
|
|
222
|
+
#
|
|
223
|
+
def name_to_path( name )
|
|
224
|
+
paths.each {
|
|
225
|
+
|path|
|
|
226
|
+
return path if name == path_to_name( path )
|
|
227
|
+
}
|
|
228
|
+
return
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
#
|
|
232
|
+
# Converts the path of a component to a component name.
|
|
233
|
+
#
|
|
234
|
+
# @param [String] path the file-path of the component
|
|
235
|
+
#
|
|
236
|
+
# @return [String]
|
|
237
|
+
#
|
|
238
|
+
def path_to_name( path )
|
|
239
|
+
File.basename( path, '.rb' )
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
#
|
|
243
|
+
# Returns the paths of all available components (excluding helper files).
|
|
244
|
+
#
|
|
245
|
+
# @return [Array]
|
|
246
|
+
#
|
|
247
|
+
def paths
|
|
248
|
+
cpaths = paths = Dir.glob( File.join( "#{@lib}**", "*.rb" ) )
|
|
249
|
+
return paths.reject { |path| helper?( path ) }
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
private
|
|
253
|
+
|
|
254
|
+
def print_errors( name, errors )
|
|
255
|
+
|
|
256
|
+
print_line
|
|
257
|
+
print_line
|
|
258
|
+
|
|
259
|
+
print_error( "Invalid options for component: #{name}" )
|
|
260
|
+
|
|
261
|
+
errors.each {
|
|
262
|
+
|optname, error|
|
|
263
|
+
|
|
264
|
+
val = error[:value].nil? ? '<empty>' : error[:value]
|
|
265
|
+
|
|
266
|
+
if( error[:type] == :invalid )
|
|
267
|
+
msg = "Invalid type"
|
|
268
|
+
else
|
|
269
|
+
msg = "Empty required value"
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
print_info( " * #{msg}: #{optname} => #{val}" )
|
|
273
|
+
print_info( " * Expected type: #{error[:opt].type}" )
|
|
274
|
+
|
|
275
|
+
print_line
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
exit
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
def load_from_path( path )
|
|
282
|
+
::Kernel::load( path )
|
|
283
|
+
return @parent.const_get( @parent.constants[-1] )
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
def helper?( path )
|
|
288
|
+
return File.exist?( File.dirname( path ) + '.rb' )
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
end
|
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
=begin
|
|
2
|
+
Arachni
|
|
3
|
+
Copyright (c) 2010-2011 Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
|
|
4
|
+
|
|
5
|
+
This is free software; you can copy and distribute and modify
|
|
6
|
+
this program under the term of the GPL v2.0 License
|
|
7
|
+
(See LICENSE file for details)
|
|
8
|
+
|
|
9
|
+
=end
|
|
10
|
+
|
|
11
|
+
module Arachni
|
|
12
|
+
|
|
13
|
+
#
|
|
14
|
+
# The following are pretty much rip offs of Metasploit's
|
|
15
|
+
# /lib/msf/core/option_container.rb
|
|
16
|
+
#
|
|
17
|
+
#
|
|
18
|
+
|
|
19
|
+
###
|
|
20
|
+
#
|
|
21
|
+
# The base class for all options.
|
|
22
|
+
#
|
|
23
|
+
###
|
|
24
|
+
class OptBase
|
|
25
|
+
|
|
26
|
+
#
|
|
27
|
+
# The name of the option.
|
|
28
|
+
#
|
|
29
|
+
attr_reader :name
|
|
30
|
+
|
|
31
|
+
#
|
|
32
|
+
# Whether or not the option is required.
|
|
33
|
+
#
|
|
34
|
+
attr_reader :required
|
|
35
|
+
|
|
36
|
+
#
|
|
37
|
+
# The description of the option.
|
|
38
|
+
#
|
|
39
|
+
attr_reader :desc
|
|
40
|
+
|
|
41
|
+
#
|
|
42
|
+
# The default value of the option.
|
|
43
|
+
#
|
|
44
|
+
attr_reader :default
|
|
45
|
+
|
|
46
|
+
#
|
|
47
|
+
# Storing the name of the option.
|
|
48
|
+
#
|
|
49
|
+
attr_writer :name
|
|
50
|
+
|
|
51
|
+
#
|
|
52
|
+
# The component that owns this option.
|
|
53
|
+
#
|
|
54
|
+
attr_accessor :owner
|
|
55
|
+
|
|
56
|
+
#
|
|
57
|
+
# The list of potential valid values
|
|
58
|
+
#
|
|
59
|
+
attr_accessor :enums
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
#
|
|
63
|
+
# Initializes a named option with the supplied attribute array.
|
|
64
|
+
# The array is composed of three values.
|
|
65
|
+
#
|
|
66
|
+
# attrs[0] = required (boolean type)
|
|
67
|
+
# attrs[1] = description (string)
|
|
68
|
+
# attrs[2] = default value
|
|
69
|
+
# attrs[3] = possible enum values
|
|
70
|
+
#
|
|
71
|
+
# @param [String] name the name of the options
|
|
72
|
+
# @param [Array] attrs option attributes
|
|
73
|
+
#
|
|
74
|
+
def initialize( name, attrs = [] )
|
|
75
|
+
@name = name
|
|
76
|
+
@required = attrs[0] || false
|
|
77
|
+
@desc = attrs[1]
|
|
78
|
+
@default = attrs[2]
|
|
79
|
+
@enums = [ *(attrs[3]) ].map { |x| x.to_s }
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
#
|
|
83
|
+
# Returns true if this is a required option.
|
|
84
|
+
#
|
|
85
|
+
def required?
|
|
86
|
+
return required
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
#
|
|
90
|
+
# Returns true if the supplied type is equivalent to this option's type.
|
|
91
|
+
#
|
|
92
|
+
def type?( in_type )
|
|
93
|
+
return (type == in_type)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
#
|
|
97
|
+
# If it's required and the value is nil or empty, then it's not valid.
|
|
98
|
+
#
|
|
99
|
+
def valid?( value )
|
|
100
|
+
return ( required? && ( value == nil || value.to_s.empty? ) ) ? false : true
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
#
|
|
104
|
+
# Returns true if the value supplied is nil and it's required to be
|
|
105
|
+
# a valid value
|
|
106
|
+
#
|
|
107
|
+
def empty_required_value?( value )
|
|
108
|
+
return ( required? && value.nil? )
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
#
|
|
112
|
+
# Normalizes the supplied value to conform with the type that the option is
|
|
113
|
+
# conveying.
|
|
114
|
+
#
|
|
115
|
+
def normalize( value )
|
|
116
|
+
value
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
#
|
|
120
|
+
# Converts the Options object to hash
|
|
121
|
+
#
|
|
122
|
+
# @return [Hash]
|
|
123
|
+
#
|
|
124
|
+
def to_h
|
|
125
|
+
hash = Hash.new
|
|
126
|
+
self.instance_variables.each {
|
|
127
|
+
|var|
|
|
128
|
+
hash[var.to_s.gsub( /@/, '' )] = self.instance_variable_get( var )
|
|
129
|
+
}
|
|
130
|
+
return hash
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
protected
|
|
135
|
+
|
|
136
|
+
attr_writer :required, :desc, :default # :nodoc:
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
###
|
|
140
|
+
#
|
|
141
|
+
# Core option types. The core supported option types are:
|
|
142
|
+
#
|
|
143
|
+
# OptString - Multi-byte character string
|
|
144
|
+
# OptBool - Boolean true or false indication
|
|
145
|
+
# OptPort - TCP/UDP service port
|
|
146
|
+
# OptPath - Path name on disk
|
|
147
|
+
# OptInt - An integer value
|
|
148
|
+
# OptEnum - Select from a set of valid values
|
|
149
|
+
#
|
|
150
|
+
###
|
|
151
|
+
|
|
152
|
+
###
|
|
153
|
+
#
|
|
154
|
+
# Mult-byte character string option.
|
|
155
|
+
#
|
|
156
|
+
###
|
|
157
|
+
class OptString < OptBase
|
|
158
|
+
def type
|
|
159
|
+
return 'string'
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def normalize(value)
|
|
163
|
+
if (value =~ /^file:(.*)/)
|
|
164
|
+
path = $1
|
|
165
|
+
begin
|
|
166
|
+
value = File.read(path)
|
|
167
|
+
rescue ::Errno::ENOENT, ::Errno::EISDIR
|
|
168
|
+
value = nil
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
value
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def valid?(value=self.value)
|
|
175
|
+
value = normalize(value)
|
|
176
|
+
return false if empty_required_value?(value)
|
|
177
|
+
return super
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
###
|
|
182
|
+
#
|
|
183
|
+
# Boolean option.
|
|
184
|
+
#
|
|
185
|
+
###
|
|
186
|
+
class OptBool < OptBase
|
|
187
|
+
|
|
188
|
+
TrueRegex = /^(y|yes|t|1|true)$/i
|
|
189
|
+
|
|
190
|
+
def type
|
|
191
|
+
return 'bool'
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
def valid?(value)
|
|
195
|
+
return false if empty_required_value?(value)
|
|
196
|
+
|
|
197
|
+
if ((value != nil and
|
|
198
|
+
(value.to_s.empty? == false) and
|
|
199
|
+
(value.to_s.match(/^(y|yes|n|no|t|f|0|1|true|false)$/i) == nil)))
|
|
200
|
+
return false
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
true
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def normalize(value)
|
|
207
|
+
if(value.nil? or value.to_s.match(TrueRegex).nil?)
|
|
208
|
+
false
|
|
209
|
+
else
|
|
210
|
+
true
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def is_true?(value)
|
|
215
|
+
return normalize(value)
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
def is_false?(value)
|
|
219
|
+
return !is_true?(value)
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
###
|
|
225
|
+
#
|
|
226
|
+
# Enum option.
|
|
227
|
+
#
|
|
228
|
+
###
|
|
229
|
+
class OptEnum < OptBase
|
|
230
|
+
|
|
231
|
+
def type
|
|
232
|
+
return 'enum'
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
def valid?(value=self.value)
|
|
236
|
+
return false if empty_required_value?(value)
|
|
237
|
+
|
|
238
|
+
(value and self.enums.include?(value.to_s))
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
def normalize(value=self.value)
|
|
242
|
+
return nil if not self.valid?(value)
|
|
243
|
+
return value.to_s
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
def desc=(value)
|
|
247
|
+
self.desc_string = value
|
|
248
|
+
|
|
249
|
+
self.desc
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
def desc
|
|
253
|
+
if self.enums
|
|
254
|
+
str = self.enums.join(', ')
|
|
255
|
+
end
|
|
256
|
+
"#{self.desc_string || ''} (accepted: #{str})"
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
protected
|
|
261
|
+
|
|
262
|
+
attr_accessor :desc_string # :nodoc:
|
|
263
|
+
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
###
|
|
267
|
+
#
|
|
268
|
+
# Network port option.
|
|
269
|
+
#
|
|
270
|
+
###
|
|
271
|
+
class OptPort < OptBase
|
|
272
|
+
def type
|
|
273
|
+
return 'port'
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
def valid?(value)
|
|
277
|
+
return false if empty_required_value?(value)
|
|
278
|
+
|
|
279
|
+
if ((value != nil and value.to_s.empty? == false) and
|
|
280
|
+
((value.to_s.match(/^\d+$/) == nil or value.to_i < 0 or value.to_i > 65535)))
|
|
281
|
+
return false
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
return super
|
|
285
|
+
end
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
###
|
|
289
|
+
#
|
|
290
|
+
# URL option.
|
|
291
|
+
#
|
|
292
|
+
###
|
|
293
|
+
class OptUrl < OptBase
|
|
294
|
+
def type
|
|
295
|
+
return 'url'
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
def valid?(value)
|
|
299
|
+
return false if empty_required_value?(value)
|
|
300
|
+
|
|
301
|
+
if (value != nil and value.empty? == false)
|
|
302
|
+
require 'uri'
|
|
303
|
+
require 'socket'
|
|
304
|
+
begin
|
|
305
|
+
::IPSocket.getaddress( URI( value ).host )
|
|
306
|
+
rescue
|
|
307
|
+
return false
|
|
308
|
+
end
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
return super
|
|
312
|
+
end
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
###
|
|
317
|
+
#
|
|
318
|
+
# Network address option.
|
|
319
|
+
#
|
|
320
|
+
###
|
|
321
|
+
class OptAddress < OptBase
|
|
322
|
+
def type
|
|
323
|
+
return 'address'
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
def valid?(value)
|
|
327
|
+
return false if empty_required_value?(value)
|
|
328
|
+
|
|
329
|
+
if (value != nil and value.empty? == false)
|
|
330
|
+
require 'socket'
|
|
331
|
+
begin
|
|
332
|
+
::IPSocket.getaddress( value )
|
|
333
|
+
rescue
|
|
334
|
+
return false
|
|
335
|
+
end
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
return super
|
|
339
|
+
end
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
###
|
|
344
|
+
#
|
|
345
|
+
# File system path option.
|
|
346
|
+
#
|
|
347
|
+
###
|
|
348
|
+
class OptPath < OptBase
|
|
349
|
+
def type
|
|
350
|
+
return 'path'
|
|
351
|
+
end
|
|
352
|
+
|
|
353
|
+
def valid?(value)
|
|
354
|
+
return false if empty_required_value?(value)
|
|
355
|
+
|
|
356
|
+
if ((value != nil and value.empty? == false) and
|
|
357
|
+
(File.exists?(value) == false))
|
|
358
|
+
return false
|
|
359
|
+
end
|
|
360
|
+
|
|
361
|
+
return super
|
|
362
|
+
end
|
|
363
|
+
end
|
|
364
|
+
|
|
365
|
+
###
|
|
366
|
+
#
|
|
367
|
+
# Integer option.
|
|
368
|
+
#
|
|
369
|
+
###
|
|
370
|
+
class OptInt < OptBase
|
|
371
|
+
def type
|
|
372
|
+
return 'integer'
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
def normalize(value)
|
|
376
|
+
if (value.to_s.match(/^0x[a-fA-F\d]+$/))
|
|
377
|
+
value.to_i(16)
|
|
378
|
+
else
|
|
379
|
+
value.to_i
|
|
380
|
+
end
|
|
381
|
+
end
|
|
382
|
+
|
|
383
|
+
def valid?(value)
|
|
384
|
+
return false if empty_required_value?(value)
|
|
385
|
+
|
|
386
|
+
if value and not normalize(value).to_s.match(/^\d+$/)
|
|
387
|
+
return false
|
|
388
|
+
end
|
|
389
|
+
|
|
390
|
+
return super
|
|
391
|
+
end
|
|
392
|
+
end
|
|
393
|
+
|
|
394
|
+
end
|
|
395
|
+
|