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
data/lib/parser.rb
ADDED
|
@@ -0,0 +1,522 @@
|
|
|
1
|
+
module Arachni
|
|
2
|
+
|
|
3
|
+
require Arachni::Options.instance.dir['lib'] + 'module/output'
|
|
4
|
+
require Arachni::Options.instance.dir['lib'] + 'module/utilities'
|
|
5
|
+
require Arachni::Options.instance.dir['lib'] + 'module/key_filler'
|
|
6
|
+
|
|
7
|
+
module Element
|
|
8
|
+
|
|
9
|
+
class Auditable
|
|
10
|
+
|
|
11
|
+
include Arachni::Module::Utilities
|
|
12
|
+
|
|
13
|
+
def self.reset
|
|
14
|
+
@@audited = Set.new
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
attr_accessor :altered
|
|
18
|
+
attr_reader :opts
|
|
19
|
+
|
|
20
|
+
#
|
|
21
|
+
# Holds constant bitfields that describe the preferred formatting
|
|
22
|
+
# of injection strings.
|
|
23
|
+
#
|
|
24
|
+
module Format
|
|
25
|
+
|
|
26
|
+
#
|
|
27
|
+
# Leaves the injection string as is.
|
|
28
|
+
#
|
|
29
|
+
STRAIGHT = 1 << 0
|
|
30
|
+
|
|
31
|
+
#
|
|
32
|
+
# Apends the injection string to the default value of the input vector.<br/>
|
|
33
|
+
# (If no default value exists Arachni will choose one.)
|
|
34
|
+
#
|
|
35
|
+
APPEND = 1 << 1
|
|
36
|
+
|
|
37
|
+
#
|
|
38
|
+
# Terminates the injection string with a null character.
|
|
39
|
+
#
|
|
40
|
+
NULL = 1 << 2
|
|
41
|
+
|
|
42
|
+
#
|
|
43
|
+
# Prefix the string with a ';', useful for command injection modules
|
|
44
|
+
#
|
|
45
|
+
SEMICOLON = 1 << 3
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def auditor( auditor )
|
|
49
|
+
@auditor = auditor
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
#
|
|
53
|
+
# Delegate output related methods to the auditor
|
|
54
|
+
#
|
|
55
|
+
|
|
56
|
+
def debug?
|
|
57
|
+
@auditor.debug? rescue false
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def print_error( str = '' )
|
|
61
|
+
@auditor.print_error( str )
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def print_status( str = '' )
|
|
65
|
+
@auditor.print_status( str )
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def print_debug( str = '' )
|
|
69
|
+
@auditor.print_debug( str )
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
#
|
|
74
|
+
# Callback invoked by {Arachni::Element::Auditable#audit} to submit
|
|
75
|
+
# the object via {Arachni::Module::HTTP}.
|
|
76
|
+
#
|
|
77
|
+
# Must be implemented by the extending class.
|
|
78
|
+
#
|
|
79
|
+
# @param [String] url
|
|
80
|
+
# @param [Hash] opts
|
|
81
|
+
#
|
|
82
|
+
# @see #submit
|
|
83
|
+
#
|
|
84
|
+
def http_request( url, opts )
|
|
85
|
+
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
#
|
|
89
|
+
# Submits self using {#http_request}.
|
|
90
|
+
#
|
|
91
|
+
# @param [Hash] opts
|
|
92
|
+
#
|
|
93
|
+
# @see #http_request
|
|
94
|
+
#
|
|
95
|
+
def submit( opts = {} )
|
|
96
|
+
|
|
97
|
+
opts = Arachni::Module::Auditor::OPTIONS.merge( opts )
|
|
98
|
+
opts[:params] = @auditable.dup
|
|
99
|
+
@opts = opts
|
|
100
|
+
|
|
101
|
+
return http_request( @action, opts )
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
#
|
|
105
|
+
# Audits self
|
|
106
|
+
#
|
|
107
|
+
# @param [String] injection_str the string to be injected
|
|
108
|
+
# @param [Hash] opts options as described in {Arachni::Module::Auditor#OPTIONS}
|
|
109
|
+
# @param [Block] &block block to be passed the:
|
|
110
|
+
# * HTTP response
|
|
111
|
+
# * name of the input vector
|
|
112
|
+
# * updated opts
|
|
113
|
+
# The block will be called as soon as the
|
|
114
|
+
# HTTP response is received.
|
|
115
|
+
#
|
|
116
|
+
def audit( injection_str, opts = { }, &block )
|
|
117
|
+
|
|
118
|
+
# respect user audit options
|
|
119
|
+
audit_opt = "@audit_#{self.type}s"
|
|
120
|
+
return if !Arachni::Options.instance.instance_variable_get( audit_opt )
|
|
121
|
+
|
|
122
|
+
@@audited ||= Set.new
|
|
123
|
+
|
|
124
|
+
opts = Arachni::Module::Auditor::OPTIONS.merge( opts )
|
|
125
|
+
opts[:element] = self.type
|
|
126
|
+
|
|
127
|
+
opts[:injected_orig] = injection_str
|
|
128
|
+
|
|
129
|
+
# if we don't have any auditable elements just return
|
|
130
|
+
return if auditable.empty?
|
|
131
|
+
|
|
132
|
+
audit_id = audit_id( injection_str, opts )
|
|
133
|
+
return if !opts[:redundant] && audited?( audit_id )
|
|
134
|
+
|
|
135
|
+
results = []
|
|
136
|
+
# iterate through all variation and audit each one
|
|
137
|
+
injection_sets( injection_str, opts ).each {
|
|
138
|
+
|elem|
|
|
139
|
+
|
|
140
|
+
opts[:altered] = elem.altered.dup
|
|
141
|
+
|
|
142
|
+
return if skip?( elem )
|
|
143
|
+
|
|
144
|
+
# inform the user about what we're auditing
|
|
145
|
+
print_status( get_status_str( opts[:altered] ) )
|
|
146
|
+
|
|
147
|
+
# submit the element with the injection values
|
|
148
|
+
req = elem.submit( opts )
|
|
149
|
+
return if !req
|
|
150
|
+
|
|
151
|
+
on_complete( req, elem, &block )
|
|
152
|
+
req.after_complete {
|
|
153
|
+
|result|
|
|
154
|
+
results << result.flatten[1] if result.flatten[1]
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
audited( audit_id )
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def skip?( elem )
|
|
162
|
+
return @auditor.skip?( elem )
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
#
|
|
166
|
+
# Injectes the injecton_str in self's values according to formatting options
|
|
167
|
+
# and returns an array of hashes in the form of:
|
|
168
|
+
# <altered_variable> => <new element>
|
|
169
|
+
#
|
|
170
|
+
# @param [String] injection_str the string to inject
|
|
171
|
+
#
|
|
172
|
+
# @return [Array]
|
|
173
|
+
#
|
|
174
|
+
def injection_sets( injection_str, opts = { } )
|
|
175
|
+
|
|
176
|
+
opts = Arachni::Module::Auditor::OPTIONS.merge( opts )
|
|
177
|
+
hash = auditable( ).dup
|
|
178
|
+
|
|
179
|
+
var_combo = []
|
|
180
|
+
if( !hash || hash.size == 0 ) then return [] end
|
|
181
|
+
|
|
182
|
+
if( self.is_a?( Arachni::Parser::Element::Form ) )
|
|
183
|
+
|
|
184
|
+
if !audited?( audit_id( Arachni::Parser::Element::Form::FORM_VALUES_ORIGINAL ) )
|
|
185
|
+
# this is the original hash, in case the default values
|
|
186
|
+
# are valid and present us with new attack vectors
|
|
187
|
+
elem = self.dup
|
|
188
|
+
elem.altered = Arachni::Parser::Element::Form::FORM_VALUES_ORIGINAL
|
|
189
|
+
var_combo << elem
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
if !audited?( audit_id( Arachni::Parser::Element::Form::FORM_VALUES_SAMPLE ) )
|
|
193
|
+
duphash = hash.dup
|
|
194
|
+
elem = self.dup
|
|
195
|
+
elem.auditable = Arachni::Module::KeyFiller.fill( duphash )
|
|
196
|
+
elem.altered = Arachni::Parser::Element::Form::FORM_VALUES_SAMPLE
|
|
197
|
+
var_combo << elem
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
chash = hash.dup
|
|
202
|
+
hash.keys.each {
|
|
203
|
+
|k|
|
|
204
|
+
|
|
205
|
+
# don't audit parameter flips
|
|
206
|
+
next if hash[k] == seed
|
|
207
|
+
|
|
208
|
+
chash = Arachni::Module::KeyFiller.fill( chash )
|
|
209
|
+
opts[:format].each {
|
|
210
|
+
|format|
|
|
211
|
+
|
|
212
|
+
str = format_str( injection_str, chash[k], format )
|
|
213
|
+
|
|
214
|
+
elem = self.dup
|
|
215
|
+
elem.altered = k.dup
|
|
216
|
+
elem.auditable = chash.merge( { k => str } )
|
|
217
|
+
var_combo << elem
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if opts[:param_flip]
|
|
223
|
+
elem = self.dup
|
|
224
|
+
elem.altered = 'Parameter flip'
|
|
225
|
+
elem.auditable[injection_str] = seed
|
|
226
|
+
var_combo << elem
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
print_debug_injection_set( var_combo, opts )
|
|
230
|
+
|
|
231
|
+
return var_combo
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
# impersonate the auditor to the output methods
|
|
236
|
+
def info
|
|
237
|
+
@auditor ? @auditor.class.info : { :name => '' }
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
#
|
|
241
|
+
# Returns a status string that explaining what's happening.
|
|
242
|
+
#
|
|
243
|
+
# The string contains the name of the input that is being audited
|
|
244
|
+
# the url and the type of the input (form, link, cookie...)
|
|
245
|
+
#
|
|
246
|
+
# @param [String] url the url under audit
|
|
247
|
+
# @param [Hash] input
|
|
248
|
+
# @param [Hash] opts
|
|
249
|
+
#
|
|
250
|
+
# @return [String]
|
|
251
|
+
#
|
|
252
|
+
def get_status_str( altered )
|
|
253
|
+
return "Auditing #{self.type} variable '" + altered + "' of " + @action
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
private
|
|
258
|
+
|
|
259
|
+
#
|
|
260
|
+
# Registers a block to be executed as soon as the Typhoeus request (reg)
|
|
261
|
+
# has been completed and a response has been received.
|
|
262
|
+
#
|
|
263
|
+
# If no &block has been provided {#get_matches} will be called instead.
|
|
264
|
+
#
|
|
265
|
+
# @param [Typhoeus::Request] req
|
|
266
|
+
# @param [Arachni::Element::Auditable] auditable element
|
|
267
|
+
# @param [Hash] opts an updated hash of options
|
|
268
|
+
# @param [Block] &block block to be passed the:
|
|
269
|
+
# * HTTP response
|
|
270
|
+
# * name of the input vector
|
|
271
|
+
# * updated opts
|
|
272
|
+
# The block will be called as soon as the
|
|
273
|
+
# HTTP response is received.
|
|
274
|
+
#
|
|
275
|
+
def on_complete( req, elem, &block )
|
|
276
|
+
|
|
277
|
+
elem.opts[:injected] = elem.auditable[elem.altered].to_s
|
|
278
|
+
elem.opts[:combo] = elem.auditable
|
|
279
|
+
elem.opts[:action] = elem.action
|
|
280
|
+
|
|
281
|
+
if( !elem.opts[:async] )
|
|
282
|
+
|
|
283
|
+
if( req && req.response )
|
|
284
|
+
block.call( req.response, elem.opts, elem )
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
return
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
req.on_complete {
|
|
291
|
+
|res|
|
|
292
|
+
|
|
293
|
+
# make sure that we have a response before continuing
|
|
294
|
+
if !res
|
|
295
|
+
print_error( 'Failed to get responses, backing out... ' )
|
|
296
|
+
next
|
|
297
|
+
else
|
|
298
|
+
print_status( 'Analyzing response #' + res.request.id.to_s + '...' )
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
# call the block, if there's one
|
|
302
|
+
if block_given?
|
|
303
|
+
block.call( res, elem.opts, elem )
|
|
304
|
+
next
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
next if !res.body
|
|
308
|
+
|
|
309
|
+
# get matches
|
|
310
|
+
get_matches( res.dup, elem.opts )
|
|
311
|
+
}
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
#
|
|
315
|
+
# Tries to identify an issue through regexp pattern matching.
|
|
316
|
+
#
|
|
317
|
+
# If a issue is found a message will be printed and a hash
|
|
318
|
+
# will be returned describing the conditions under which
|
|
319
|
+
# the issue was discovered.
|
|
320
|
+
#
|
|
321
|
+
# @param [Typhoeus::Response]
|
|
322
|
+
# @param [Hash] opts
|
|
323
|
+
#
|
|
324
|
+
# @return [Hash]
|
|
325
|
+
#
|
|
326
|
+
def get_matches( res, opts )
|
|
327
|
+
[opts[:regexp]].flatten.compact.each { |regexp| match_regexp_and_log( regexp, res, opts ) }
|
|
328
|
+
[opts[:substring]].flatten.compact.each { |substring| match_substring_and_log( substring, res, opts ) }
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
def match_substring_and_log( substring, res, opts )
|
|
332
|
+
|
|
333
|
+
verification = false
|
|
334
|
+
|
|
335
|
+
# an annoying encoding exception may be thrown by scan()
|
|
336
|
+
# the sob started occuring again....
|
|
337
|
+
begin
|
|
338
|
+
if( @auditor.page.html.substring?( substring ) )
|
|
339
|
+
verification = true
|
|
340
|
+
end
|
|
341
|
+
rescue
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
if res.body.substring?( substring )
|
|
345
|
+
opts[:regexp] = opts[:id] = opts[:match] = substring.clone
|
|
346
|
+
@auditor.log( opts, res )
|
|
347
|
+
end
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
def match_regexp_and_log( regexp, res, opts )
|
|
351
|
+
|
|
352
|
+
match_data = res.body.scan( regexp )[0]
|
|
353
|
+
match_data = match_data.to_s
|
|
354
|
+
|
|
355
|
+
verification = false
|
|
356
|
+
|
|
357
|
+
# an annoying encoding exception may be thrown by scan()
|
|
358
|
+
# the sob started occuring again....
|
|
359
|
+
begin
|
|
360
|
+
if( @auditor.page.html.scan( regexp )[0] )
|
|
361
|
+
opts[:verification] = true
|
|
362
|
+
end
|
|
363
|
+
rescue
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
# fairly obscure condition...pardon me...
|
|
367
|
+
if ( opts[:match] && match_data == opts[:match] ) ||
|
|
368
|
+
( !opts[:match] && match_data && match_data.size > 0 )
|
|
369
|
+
|
|
370
|
+
opts[:id] = opts[:match] = opts[:match] ? opts[:match] : match_data
|
|
371
|
+
opts[:regexp] = regexp
|
|
372
|
+
|
|
373
|
+
@auditor.log( opts, res )
|
|
374
|
+
end
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
#
|
|
378
|
+
# Returns am audit identifier string to be registered using {#audited}.
|
|
379
|
+
#
|
|
380
|
+
# @param [Hash] input
|
|
381
|
+
# @param [Hash] opts
|
|
382
|
+
#
|
|
383
|
+
# @return [String]
|
|
384
|
+
#
|
|
385
|
+
def audit_id( injection_str, opts = {} )
|
|
386
|
+
vars = auditable.keys.sort.to_s
|
|
387
|
+
|
|
388
|
+
timeout = opts[:timeout] || ''
|
|
389
|
+
return "#{@auditor.class.info[:name]}:" +
|
|
390
|
+
"#{@action}:" + "#{self.type}:" +
|
|
391
|
+
"#{vars}=#{injection_str.to_s}:timeout=#{timeout}"
|
|
392
|
+
end
|
|
393
|
+
|
|
394
|
+
#
|
|
395
|
+
# Checks whether or not an audit has been already performed.
|
|
396
|
+
#
|
|
397
|
+
# @param [String] audit_id a string returned by {#audit_id}
|
|
398
|
+
#
|
|
399
|
+
def audited?( audit_id )
|
|
400
|
+
ret = @@audited.include?( audit_id )
|
|
401
|
+
|
|
402
|
+
msg = 'Current audit ID: ' if !ret
|
|
403
|
+
msg = 'Skipping, already audited: ' if ret
|
|
404
|
+
print_debug( msg + audit_id )
|
|
405
|
+
|
|
406
|
+
return ret
|
|
407
|
+
end
|
|
408
|
+
|
|
409
|
+
#
|
|
410
|
+
# Registers an audit
|
|
411
|
+
#
|
|
412
|
+
# @param [String] audit_id a string returned by {#audit_id}
|
|
413
|
+
#
|
|
414
|
+
def audited( audit_id )
|
|
415
|
+
@@audited << audit_id
|
|
416
|
+
end
|
|
417
|
+
|
|
418
|
+
#
|
|
419
|
+
# Prepares an injection string following the specified formating options
|
|
420
|
+
# as contained in the format bitfield.
|
|
421
|
+
#
|
|
422
|
+
# @see Format
|
|
423
|
+
# @param [String] injection_str
|
|
424
|
+
# @param [String] default_str default value to be appended by the
|
|
425
|
+
# injection string if {Format::APPEND} is set in 'format'
|
|
426
|
+
# @param [Integer] format bitfield describing formating preferencies
|
|
427
|
+
#
|
|
428
|
+
# @return [String]
|
|
429
|
+
#
|
|
430
|
+
def format_str( injection_str, default_str, format )
|
|
431
|
+
|
|
432
|
+
semicolon = null = append = ''
|
|
433
|
+
|
|
434
|
+
null = "\0" if ( format & Format::NULL ) != 0
|
|
435
|
+
semicolon = ';' if ( format & Format::SEMICOLON ) != 0
|
|
436
|
+
append = default_str if ( format & Format::APPEND ) != 0
|
|
437
|
+
semicolon = append = null = '' if ( format & Format::STRAIGHT ) != 0
|
|
438
|
+
|
|
439
|
+
|
|
440
|
+
return semicolon + append + injection_str + null
|
|
441
|
+
end
|
|
442
|
+
|
|
443
|
+
def print_debug_injection_set( var_combo, opts )
|
|
444
|
+
return if !debug?
|
|
445
|
+
|
|
446
|
+
print_debug( )
|
|
447
|
+
print_debug_trainer( opts )
|
|
448
|
+
print_debug_formatting( opts )
|
|
449
|
+
print_debug_combos( var_combo )
|
|
450
|
+
end
|
|
451
|
+
|
|
452
|
+
def print_debug_formatting( opts )
|
|
453
|
+
print_debug( '------------' )
|
|
454
|
+
|
|
455
|
+
print_debug( 'Injection string format combinations set to:' )
|
|
456
|
+
print_debug( '|')
|
|
457
|
+
msg = []
|
|
458
|
+
opts[:format].each {
|
|
459
|
+
|format|
|
|
460
|
+
|
|
461
|
+
if( format & Format::NULL ) != 0
|
|
462
|
+
msg << 'null character termination (Format::NULL)'
|
|
463
|
+
end
|
|
464
|
+
|
|
465
|
+
if( format & Format::APPEND ) != 0
|
|
466
|
+
msg << 'append to default value (Format::APPEND)'
|
|
467
|
+
end
|
|
468
|
+
|
|
469
|
+
if( format & Format::STRAIGHT ) != 0
|
|
470
|
+
msg << 'straight, leave as is (Format::STRAIGHT)'
|
|
471
|
+
end
|
|
472
|
+
|
|
473
|
+
prep = msg.join( ' and ' ).capitalize + ". [Combo mask: #{format}]"
|
|
474
|
+
prep.gsub!( 'format::null', "Format::NULL [#{Format::NULL}]" )
|
|
475
|
+
prep.gsub!( 'format::append', "Format::APPEND [#{Format::APPEND}]" )
|
|
476
|
+
prep.gsub!( 'format::straight', "Format::STRAIGHT [#{Format::STRAIGHT}]" )
|
|
477
|
+
print_debug( "|----> " + prep )
|
|
478
|
+
|
|
479
|
+
msg.clear
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
end
|
|
483
|
+
|
|
484
|
+
def print_debug_combos( combos )
|
|
485
|
+
|
|
486
|
+
print_debug( )
|
|
487
|
+
print_debug( 'Prepared combinations:' )
|
|
488
|
+
print_debug('|' )
|
|
489
|
+
|
|
490
|
+
combos.each{
|
|
491
|
+
|elem|
|
|
492
|
+
|
|
493
|
+
altered = elem.altered
|
|
494
|
+
combo = elem.auditable
|
|
495
|
+
|
|
496
|
+
|
|
497
|
+
print_debug( '|' )
|
|
498
|
+
print_debug( "|--> Auditing: " + altered )
|
|
499
|
+
print_debug( "|--> Combo: " )
|
|
500
|
+
|
|
501
|
+
combo.each {
|
|
502
|
+
|combo|
|
|
503
|
+
print_debug( "|------> " + combo.to_s )
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
print_debug( )
|
|
509
|
+
print_debug( '------------' )
|
|
510
|
+
print_debug( )
|
|
511
|
+
|
|
512
|
+
end
|
|
513
|
+
|
|
514
|
+
def print_debug_trainer( opts )
|
|
515
|
+
print_debug( 'Trainer set to: ' + ( opts[:train] ? 'ON' : 'OFF' ) )
|
|
516
|
+
end
|
|
517
|
+
|
|
518
|
+
|
|
519
|
+
end
|
|
520
|
+
|
|
521
|
+
end
|
|
522
|
+
end
|