ruby_smb 3.3.6 → 3.3.8
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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/README.md +14 -0
- data/examples/registry_key_security_descriptor.rb +109 -0
- data/lib/ruby_smb/client/winreg.rb +12 -0
- data/lib/ruby_smb/dcerpc/error.rb +3 -0
- data/lib/ruby_smb/dcerpc/lsarpc/lsar_close_handle_request.rb +22 -0
- data/lib/ruby_smb/dcerpc/lsarpc/lsar_close_handle_response.rb +23 -0
- data/lib/ruby_smb/dcerpc/lsarpc/lsar_lookup_sids_request.rb +26 -0
- data/lib/ruby_smb/dcerpc/lsarpc/lsar_lookup_sids_response.rb +25 -0
- data/lib/ruby_smb/dcerpc/lsarpc/lsar_open_policy2_request.rb +24 -0
- data/lib/ruby_smb/dcerpc/lsarpc/lsar_open_policy2_response.rb +23 -0
- data/lib/ruby_smb/dcerpc/lsarpc/lsar_open_policy_request.rb +24 -0
- data/lib/ruby_smb/dcerpc/lsarpc/lsar_open_policy_response.rb +23 -0
- data/lib/ruby_smb/dcerpc/lsarpc/lsar_query_information_policy2_request.rb +23 -0
- data/lib/ruby_smb/dcerpc/lsarpc/lsar_query_information_policy2_response.rb +23 -0
- data/lib/ruby_smb/dcerpc/lsarpc/lsar_query_information_policy_request.rb +23 -0
- data/lib/ruby_smb/dcerpc/lsarpc/lsar_query_information_policy_response.rb +23 -0
- data/lib/ruby_smb/dcerpc/lsarpc.rb +634 -2
- data/lib/ruby_smb/dcerpc/ndr.rb +10 -4
- data/lib/ruby_smb/dcerpc/request.rb +26 -16
- data/lib/ruby_smb/dcerpc/rrp_rpc_unicode_string.rb +1 -1
- data/lib/ruby_smb/dcerpc/samr/rpc_sid.rb +1 -1
- data/lib/ruby_smb/dcerpc/winreg/get_key_security_request.rb +26 -0
- data/lib/ruby_smb/dcerpc/winreg/get_key_security_response.rb +26 -0
- data/lib/ruby_smb/dcerpc/winreg/query_value_response.rb +2 -0
- data/lib/ruby_smb/dcerpc/winreg/set_key_security_request.rb +26 -0
- data/lib/ruby_smb/dcerpc/winreg/set_key_security_response.rb +25 -0
- data/lib/ruby_smb/dcerpc/winreg.rb +121 -9
- data/lib/ruby_smb/field/security_descriptor.rb +17 -0
- data/lib/ruby_smb/version.rb +1 -1
- data/spec/lib/ruby_smb/dcerpc/lsarpc/lsar_close_handle_request_spec.rb +40 -0
- data/spec/lib/ruby_smb/dcerpc/lsarpc/lsar_close_handle_response_spec.rb +46 -0
- data/spec/lib/ruby_smb/dcerpc/lsarpc/lsar_lookup_sids_request_spec.rb +69 -0
- data/spec/lib/ruby_smb/dcerpc/lsarpc/lsar_lookup_sids_response_spec.rb +56 -0
- data/spec/lib/ruby_smb/dcerpc/lsarpc/lsar_open_policy2_request_spec.rb +68 -0
- data/spec/lib/ruby_smb/dcerpc/lsarpc/lsar_open_policy2_response_spec.rb +46 -0
- data/spec/lib/ruby_smb/dcerpc/lsarpc/lsar_open_policy_request_spec.rb +68 -0
- data/spec/lib/ruby_smb/dcerpc/lsarpc/lsar_open_policy_response_spec.rb +45 -0
- data/spec/lib/ruby_smb/dcerpc/lsarpc/lsar_query_information_policy2_request_spec.rb +47 -0
- data/spec/lib/ruby_smb/dcerpc/lsarpc/lsar_query_information_policy2_response_spec.rb +54 -0
- data/spec/lib/ruby_smb/dcerpc/lsarpc/lsar_query_information_policy_request_spec.rb +46 -0
- data/spec/lib/ruby_smb/dcerpc/lsarpc/lsar_query_information_policy_response_spec.rb +53 -0
- data/spec/lib/ruby_smb/dcerpc/ndr_spec.rb +80 -0
- data/spec/lib/ruby_smb/dcerpc/winreg_spec.rb +267 -18
- data.tar.gz.sig +0 -0
- metadata +44 -3
- metadata.gz.sig +0 -0
@@ -18,22 +18,24 @@ module RubySMB
|
|
18
18
|
choice :stub, label: 'Stub', selection: -> { @obj.parent.get_parameter(:endpoint) || '' } do
|
19
19
|
string 'Encrypted'
|
20
20
|
choice 'Winreg', selection: -> { opnum } do
|
21
|
-
open_root_key_request
|
22
|
-
open_root_key_request
|
23
|
-
open_root_key_request
|
24
|
-
open_root_key_request
|
25
|
-
open_root_key_request
|
26
|
-
open_root_key_request
|
27
|
-
open_root_key_request
|
28
|
-
open_root_key_request
|
29
|
-
close_key_request
|
30
|
-
enum_key_request
|
31
|
-
enum_value_request
|
32
|
-
open_key_request
|
33
|
-
query_info_key_request
|
34
|
-
query_value_request
|
35
|
-
create_key_request
|
36
|
-
save_key_request
|
21
|
+
open_root_key_request Winreg::OPEN_HKCR, opnum: Winreg::OPEN_HKCR
|
22
|
+
open_root_key_request Winreg::OPEN_HKCU, opnum: Winreg::OPEN_HKCU
|
23
|
+
open_root_key_request Winreg::OPEN_HKLM, opnum: Winreg::OPEN_HKLM
|
24
|
+
open_root_key_request Winreg::OPEN_HKPD, opnum: Winreg::OPEN_HKPD
|
25
|
+
open_root_key_request Winreg::OPEN_HKU, opnum: Winreg::OPEN_HKU
|
26
|
+
open_root_key_request Winreg::OPEN_HKCC, opnum: Winreg::OPEN_HKCC
|
27
|
+
open_root_key_request Winreg::OPEN_HKPT, opnum: Winreg::OPEN_HKPT
|
28
|
+
open_root_key_request Winreg::OPEN_HKPN, opnum: Winreg::OPEN_HKPN
|
29
|
+
close_key_request Winreg::REG_CLOSE_KEY
|
30
|
+
enum_key_request Winreg::REG_ENUM_KEY
|
31
|
+
enum_value_request Winreg::REG_ENUM_VALUE
|
32
|
+
open_key_request Winreg::REG_OPEN_KEY
|
33
|
+
query_info_key_request Winreg::REG_QUERY_INFO_KEY
|
34
|
+
query_value_request Winreg::REG_QUERY_VALUE
|
35
|
+
create_key_request Winreg::REG_CREATE_KEY
|
36
|
+
save_key_request Winreg::REG_SAVE_KEY
|
37
|
+
get_key_security_request Winreg::REG_GET_KEY_SECURITY
|
38
|
+
set_key_security_request Winreg::REG_SET_KEY_SECURITY
|
37
39
|
string :default
|
38
40
|
end
|
39
41
|
choice 'Netlogon', selection: -> { opnum } do
|
@@ -109,6 +111,14 @@ module RubySMB
|
|
109
111
|
efs_rpc_query_recovery_agents_request Efsrpc::EFS_RPC_QUERY_RECOVERY_AGENTS
|
110
112
|
efs_rpc_query_users_on_file_request Efsrpc::EFS_RPC_QUERY_USERS_ON_FILE
|
111
113
|
end
|
114
|
+
choice 'Lsarpc', selection: -> { opnum } do
|
115
|
+
lsar_open_policy_request Lsarpc::LSAR_OPEN_POLICY
|
116
|
+
lsar_open_policy2_request Lsarpc::LSAR_OPEN_POLICY2
|
117
|
+
lsar_query_information_policy_request Lsarpc::LSAR_QUERY_INFORMATION_POLICY
|
118
|
+
lsar_query_information_policy2_request Lsarpc::LSAR_QUERY_INFORMATION_POLICY2
|
119
|
+
lsar_close_handle_request Lsarpc::LSAR_CLOSE_HANDLE
|
120
|
+
lsar_lookup_sids_request Lsarpc::LSAR_LOOKUP_SIDS
|
121
|
+
end
|
112
122
|
string :default
|
113
123
|
end
|
114
124
|
|
@@ -20,7 +20,7 @@ module RubySMB
|
|
20
20
|
when BinData::Stringz, BinData::String, String
|
21
21
|
self.buffer = val.to_s
|
22
22
|
val_length = val.strip.length
|
23
|
-
val_length += 1
|
23
|
+
val_length += 1
|
24
24
|
self.buffer_length = val_length * 2
|
25
25
|
self.maximum_length = val_length * 2
|
26
26
|
else
|
@@ -107,7 +107,7 @@ module RubySMB
|
|
107
107
|
case val
|
108
108
|
when String
|
109
109
|
elems = val.split('-')
|
110
|
-
raise ArgumentError, "Wrong SID format" unless elems[0].downcase == 's'
|
110
|
+
raise ArgumentError, "Wrong SID format for #{val.inspect}" unless elems[0].downcase == 's'
|
111
111
|
self.revision = elems[1].to_i
|
112
112
|
self.sub_authority_count = elems[3..-1].size
|
113
113
|
self.identifier_authority = [0, 0, 0, 0, 0, elems[2].to_i]
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module RubySMB
|
2
|
+
module Dcerpc
|
3
|
+
module Winreg
|
4
|
+
|
5
|
+
# This class represents a GetKeySecurity Request Packet as defined in
|
6
|
+
# [3.1.5.13 BaseRegGetKeySecurity (Opnum 12)](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rrp/b0e1868c-f4fd-4b43-959f-c0f0cac3ee26)
|
7
|
+
class GetKeySecurityRequest < BinData::Record
|
8
|
+
attr_reader :opnum
|
9
|
+
|
10
|
+
endian :little
|
11
|
+
|
12
|
+
rpc_hkey :hkey
|
13
|
+
uint32 :security_information
|
14
|
+
rpc_security_descriptor :prpc_security_descriptor_in
|
15
|
+
|
16
|
+
def initialize_instance
|
17
|
+
super
|
18
|
+
@opnum = REG_GET_KEY_SECURITY
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module RubySMB
|
2
|
+
module Dcerpc
|
3
|
+
module Winreg
|
4
|
+
|
5
|
+
# This class represents a GetKeySecurity Response Packet as defined in
|
6
|
+
# [3.1.5.13 BaseRegGetKeySecurity (Opnum 12)](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rrp/b0e1868c-f4fd-4b43-959f-c0f0cac3ee26)
|
7
|
+
class GetKeySecurityResponse < BinData::Record
|
8
|
+
attr_reader :opnum
|
9
|
+
|
10
|
+
endian :little
|
11
|
+
|
12
|
+
rpc_security_descriptor :prpc_security_descriptor_out
|
13
|
+
ndr_uint32 :error_status
|
14
|
+
|
15
|
+
def initialize_instance
|
16
|
+
super
|
17
|
+
@opnum = REG_GET_KEY_SECURITY
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module RubySMB
|
2
|
+
module Dcerpc
|
3
|
+
module Winreg
|
4
|
+
|
5
|
+
# This class represents a SetKeySecurity Request Packet as defined in
|
6
|
+
# [3.1.5.21 BaseRegSetKeySecurity (Opnum 21)](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rrp/da18856c-8a6d-4217-8e93-3625865e562c)
|
7
|
+
class SetKeySecurityRequest < BinData::Record
|
8
|
+
attr_reader :opnum
|
9
|
+
|
10
|
+
endian :little
|
11
|
+
|
12
|
+
rpc_hkey :hkey
|
13
|
+
uint32 :security_information
|
14
|
+
rpc_security_descriptor :prpc_security_descriptor
|
15
|
+
|
16
|
+
def initialize_instance
|
17
|
+
super
|
18
|
+
@opnum = REG_SET_KEY_SECURITY
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module RubySMB
|
2
|
+
module Dcerpc
|
3
|
+
module Winreg
|
4
|
+
|
5
|
+
# This class represents a SetKeySecurity Response Packet as defined in
|
6
|
+
# [3.1.5.21 BaseRegSetKeySecurity (Opnum 21)](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rrp/da18856c-8a6d-4217-8e93-3625865e562c)
|
7
|
+
class SetKeySecurityResponse < BinData::Record
|
8
|
+
attr_reader :opnum
|
9
|
+
|
10
|
+
endian :little
|
11
|
+
|
12
|
+
ndr_uint32 :error_status
|
13
|
+
|
14
|
+
def initialize_instance
|
15
|
+
super
|
16
|
+
@opnum = REG_SET_KEY_SECURITY
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
|
@@ -16,10 +16,12 @@ module RubySMB
|
|
16
16
|
REG_CREATE_KEY = 0x06
|
17
17
|
REG_ENUM_KEY = 0x09
|
18
18
|
REG_ENUM_VALUE = 0x0a
|
19
|
+
REG_GET_KEY_SECURITY = 0x0c
|
19
20
|
REG_OPEN_KEY = 0x0f
|
20
21
|
REG_QUERY_INFO_KEY = 0x10
|
21
22
|
REG_QUERY_VALUE = 0x11
|
22
23
|
REG_SAVE_KEY = 0x14
|
24
|
+
REG_SET_KEY_SECURITY = 0x15
|
23
25
|
OPEN_HKCC = 0x1b
|
24
26
|
OPEN_HKPT = 0x20
|
25
27
|
OPEN_HKPN = 0x21
|
@@ -43,6 +45,10 @@ module RubySMB
|
|
43
45
|
require 'ruby_smb/dcerpc/winreg/create_key_response'
|
44
46
|
require 'ruby_smb/dcerpc/winreg/save_key_request'
|
45
47
|
require 'ruby_smb/dcerpc/winreg/save_key_response'
|
48
|
+
require 'ruby_smb/dcerpc/winreg/get_key_security_request'
|
49
|
+
require 'ruby_smb/dcerpc/winreg/get_key_security_response'
|
50
|
+
require 'ruby_smb/dcerpc/winreg/set_key_security_request'
|
51
|
+
require 'ruby_smb/dcerpc/winreg/set_key_security_response'
|
46
52
|
|
47
53
|
ROOT_KEY_MAP = {
|
48
54
|
"HKEY_CLASSES_ROOT" => OPEN_HKCR,
|
@@ -65,6 +71,8 @@ module RubySMB
|
|
65
71
|
|
66
72
|
BUFFER_SIZE = 1024
|
67
73
|
|
74
|
+
RegValue = Struct.new(:type, :data)
|
75
|
+
|
68
76
|
# Open the registry root key and return a handle for it. The key can be
|
69
77
|
# either a long format (e.g. HKEY_LOCAL_MACHINE) or a short format
|
70
78
|
# (e.g. HKLM)
|
@@ -105,10 +113,7 @@ module RubySMB
|
|
105
113
|
# @raise [RubySMB::Dcerpc::Error::WinregError] if the response error status is not ERROR_SUCCESS
|
106
114
|
def open_key(handle, sub_key)
|
107
115
|
openkey_request_packet = RubySMB::Dcerpc::Winreg::OpenKeyRequest.new(hkey: handle, lp_sub_key: sub_key)
|
108
|
-
openkey_request_packet.sam_desired.
|
109
|
-
openkey_request_packet.sam_desired.key_query_value = 1
|
110
|
-
openkey_request_packet.sam_desired.key_enumerate_sub_keys = 1
|
111
|
-
openkey_request_packet.sam_desired.key_notify = 1
|
116
|
+
openkey_request_packet.sam_desired.maximum_allowed = 1
|
112
117
|
response = dcerpc_request(openkey_request_packet)
|
113
118
|
begin
|
114
119
|
open_key_response = RubySMB::Dcerpc::Winreg::OpenKeyResponse.read(response)
|
@@ -124,11 +129,12 @@ module RubySMB
|
|
124
129
|
end
|
125
130
|
|
126
131
|
# Retrieve the data associated with the named value of a specified
|
127
|
-
# registry open key.
|
132
|
+
# registry open key. This will also return the type if required.
|
128
133
|
#
|
129
134
|
# @param handle [Ndr::NdrContextHandle] the handle for the key
|
130
135
|
# @param value_name [String] the name of the value
|
131
|
-
# @
|
136
|
+
# @param value_name [Boolean] also return the data type if set to true
|
137
|
+
# @return [RegValue] a RegValue struct containing the data type and the actual data of the value entry
|
132
138
|
# @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a QueryValueResponse packet
|
133
139
|
# @raise [RubySMB::Dcerpc::Error::WinregError] if the response error status is not ERROR_SUCCESS
|
134
140
|
def query_value(handle, value_name)
|
@@ -161,7 +167,7 @@ module RubySMB
|
|
161
167
|
"#{WindowsError::Win32.find_by_retval(query_value_response.error_status.value).join(',')}"
|
162
168
|
end
|
163
169
|
|
164
|
-
query_value_response.data
|
170
|
+
RegValue.new(query_value_response.lp_type, query_value_response.data)
|
165
171
|
end
|
166
172
|
|
167
173
|
# Close the handle to the registry key.
|
@@ -323,6 +329,7 @@ module RubySMB
|
|
323
329
|
# exists, false otherwise.
|
324
330
|
#
|
325
331
|
# @param key [String] the registry key to check
|
332
|
+
# @param bind [Boolean] Bind to the winreg endpoint if true (default)
|
326
333
|
# @return [Boolean]
|
327
334
|
def has_registry_key?(key, bind: true)
|
328
335
|
bind(endpoint: RubySMB::Dcerpc::Winreg) if bind
|
@@ -345,6 +352,7 @@ module RubySMB
|
|
345
352
|
#
|
346
353
|
# @param key [String] the registry key
|
347
354
|
# @param value_name [String] the name of the value to read
|
355
|
+
# @param bind [Boolean] Bind to the winreg endpoint if true (default)
|
348
356
|
# @return [String] the data of the value entry
|
349
357
|
def read_registry_key_value(key, value_name, bind: true)
|
350
358
|
bind(endpoint: RubySMB::Dcerpc::Winreg) if bind
|
@@ -352,8 +360,8 @@ module RubySMB
|
|
352
360
|
root_key, sub_key = key.gsub(/\//, '\\').split('\\', 2)
|
353
361
|
root_key_handle = open_root_key(root_key)
|
354
362
|
subkey_handle = open_key(root_key_handle, sub_key)
|
355
|
-
|
356
|
-
|
363
|
+
reg_value = query_value(subkey_handle, value_name)
|
364
|
+
reg_value.data
|
357
365
|
ensure
|
358
366
|
close_key(subkey_handle) if subkey_handle
|
359
367
|
close_key(root_key_handle) if root_key_handle
|
@@ -363,6 +371,7 @@ module RubySMB
|
|
363
371
|
# is provided, it enumerates its subkeys.
|
364
372
|
#
|
365
373
|
# @param key [String] the registry key
|
374
|
+
# @param bind [Boolean] Bind to the winreg endpoint if true (default)
|
366
375
|
# @return [Array<String>] the subkeys
|
367
376
|
def enum_registry_key(key, bind: true)
|
368
377
|
bind(endpoint: RubySMB::Dcerpc::Winreg) if bind
|
@@ -389,6 +398,7 @@ module RubySMB
|
|
389
398
|
# Enumerate the values for the specified registry key.
|
390
399
|
#
|
391
400
|
# @param key [String] the registry key
|
401
|
+
# @param bind [Boolean] Bind to the winreg endpoint if true (default)
|
392
402
|
# @return [Array<String>] the values
|
393
403
|
def enum_registry_values(key, bind: true)
|
394
404
|
bind(endpoint: RubySMB::Dcerpc::Winreg) if bind
|
@@ -412,6 +422,108 @@ module RubySMB
|
|
412
422
|
close_key(root_key_handle) if root_key_handle && root_key_handle != subkey_handle
|
413
423
|
end
|
414
424
|
|
425
|
+
|
426
|
+
# Retrieve the security descriptor for the given registry key handle.
|
427
|
+
#
|
428
|
+
# @param handle [String] the handle to the registry key
|
429
|
+
# @param security_information [] the security information to query (see https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/23e75ca3-98fd-4396-84e5-86cd9d40d343). These constants are defined in the `RubySMB::Field::SecurityDescriptor` class
|
430
|
+
# @return [String] The security descriptor as a byte stream
|
431
|
+
# @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a GetKeySecurityResponse packet
|
432
|
+
# @raise [RubySMB::Dcerpc::Error::WinregError] if the response error status is not ERROR_SUCCESS
|
433
|
+
def get_key_security(handle, security_information = RubySMB::Field::SecurityDescriptor::OWNER_SECURITY_INFORMATION)
|
434
|
+
get_key_security_request = RubySMB::Dcerpc::Winreg::GetKeySecurityRequest.new(
|
435
|
+
hkey: handle,
|
436
|
+
security_information: security_information,
|
437
|
+
prpc_security_descriptor_in: { cb_in_security_descriptor: 4096 }
|
438
|
+
)
|
439
|
+
response = dcerpc_request(get_key_security_request)
|
440
|
+
begin
|
441
|
+
get_key_security_response = RubySMB::Dcerpc::Winreg::GetKeySecurityResponse.read(response)
|
442
|
+
rescue IOError
|
443
|
+
raise RubySMB::Dcerpc::Error::InvalidPacket, "Error reading the GetKeySecurity response"
|
444
|
+
end
|
445
|
+
unless get_key_security_response.error_status == WindowsError::Win32::ERROR_SUCCESS
|
446
|
+
raise RubySMB::Dcerpc::Error::WinregError, "Error returned when querying information: "\
|
447
|
+
"#{WindowsError::Win32.find_by_retval(get_key_security_response.error_status.value).join(',')}"
|
448
|
+
end
|
449
|
+
|
450
|
+
get_key_security_response.prpc_security_descriptor_out.lp_security_descriptor.to_a.pack('C*')
|
451
|
+
end
|
452
|
+
|
453
|
+
# Retrieve the security descriptor for the given key.
|
454
|
+
#
|
455
|
+
# @param key [String] the registry key
|
456
|
+
# @param security_information [] the security information to query (see https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/23e75ca3-98fd-4396-84e5-86cd9d40d343). These constants are defined in the `RubySMB::Field::SecurityDescriptor` class
|
457
|
+
# @param bind [Boolean] Bind to the winreg endpoint if true (default)
|
458
|
+
# @return [String] The security descriptor as a byte stream
|
459
|
+
# @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a GetKeySecurityResponse packet
|
460
|
+
# @raise [RubySMB::Dcerpc::Error::WinregError] if the response error status is not ERROR_SUCCESS
|
461
|
+
def get_key_security_descriptor(key, security_information = RubySMB::Field::SecurityDescriptor::OWNER_SECURITY_INFORMATION, bind: true)
|
462
|
+
bind(endpoint: RubySMB::Dcerpc::Winreg) if bind
|
463
|
+
|
464
|
+
root_key, sub_key = key.gsub(/\//, '\\').split('\\', 2)
|
465
|
+
root_key_handle = open_root_key(root_key)
|
466
|
+
subkey_handle = open_key(root_key_handle, sub_key)
|
467
|
+
get_key_security(subkey_handle, security_information)
|
468
|
+
ensure
|
469
|
+
close_key(subkey_handle) if subkey_handle
|
470
|
+
close_key(root_key_handle) if root_key_handle
|
471
|
+
end
|
472
|
+
|
473
|
+
# Set the security descriptor for the given registry key handle.
|
474
|
+
#
|
475
|
+
# @param handle [String] the handle to the registry key
|
476
|
+
# @param security_descriptor [String] the new security descriptor to set as a byte stream
|
477
|
+
# @param security_information [] the security information to query (see https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/23e75ca3-98fd-4396-84e5-86cd9d40d343). These constants are defined in the `RubySMB::Field::SecurityDescriptor` class
|
478
|
+
# @param bind [Boolean] Bind to the winreg endpoint if true (default)
|
479
|
+
# @return [Integer] The error status returned by the DCERPC call
|
480
|
+
# @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a SetKeySecurityResponse packet
|
481
|
+
# @raise [RubySMB::Dcerpc::Error::WinregError] if the response error status is not ERROR_SUCCESS
|
482
|
+
def set_key_security(handle, security_descriptor, security_information = RubySMB::Field::SecurityDescriptor::OWNER_SECURITY_INFORMATION)
|
483
|
+
set_key_security_request = RubySMB::Dcerpc::Winreg::SetKeySecurityRequest.new(
|
484
|
+
hkey: handle,
|
485
|
+
security_information: security_information,
|
486
|
+
prpc_security_descriptor: {
|
487
|
+
lp_security_descriptor: security_descriptor.bytes,
|
488
|
+
cb_in_security_descriptor: security_descriptor.b.size,
|
489
|
+
cb_out_security_descriptor: security_descriptor.b.size
|
490
|
+
}
|
491
|
+
)
|
492
|
+
response = dcerpc_request(set_key_security_request)
|
493
|
+
begin
|
494
|
+
set_key_security_response = RubySMB::Dcerpc::Winreg::SetKeySecurityResponse.read(response)
|
495
|
+
rescue IOError
|
496
|
+
raise RubySMB::Dcerpc::Error::InvalidPacket, "Error reading the SetKeySecurity response"
|
497
|
+
end
|
498
|
+
unless set_key_security_response.error_status == WindowsError::Win32::ERROR_SUCCESS
|
499
|
+
raise RubySMB::Dcerpc::Error::WinregError, "Error returned when setting the registry key: "\
|
500
|
+
"#{WindowsError::Win32.find_by_retval(set_key_security_response.error_status.value).join(',')}"
|
501
|
+
end
|
502
|
+
|
503
|
+
set_key_security_response.error_status
|
504
|
+
end
|
505
|
+
|
506
|
+
# Set the security descriptor for the given key.
|
507
|
+
#
|
508
|
+
# @param key [String] the registry key
|
509
|
+
# @param security_descriptor [String] the new security descriptor to set as a byte stream
|
510
|
+
# @param security_information [] the security information to query (see https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/23e75ca3-98fd-4396-84e5-86cd9d40d343). These constants are defined in the `RubySMB::Field::SecurityDescriptor` class
|
511
|
+
# @param bind [Boolean] Bind to the winreg endpoint if true (default)
|
512
|
+
# @return [Integer] The error status returned by the DCERPC call
|
513
|
+
# @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a SetKeySecurityResponse packet
|
514
|
+
# @raise [RubySMB::Dcerpc::Error::WinregError] if the response error status is not ERROR_SUCCESS
|
515
|
+
def set_key_security_descriptor(key, security_descriptor, security_information = RubySMB::Field::SecurityDescriptor::OWNER_SECURITY_INFORMATION, bind: true)
|
516
|
+
bind(endpoint: RubySMB::Dcerpc::Winreg) if bind
|
517
|
+
|
518
|
+
root_key, sub_key = key.gsub(/\//, '\\').split('\\', 2)
|
519
|
+
root_key_handle = open_root_key(root_key)
|
520
|
+
subkey_handle = open_key(root_key_handle, sub_key)
|
521
|
+
set_key_security(subkey_handle, security_descriptor, security_information)
|
522
|
+
ensure
|
523
|
+
close_key(subkey_handle) if subkey_handle
|
524
|
+
close_key(root_key_handle) if root_key_handle
|
525
|
+
end
|
526
|
+
|
415
527
|
end
|
416
528
|
end
|
417
529
|
end
|
@@ -3,6 +3,23 @@ module RubySMB
|
|
3
3
|
# Class representing a SECURITY_DESCRIPTOR as defined in
|
4
4
|
# [2.4.6 SECURITY_DESCRIPTOR](https://msdn.microsoft.com/en-us/library/cc230366.aspx)
|
5
5
|
class SecurityDescriptor < BinData::Record
|
6
|
+
|
7
|
+
# Security Information as defined in
|
8
|
+
# [2.4.7 SECURITY_INFORMATION](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/23e75ca3-98fd-4396-84e5-86cd9d40d343)
|
9
|
+
OWNER_SECURITY_INFORMATION = 0x00000001
|
10
|
+
GROUP_SECURITY_INFORMATION = 0x00000002
|
11
|
+
DACL_SECURITY_INFORMATION = 0x00000004
|
12
|
+
SACL_SECURITY_INFORMATION = 0x00000008
|
13
|
+
LABEL_SECURITY_INFORMATION = 0x00000010
|
14
|
+
UNPROTECTED_SACL_SECURITY_INFORMATION = 0x10000000
|
15
|
+
UNPROTECTED_DACL_SECURITY_INFORMATION = 0x20000000
|
16
|
+
PROTECTED_SACL_SECURITY_INFORMATION = 0x40000000
|
17
|
+
PROTECTED_DACL_SECURITY_INFORMATION = 0x80000000
|
18
|
+
ATTRIBUTE_SECURITY_INFORMATION = 0x00000020
|
19
|
+
SCOPE_SECURITY_INFORMATION = 0x00000040
|
20
|
+
PROCESS_TRUST_LABEL_SECURITY_INFORMATION = 0x00000080
|
21
|
+
BACKUP_SECURITY_INFORMATION = 0x00010000
|
22
|
+
|
6
23
|
endian :little
|
7
24
|
uint8 :revision, label: 'Revision', initial_value: 0x01
|
8
25
|
uint8 :sbz1, label: 'Resource Manager Control Bits'
|
data/lib/ruby_smb/version.rb
CHANGED
@@ -0,0 +1,40 @@
|
|
1
|
+
RSpec.describe RubySMB::Dcerpc::Lsarpc::LsarCloseHandleRequest do
|
2
|
+
subject(:packet) { described_class.new }
|
3
|
+
|
4
|
+
it { is_expected.to respond_to :policy_handle }
|
5
|
+
it { is_expected.to respond_to :opnum }
|
6
|
+
|
7
|
+
it 'is little endian' do
|
8
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
9
|
+
end
|
10
|
+
it 'is a BinData::Record' do
|
11
|
+
expect(packet).to be_a(BinData::Record)
|
12
|
+
end
|
13
|
+
describe '#policy_handle' do
|
14
|
+
it 'is an LsaprHandle structure' do
|
15
|
+
expect(packet.policy_handle).to be_a RubySMB::Dcerpc::Lsarpc::LsaprHandle
|
16
|
+
end
|
17
|
+
end
|
18
|
+
describe '#initialize_instance' do
|
19
|
+
it 'sets #opnum to LSAR_CLOSE_HANDLE constant' do
|
20
|
+
expect(packet.opnum).to eq(RubySMB::Dcerpc::Lsarpc::LSAR_CLOSE_HANDLE)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
it 'reads itself' do
|
24
|
+
new_packet = described_class.new(
|
25
|
+
policy_handle: {
|
26
|
+
context_handle_attributes: 0,
|
27
|
+
context_handle_uuid: "fc873b90-d9a9-46a4-b9ea-f44bb1c272a7"
|
28
|
+
}
|
29
|
+
)
|
30
|
+
expected_output = {
|
31
|
+
policy_handle: {
|
32
|
+
context_handle_attributes: 0,
|
33
|
+
context_handle_uuid: "fc873b90-d9a9-46a4-b9ea-f44bb1c272a7"
|
34
|
+
}
|
35
|
+
}
|
36
|
+
expect(packet.read(new_packet.to_binary_s)).to eq(expected_output)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
|
@@ -0,0 +1,46 @@
|
|
1
|
+
RSpec.describe RubySMB::Dcerpc::Lsarpc::LsarCloseHandleResponse do
|
2
|
+
subject(:packet) { described_class.new }
|
3
|
+
|
4
|
+
it { is_expected.to respond_to :policy_handle }
|
5
|
+
it { is_expected.to respond_to :error_status }
|
6
|
+
it { is_expected.to respond_to :opnum }
|
7
|
+
|
8
|
+
it 'is little endian' do
|
9
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
10
|
+
end
|
11
|
+
it 'is a BinData::Record' do
|
12
|
+
expect(packet).to be_a(BinData::Record)
|
13
|
+
end
|
14
|
+
describe '#policy_handle' do
|
15
|
+
it 'is a LsaprHandle structure' do
|
16
|
+
expect(packet.policy_handle).to be_a RubySMB::Dcerpc::Lsarpc::LsaprHandle
|
17
|
+
end
|
18
|
+
end
|
19
|
+
describe '#error_status' do
|
20
|
+
it 'is a NdrUint32 structure' do
|
21
|
+
expect(packet.error_status).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
|
22
|
+
end
|
23
|
+
end
|
24
|
+
describe '#initialize_instance' do
|
25
|
+
it 'sets #opnum to LSAR_CLOSE_HANDLE constant' do
|
26
|
+
expect(packet.opnum).to eq(RubySMB::Dcerpc::Lsarpc::LSAR_CLOSE_HANDLE)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
it 'reads itself' do
|
30
|
+
new_class = described_class.new(
|
31
|
+
policy_handle: {
|
32
|
+
context_handle_attributes: 0,
|
33
|
+
context_handle_uuid: '2ef54a87-e29e-4d24-90e9-9da49b94449e'
|
34
|
+
},
|
35
|
+
error_status: 0
|
36
|
+
)
|
37
|
+
expect(packet.read(new_class.to_binary_s)).to eq(
|
38
|
+
{
|
39
|
+
policy_handle: {
|
40
|
+
context_handle_attributes: 0,
|
41
|
+
context_handle_uuid: '2ef54a87-e29e-4d24-90e9-9da49b94449e'
|
42
|
+
},
|
43
|
+
error_status: 0
|
44
|
+
})
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'ruby_smb/dcerpc/ndr'
|
2
|
+
|
3
|
+
RSpec.describe RubySMB::Dcerpc::Lsarpc::LsarLookupSidsRequest do
|
4
|
+
subject(:packet) { described_class.new }
|
5
|
+
|
6
|
+
it { is_expected.to respond_to :policy_handle }
|
7
|
+
it { is_expected.to respond_to :sid_enum_buffer }
|
8
|
+
it { is_expected.to respond_to :translated_names }
|
9
|
+
it { is_expected.to respond_to :lookup_level }
|
10
|
+
it { is_expected.to respond_to :mapped_count }
|
11
|
+
it { is_expected.to respond_to :opnum }
|
12
|
+
|
13
|
+
it 'is little endian' do
|
14
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
15
|
+
end
|
16
|
+
it 'is a BinData::Record' do
|
17
|
+
expect(packet).to be_a(BinData::Record)
|
18
|
+
end
|
19
|
+
describe '#policy_handle' do
|
20
|
+
it 'is an LsaprHandle structure' do
|
21
|
+
expect(packet.policy_handle).to be_a RubySMB::Dcerpc::Lsarpc::LsaprHandle
|
22
|
+
end
|
23
|
+
end
|
24
|
+
describe '#sid_enum_buffer' do
|
25
|
+
it 'is an LsaprSidEnumBuffer structure' do
|
26
|
+
expect(packet.sid_enum_buffer).to be_a RubySMB::Dcerpc::Lsarpc::LsaprSidEnumBuffer
|
27
|
+
end
|
28
|
+
end
|
29
|
+
describe '#translated_names' do
|
30
|
+
it 'is an LsaprTranslatedNames structure' do
|
31
|
+
expect(packet.translated_names).to be_a RubySMB::Dcerpc::Lsarpc::LsaprTranslatedNames
|
32
|
+
end
|
33
|
+
end
|
34
|
+
describe '#lookup_level' do
|
35
|
+
it 'is an NdrUint16' do
|
36
|
+
expect(packet.lookup_level).to be_a RubySMB::Dcerpc::Ndr::NdrUint16
|
37
|
+
end
|
38
|
+
end
|
39
|
+
describe '#mapped_count' do
|
40
|
+
it 'is an NdrUint32' do
|
41
|
+
expect(packet.mapped_count).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
|
42
|
+
end
|
43
|
+
end
|
44
|
+
describe '#initialize_instance' do
|
45
|
+
it 'sets #opnum to LSAR_LOOKUP_SIDS constant' do
|
46
|
+
expect(packet.opnum).to eq(RubySMB::Dcerpc::Lsarpc::LSAR_LOOKUP_SIDS)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
it 'reads itself' do
|
50
|
+
new_class = described_class.new(
|
51
|
+
policy_handle: {
|
52
|
+
context_handle_attributes: 0,
|
53
|
+
context_handle_uuid: "fc873b90-d9a9-46a4-b9ea-f44bb1c272a7"
|
54
|
+
},
|
55
|
+
sid_enum_buffer: { num_entries: 1, sid_info: [ { sid: 'S-1-5-21-2181772609-2124839192-2039643012-500' } ] },
|
56
|
+
lookup_level: 0,
|
57
|
+
)
|
58
|
+
expect(packet.read(new_class.to_binary_s)).to eq(
|
59
|
+
policy_handle: {
|
60
|
+
context_handle_attributes: 0,
|
61
|
+
context_handle_uuid: "fc873b90-d9a9-46a4-b9ea-f44bb1c272a7"
|
62
|
+
},
|
63
|
+
sid_enum_buffer: { num_entries: 1, sid_info: [ { sid: 'S-1-5-21-2181772609-2124839192-2039643012-500' } ] },
|
64
|
+
translated_names: { num_entries: 0, names: :null },
|
65
|
+
lookup_level: 0,
|
66
|
+
mapped_count: 0
|
67
|
+
)
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'ruby_smb/dcerpc/ndr'
|
2
|
+
|
3
|
+
RSpec.describe RubySMB::Dcerpc::Lsarpc::LsarLookupSidsResponse do
|
4
|
+
subject(:packet) { described_class.new }
|
5
|
+
|
6
|
+
it { is_expected.to respond_to :referenced_domains }
|
7
|
+
it { is_expected.to respond_to :translated_names }
|
8
|
+
it { is_expected.to respond_to :mapped_count }
|
9
|
+
it { is_expected.to respond_to :error_status }
|
10
|
+
it { is_expected.to respond_to :opnum }
|
11
|
+
|
12
|
+
it 'is little endian' do
|
13
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
14
|
+
end
|
15
|
+
it 'is a BinData::Record' do
|
16
|
+
expect(packet).to be_a(BinData::Record)
|
17
|
+
end
|
18
|
+
describe '#referenced_domains' do
|
19
|
+
it 'is an LsaprReferencedDomainListPtr structure' do
|
20
|
+
expect(packet.referenced_domains).to be_a RubySMB::Dcerpc::Lsarpc::LsaprReferencedDomainListPtr
|
21
|
+
end
|
22
|
+
end
|
23
|
+
describe '#translated_names' do
|
24
|
+
it 'is an LsaprTranslatedNames structure' do
|
25
|
+
expect(packet.translated_names).to be_a RubySMB::Dcerpc::Lsarpc::LsaprTranslatedNames
|
26
|
+
end
|
27
|
+
end
|
28
|
+
describe '#mapped_count' do
|
29
|
+
it 'is an NdrUint32 structure' do
|
30
|
+
expect(packet.mapped_count).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
|
31
|
+
end
|
32
|
+
end
|
33
|
+
describe '#error_status' do
|
34
|
+
it 'is an NdrUint32' do
|
35
|
+
expect(packet.error_status).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
|
36
|
+
end
|
37
|
+
end
|
38
|
+
describe '#initialize_instance' do
|
39
|
+
it 'sets #opnum to LSAR_LOOKUP_SIDS constant' do
|
40
|
+
expect(packet.opnum).to eq(RubySMB::Dcerpc::Lsarpc::LSAR_LOOKUP_SIDS)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
it 'reads itself' do
|
44
|
+
new_class = described_class.new(
|
45
|
+
translated_names: { num_entries: 1, names: [ { use: 0, name: 'Administrator', domain_index: 0 }] },
|
46
|
+
mapped_count: 1,
|
47
|
+
error_status: 0
|
48
|
+
)
|
49
|
+
expect(packet.read(new_class.to_binary_s)).to eq(
|
50
|
+
referenced_domains: :null,
|
51
|
+
translated_names: { num_entries: 1, names: [ { use: 0, name: { buffer_length: 26, maximum_length: 26, buffer: 'Administrator'.encode('UTF-16LE') }, domain_index: 0 } ] },
|
52
|
+
mapped_count: 1,
|
53
|
+
error_status: 0
|
54
|
+
)
|
55
|
+
end
|
56
|
+
end
|