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/rex/post/meterpreter/extensions/stdapi/sys/registry.rb
Views: 11793
1
# -*- coding: binary -*-
2
3
require 'rex/post/process'
4
require 'rex/post/meterpreter/packet'
5
require 'rex/post/meterpreter/client'
6
require 'rex/post/meterpreter/extensions/stdapi/constants'
7
require 'rex/post/meterpreter/extensions/stdapi/stdapi'
8
require 'rex/post/meterpreter/extensions/stdapi/sys/registry_subsystem/registry_key'
9
require 'rex/post/meterpreter/extensions/stdapi/sys/registry_subsystem/registry_value'
10
require 'rex/post/meterpreter/extensions/stdapi/sys/registry_subsystem/remote_registry_key'
11
12
module Rex
13
module Post
14
module Meterpreter
15
module Extensions
16
module Stdapi
17
module Sys
18
19
###
20
#
21
# This class provides access to the Windows registry on the remote
22
# machine.
23
#
24
###
25
class Registry
26
27
class << self
28
attr_accessor :client
29
end
30
31
##
32
#
33
# Registry key interaction
34
#
35
##
36
37
#
38
# Opens the supplied registry key relative to the root key with
39
# the supplied permissions. Right now this is merely a wrapper around
40
# create_key.
41
#
42
43
def Registry.load_key(root_key,base_key,hive_file)
44
request = Packet.create_request(COMMAND_ID_STDAPI_REGISTRY_LOAD_KEY)
45
request.add_tlv(TLV_TYPE_ROOT_KEY, root_key)
46
request.add_tlv(TLV_TYPE_BASE_KEY, base_key)
47
request.add_tlv(TLV_TYPE_FILE_PATH, client.unicode_filter_decode( hive_file ))
48
49
response = client.send_request(request)
50
return response.get_tlv(TLV_TYPE_RESULT).value
51
end
52
53
def Registry.unload_key(root_key,base_key)
54
request = Packet.create_request(COMMAND_ID_STDAPI_REGISTRY_UNLOAD_KEY)
55
request.add_tlv(TLV_TYPE_ROOT_KEY, root_key)
56
request.add_tlv(TLV_TYPE_BASE_KEY, base_key)
57
response = client.send_request(request)
58
return response.get_tlv(TLV_TYPE_RESULT).value
59
end
60
61
62
def Registry.open_key(root_key, base_key, perm = KEY_READ)
63
# If no base key was provided, just return the root_key.
64
if (base_key == nil or base_key.length == 0)
65
return RegistrySubsystem::RegistryKey.new(client, root_key, base_key, perm, root_key)
66
end
67
68
request = Packet.create_request(COMMAND_ID_STDAPI_REGISTRY_OPEN_KEY)
69
70
request.add_tlv(TLV_TYPE_ROOT_KEY, root_key)
71
request.add_tlv(TLV_TYPE_BASE_KEY, base_key)
72
request.add_tlv(TLV_TYPE_PERMISSION, perm)
73
74
response = client.send_request(request)
75
76
return Rex::Post::Meterpreter::Extensions::Stdapi::Sys::RegistrySubsystem::RegistryKey.new(
77
client, root_key, base_key, perm, response.get_tlv(TLV_TYPE_HKEY).value)
78
end
79
80
# Checks if a key exists on the target registry
81
#
82
# @param root_key [String] the root part of the key path. Ex: HKEY_LOCAL_MACHINE
83
# @param base_key [String] the base part of the key path
84
# @return [Boolean] true if the key exists on the target registry, false otherwise, even
85
# it the session hasn't permissions to access the target key.
86
# @raise [TimeoutError] if the timeout expires when waiting the answer
87
# @raise [Rex::Post::Meterpreter::RequestError] if the parameters are not valid
88
def Registry.check_key_exists(root_key, base_key)
89
request = Packet.create_request(COMMAND_ID_STDAPI_REGISTRY_CHECK_KEY_EXISTS)
90
request.add_tlv(TLV_TYPE_ROOT_KEY, root_key)
91
request.add_tlv(TLV_TYPE_BASE_KEY, base_key)
92
response = client.send_request(request)
93
return response.get_tlv(TLV_TYPE_BOOL).value
94
end
95
96
#
97
# Opens the supplied registry key on the specified remote host. Requires that the
98
# current process has credentials to access the target and that the target has the
99
# remote registry service running.
100
#
101
def Registry.open_remote_key(target_host, root_key)
102
103
request = Packet.create_request(COMMAND_ID_STDAPI_REGISTRY_OPEN_REMOTE_KEY)
104
105
request.add_tlv(TLV_TYPE_TARGET_HOST, target_host)
106
request.add_tlv(TLV_TYPE_ROOT_KEY, root_key)
107
108
response = client.send_request(request)
109
110
return Rex::Post::Meterpreter::Extensions::Stdapi::Sys::RegistrySubsystem::RemoteRegistryKey.new(
111
client, target_host, root_key, response.get_tlv(TLV_TYPE_HKEY).value)
112
end
113
114
#
115
# Creates the supplied registry key or opens it if it already exists.
116
#
117
def Registry.create_key(root_key, base_key, perm = KEY_READ)
118
request = Packet.create_request(COMMAND_ID_STDAPI_REGISTRY_CREATE_KEY)
119
120
request.add_tlv(TLV_TYPE_ROOT_KEY, root_key)
121
request.add_tlv(TLV_TYPE_BASE_KEY, base_key)
122
request.add_tlv(TLV_TYPE_PERMISSION, perm)
123
124
response = client.send_request(request)
125
126
return Rex::Post::Meterpreter::Extensions::Stdapi::Sys::RegistrySubsystem::RegistryKey.new(
127
client, root_key, base_key, perm, response.get_tlv(TLV_TYPE_HKEY).value)
128
end
129
130
#
131
# Deletes the supplied registry key.
132
#
133
def Registry.delete_key(root_key, base_key, recursive = true)
134
request = Packet.create_request(COMMAND_ID_STDAPI_REGISTRY_DELETE_KEY)
135
flags = 0
136
137
if (recursive)
138
flags |= DELETE_KEY_FLAG_RECURSIVE
139
end
140
141
request.add_tlv(TLV_TYPE_ROOT_KEY, root_key)
142
request.add_tlv(TLV_TYPE_BASE_KEY, base_key)
143
request.add_tlv(TLV_TYPE_FLAGS, flags)
144
145
if (client.send_request(request) != nil)
146
return true
147
end
148
149
return false
150
end
151
152
#
153
# Closes the supplied registry key.
154
#
155
def Registry.close_key(hkey)
156
request = Packet.create_request(COMMAND_ID_STDAPI_REGISTRY_CLOSE_KEY)
157
158
request.add_tlv(TLV_TYPE_HKEY, hkey)
159
160
client.send_packet(request)
161
162
return true
163
end
164
165
#
166
# Enumerates the supplied registry key returning an array of key names.
167
#
168
def Registry.enum_key(hkey)
169
keys = []
170
request = Packet.create_request(COMMAND_ID_STDAPI_REGISTRY_ENUM_KEY)
171
172
request.add_tlv(TLV_TYPE_HKEY, hkey)
173
174
response = client.send_request(request)
175
176
# Enumerate through all of the registry keys
177
response.each(TLV_TYPE_KEY_NAME) { |key_name|
178
keys << key_name.value
179
}
180
181
return keys
182
end
183
184
def Registry.enum_key_direct(root_key, base_key, perm = KEY_READ)
185
request = Packet.create_request(COMMAND_ID_STDAPI_REGISTRY_ENUM_KEY_DIRECT)
186
keys = []
187
188
request.add_tlv(TLV_TYPE_ROOT_KEY, root_key)
189
request.add_tlv(TLV_TYPE_BASE_KEY, base_key)
190
request.add_tlv(TLV_TYPE_PERMISSION, perm)
191
192
response = client.send_request(request)
193
194
# Enumerate through all of the registry keys
195
response.each(TLV_TYPE_KEY_NAME) do |key_name|
196
keys << key_name.value
197
end
198
199
keys
200
end
201
202
##
203
#
204
# Registry value interaction
205
#
206
##
207
208
#
209
# Sets the registry value relative to the supplied hkey.
210
#
211
def Registry.set_value(hkey, name, type, data)
212
request = Packet.create_request(COMMAND_ID_STDAPI_REGISTRY_SET_VALUE)
213
214
request.add_tlv(TLV_TYPE_HKEY, hkey)
215
request.add_tlv(TLV_TYPE_VALUE_NAME, name)
216
request.add_tlv(TLV_TYPE_VALUE_TYPE, type)
217
request.add_tlv(TLV_TYPE_VALUE_DATA, self.ruby2reg_value(type, data))
218
219
client.send_request(request)
220
221
return true
222
end
223
224
def Registry.set_value_direct(root_key, base_key, name, type, data, perm = KEY_WRITE)
225
request = Packet.create_request(COMMAND_ID_STDAPI_REGISTRY_SET_VALUE_DIRECT)
226
227
request.add_tlv(TLV_TYPE_ROOT_KEY, root_key)
228
request.add_tlv(TLV_TYPE_BASE_KEY, base_key)
229
request.add_tlv(TLV_TYPE_PERMISSION, perm)
230
request.add_tlv(TLV_TYPE_VALUE_NAME, name)
231
request.add_tlv(TLV_TYPE_VALUE_TYPE, type)
232
request.add_tlv(TLV_TYPE_VALUE_DATA, self.ruby2reg_value(type, data))
233
234
client.send_request(request)
235
236
true
237
end
238
239
#
240
# Queries the registry value supplied in name and returns an
241
# initialized RegistryValue instance if a match is found.
242
#
243
def Registry.query_value_direct(root_key, base_key, name, perm = KEY_READ)
244
request = Packet.create_request(COMMAND_ID_STDAPI_REGISTRY_QUERY_VALUE_DIRECT)
245
246
request.add_tlv(TLV_TYPE_ROOT_KEY, root_key)
247
request.add_tlv(TLV_TYPE_BASE_KEY, base_key)
248
request.add_tlv(TLV_TYPE_PERMISSION, perm)
249
request.add_tlv(TLV_TYPE_VALUE_NAME, name)
250
251
response = client.send_request(request)
252
253
type = response.get_tlv(TLV_TYPE_VALUE_TYPE).value
254
data = self.reg2ruby_value(type, response.get_tlv(TLV_TYPE_VALUE_DATA).value)
255
256
Rex::Post::Meterpreter::Extensions::Stdapi::Sys::RegistrySubsystem::RegistryValue.new(
257
client, 0, name, type, data)
258
end
259
260
def Registry.query_value(hkey, name)
261
request = Packet.create_request(COMMAND_ID_STDAPI_REGISTRY_QUERY_VALUE)
262
263
request.add_tlv(TLV_TYPE_HKEY, hkey)
264
request.add_tlv(TLV_TYPE_VALUE_NAME, name)
265
266
response = client.send_request(request)
267
268
type = response.get_tlv(TLV_TYPE_VALUE_TYPE).value
269
data = self.reg2ruby_value(type, response.get_tlv(TLV_TYPE_VALUE_DATA).value)
270
271
272
return Rex::Post::Meterpreter::Extensions::Stdapi::Sys::RegistrySubsystem::RegistryValue.new(
273
client, hkey, name, type, data)
274
end
275
276
#
277
# Deletes the registry value supplied in name from the supplied
278
# registry key.
279
#
280
def Registry.delete_value(hkey, name)
281
request = Packet.create_request(COMMAND_ID_STDAPI_REGISTRY_DELETE_VALUE)
282
283
request.add_tlv(TLV_TYPE_HKEY, hkey)
284
request.add_tlv(TLV_TYPE_VALUE_NAME, name)
285
286
if (client.send_request(request) != nil)
287
return true
288
end
289
290
return false
291
end
292
293
#
294
# Queries the registry class name and returns a string
295
#
296
def Registry.query_class(hkey)
297
request = Packet.create_request(COMMAND_ID_STDAPI_REGISTRY_QUERY_CLASS)
298
299
request.add_tlv(TLV_TYPE_HKEY, hkey)
300
301
response = client.send_request(request)
302
cls = response.get_tlv(TLV_TYPE_VALUE_DATA)
303
return nil if not cls
304
data = cls.value.gsub(/\x00.*/n, '')
305
return data
306
end
307
308
#
309
# Enumerates all of the values at the supplied hkey including their
310
# names. An array of RegistryValue's is returned.
311
#
312
def Registry.enum_value(hkey)
313
request = Packet.create_request(COMMAND_ID_STDAPI_REGISTRY_ENUM_VALUE)
314
values = []
315
316
request.add_tlv(TLV_TYPE_HKEY, hkey)
317
318
response = client.send_request(request)
319
320
response.each(TLV_TYPE_VALUE_NAME) { |value_name|
321
values << Rex::Post::Meterpreter::Extensions::Stdapi::Sys::RegistrySubsystem::RegistryValue.new(
322
client, hkey, value_name.value)
323
}
324
325
return values
326
end
327
328
def Registry.enum_value_direct(root_key, base_key, perm = KEY_READ)
329
request = Packet.create_request(COMMAND_ID_STDAPI_REGISTRY_ENUM_VALUE_DIRECT)
330
values = []
331
332
request.add_tlv(TLV_TYPE_ROOT_KEY, root_key)
333
request.add_tlv(TLV_TYPE_BASE_KEY, base_key)
334
request.add_tlv(TLV_TYPE_PERMISSION, perm)
335
336
response = client.send_request(request)
337
338
response.each(TLV_TYPE_VALUE_NAME) do |value_name|
339
values << Rex::Post::Meterpreter::Extensions::Stdapi::Sys::RegistrySubsystem::RegistryValue.new(
340
client, 0, value_name.value)
341
end
342
343
values
344
end
345
346
#
347
# Return the key value associated with the supplied string. This is useful
348
# for converting HKLM as a string into its actual integer representation.
349
#
350
def self.key2str(key)
351
if (key == 'HKLM' or key == 'HKEY_LOCAL_MACHINE')
352
return HKEY_LOCAL_MACHINE
353
elsif (key == 'HKCU' or key == 'HKEY_CURRENT_USER')
354
return HKEY_CURRENT_USER
355
elsif (key == 'HKU' or key == 'HKEY_USERS')
356
return HKEY_USERS
357
elsif (key == 'HKCR' or key == 'HKEY_CLASSES_ROOT')
358
return HKEY_CLASSES_ROOT
359
elsif (key == 'HKEY_CURRENT_CONFIG')
360
return HKEY_CURRENT_CONFIG
361
elsif (key == 'HKEY_PERFORMANCE_DATA')
362
return HKEY_PERFORMANCE_DATA
363
elsif (key == 'HKEY_DYN_DATA')
364
return HKEY_DYN_DATA
365
else
366
raise ArgumentError, "Unknown key: #{key}"
367
end
368
end
369
370
#
371
# Returns the integer value associated with the supplied registry value
372
# type (like REG_SZ).
373
#
374
# @see https://msdn.microsoft.com/en-us/library/windows/desktop/ms724884(v=vs.85).aspx
375
# @param type [String] A Windows registry type constant name, e.g. 'REG_SZ'
376
# @return [Integer] one of the `REG_*` constants
377
def self.type2str(type)
378
case type
379
when 'REG_BINARY' then REG_BINARY
380
when 'REG_DWORD' then REG_DWORD
381
when 'REG_EXPAND_SZ' then REG_EXPAND_SZ
382
when 'REG_MULTI_SZ' then REG_MULTI_SZ
383
when 'REG_NONE' then REG_NONE
384
when 'REG_QWORD' then REG_QWORD
385
when 'REG_SZ' then REG_SZ
386
else
387
nil
388
end
389
end
390
391
#
392
# Split the supplied full registry key into its root key and base key. For
393
# instance, passing HKLM\Software\Dog will return [ HKEY_LOCAL_MACHINE,
394
# 'Software\Dog' ]
395
#
396
def self.splitkey(str)
397
if (str =~ /^(.+?)[\\]{1,}(.*)$/)
398
[ key2str($1), $2 ]
399
else
400
[ key2str(str), nil ]
401
end
402
end
403
404
class << self
405
private
406
407
def ruby2reg_value(type, value)
408
case type
409
when REG_DWORD
410
value = [value.to_i].pack('L<')
411
when REG_EXPAND_SZ
412
value += "\x00".b
413
when REG_MULTI_SZ
414
value = value.join("\x00".b) + "\x00\x00".b
415
when REG_QWORD
416
value = [value.to_i].pack('Q<')
417
when REG_SZ
418
value += "\x00".b
419
end
420
421
value
422
end
423
424
def reg2ruby_value(type, value)
425
case type
426
when REG_DWORD
427
value = value.unpack1('L>')
428
when REG_EXPAND_SZ
429
value = value[0..-2]
430
when REG_MULTI_SZ
431
value = value[0..-3].split("\x00".b)
432
when REG_QWORD
433
value = value.unpack1('Q<')
434
when REG_SZ
435
value = value[0..-2]
436
end
437
438
value
439
end
440
end
441
442
end
443
444
end; end; end; end; end; end
445
446
447