CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/lib/msf/core/auxiliary/web.rb
Views: 11784
1
# -*- coding: binary -*-
2
3
module Msf
4
###
5
#
6
# This module provides methods for brute forcing authentication
7
#
8
###
9
10
module Auxiliary::Web
11
module Analysis
12
end
13
14
include Auxiliary::Report
15
16
attr_reader :target
17
attr_reader :http
18
attr_reader :parent
19
attr_reader :page
20
21
def initialize(info = {})
22
super
23
end
24
25
# String id to push to the #checklist
26
def checked(id)
27
parent.checklist << "#{shortname}#{id}".hash
28
end
29
30
# String id to check against the #checklist
31
def checked?(id)
32
parent.checklist.include? "#{shortname}#{id}".hash
33
end
34
35
#
36
# Called directly before 'run'
37
#
38
def setup(opts = {})
39
@parent = opts[:parent]
40
@target = opts[:target]
41
@page = opts[:page]
42
@http = opts[:http]
43
end
44
45
# Should be overridden to return the exploits to use for this
46
# vulnerability type as an Array of Strings.
47
def self.exploits; end
48
49
# Must return a configuration Hash for the given exploit and vulnerability.
50
def self.configure_exploit(exploit, vuln); end
51
52
# Should be overridden to return the payloads used for this
53
# vulnerability type as an Array of Strings.
54
def payloads; end
55
56
def token
57
"xssmsfpro"
58
end
59
60
#
61
# Should be overridden to return a pattern to be matched against response
62
# bodies in order to identify a vulnerability.
63
#
64
# You can go one deeper and override #find_proof for more complex processing.
65
#
66
def signature; end
67
68
#
69
# Default #run, will audit all elements using taint analysis and log
70
# results based on #find_proof return values.
71
#
72
def run
73
auditable.each(&:taint_analysis)
74
end
75
76
# Returns an Array of elements prepared to be audited.
77
def auditable
78
target.auditable.map do |element|
79
element.fuzzer = self
80
element
81
end
82
end
83
84
# Checks whether a resource exists based on a path String.
85
def resource_exist?(path)
86
res = http.get(path)
87
res.code.to_i == 200 && !http.custom_404?(path, res.body)
88
end
89
alias file_exist? resource_exist?
90
91
# Checks whether a directory exists based on a path String.
92
def directory_exist?(path)
93
dir = path.dup
94
dir << '/' if !dir.end_with?('/')
95
resource_exist?(dir)
96
end
97
98
# Logs the existence of a resource in the path String.
99
def log_resource_if_exists(path)
100
log_resource(location: path) if resource_exist?(path)
101
end
102
alias log_file_if_exists log_resource_if_exists
103
104
# Logs the existence of the directory in the path String.
105
def log_directory_if_exists(path)
106
dir = path.dup
107
dir << '/' if !dir.end_with?('/')
108
log_resource_if_exists(dir)
109
end
110
111
# Matches fingerprint pattern against the current page's body and logs matches
112
def match_and_log_fingerprint(fingerprint, options = {})
113
return if (match = page.body.to_s.match(fingerprint).to_s).empty?
114
log_fingerprint(options.merge(fingerprint: match))
115
end
116
117
#
118
# Serves as a default detection method for when performing taint analysis.
119
#
120
# Uses the Regexp in #signature against the response body in order to
121
# identify vulnerabilities and return a String that proves it.
122
#
123
# Override it if you need more complex processing, but remember to return
124
# the proof as a String.
125
#
126
# response - Auxiliary::Web::HTTP::Response
127
# element - the submitted element
128
#
129
def find_proof(response, _element)
130
return if !signature
131
132
m = response.body.match(signature).to_s
133
return if !m || m.empty?
134
135
m.gsub(/[\r\n]/, ' ')
136
end
137
138
def increment_request_counter
139
parent.increment_request_counter
140
end
141
142
# Should be overridden and return an Integer (0-100) denoting the confidence
143
# in the accuracy of the logged vuln.
144
def calculate_confidence(_vuln)
145
100
146
end
147
148
def log_fingerprint(opts = {})
149
mode = name
150
vhash = [target.to_url, opts[:fingerprint], mode, opts[:location]]
151
.map(&:to_s).join('|').hash
152
153
parent.vulns[mode] ||= {}
154
return if parent.vulns[mode].include?(vhash)
155
156
location = opts[:location] ?
157
page.url.merge(URI(opts[:location].to_s)) : page.url
158
159
info = {
160
web_site: target.site,
161
path: location.path,
162
query: location.query,
163
method: 'GET',
164
params: [],
165
pname: 'path',
166
proof: opts[:fingerprint],
167
risk: details[:risk],
168
name: details[:name],
169
blame: details[:blame],
170
category: details[:category],
171
description: details[:description],
172
owner: self
173
}
174
175
info[:confidence] = calculate_confidence(info)
176
parent.vulns[mode][vhash] = info
177
178
report_web_vuln(info)
179
180
opts[:print_fingerprint] = true if !opts.include?(:print_fingerprint)
181
182
print_good " FOUND(#{mode}) URL(#{location})"
183
print_good " PROOF(#{opts[:fingerprint]})" if opts[:print_fingerprint]
184
end
185
186
def log_resource(opts = {})
187
mode = name
188
vhash = [target.to_url, mode, opts[:location]]
189
.map(&:to_s).join('|').hash
190
191
parent.vulns[mode] ||= {}
192
return if parent.vulns[mode].include?(vhash)
193
194
location = URI(opts[:location].to_s)
195
info = {
196
web_site: target.site,
197
path: location.path,
198
query: location.query,
199
method: 'GET',
200
params: [],
201
pname: 'path',
202
proof: opts[:location],
203
risk: details[:risk],
204
name: details[:name],
205
blame: details[:blame],
206
category: details[:category],
207
description: details[:description],
208
owner: self
209
}
210
211
info[:confidence] = calculate_confidence(info)
212
parent.vulns[mode][vhash] = info
213
214
report_web_vuln(info)
215
216
print_good " VULNERABLE(#{mode}) URL(#{target.to_url})"
217
print_good " PROOF(#{opts[:location]})"
218
end
219
220
def process_vulnerability(element, proof, opts = {})
221
mode = name
222
vhash = [target.to_url, mode, element.altered]
223
.map(&:to_s).join('|').hash
224
225
parent.vulns[mode] ||= {}
226
return parent.vulns[mode][vhash] if parent.vulns[mode][vhash]
227
228
parent.vulns[mode][vhash] = {
229
target: target,
230
method: element.method.to_s.upcase,
231
params: element.params.to_a,
232
mode: mode,
233
pname: element.altered,
234
proof: proof.to_s,
235
form: element.model,
236
risk: details[:risk],
237
name: details[:name],
238
blame: details[:blame],
239
category: details[:category],
240
description: details[:description]
241
}
242
243
confidence = calculate_confidence(parent.vulns[mode][vhash])
244
245
parent.vulns[mode][vhash][:confidence] = confidence
246
247
if !(payload = opts[:payload])
248
if payloads
249
payload = payloads.select do |p|
250
element.altered_value.include?(p)
251
end.max_by(&:size)
252
end
253
end
254
255
uri = URI(element.action)
256
info = {
257
web_site: element.model.web_site,
258
path: uri.path,
259
query: uri.query,
260
method: element.method.to_s.upcase,
261
params: element.params.to_a,
262
pname: element.altered,
263
proof: proof.to_s,
264
risk: details[:risk],
265
name: details[:name],
266
blame: details[:blame],
267
category: details[:category],
268
description: details[:description],
269
confidence: confidence,
270
payload: payload,
271
owner: self
272
}
273
274
report_web_vuln(info)
275
276
print_good " VULNERABLE(#{mode}) URL(#{target.to_url})" \
277
" PARAMETER(#{element.altered}) VALUES(#{element.params})"
278
print_good " PROOF(#{proof})"
279
end
280
end
281
end
282
283