ruby_smb 3.3.6 → 3.3.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/examples/registry_key_security_descriptor.rb +109 -0
- data/lib/ruby_smb/client/winreg.rb +12 -0
- data/lib/ruby_smb/dcerpc/ndr.rb +10 -4
- data/lib/ruby_smb/dcerpc/request.rb +18 -16
- data/lib/ruby_smb/dcerpc/rrp_rpc_unicode_string.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/ndr_spec.rb +80 -0
- data/spec/lib/ruby_smb/dcerpc/winreg_spec.rb +267 -18
- data.tar.gz.sig +0 -0
- metadata +8 -3
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 228afeef84601354373c132ceaa48341ed9f5f4bbab4e625c37d2f2d71864146
|
4
|
+
data.tar.gz: 71512d0529ba352d0cc0ee7c27a27e03116d50f31801beed3fd04cb19e73f4ff
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3c7dede328c8d637b9088da518649deba6d758a1093e3591bb0cd9e2f4c458a5c5a82a37640aa14523586aa6e83b61d59d4fab21d3fa33739c47d687367cede3
|
7
|
+
data.tar.gz: 6c72f0673379264f71a55935dec05f13f195614c9cd8d6f44935687ab028545e233496ad04f4157a07d1f5f74092fac8dd43f69713d2ac1aeeb7006a12c47e21
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
@@ -0,0 +1,109 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
# This example script is used for testing the Winreg registry key security descriptor functionalities.
|
4
|
+
# It will attempt to connect to a host and reads (or writes) the security descriptor of a specified registry key.
|
5
|
+
#
|
6
|
+
# Example usage:
|
7
|
+
# - read:
|
8
|
+
# ruby examples/read_registry_key_security.rb --username msfadmin --password msfadmin -i 7 -o r 192.168.172.138 'HKLM\SECURITY\Policy\PolEKList'
|
9
|
+
# This will try to connect to \\192.168.172.138 with the msfadmin:msfadmin
|
10
|
+
# credentialas and read the security descriptor of the
|
11
|
+
# `HKLM\SECURITY\Policy\PolEKList` registry key with the security information 7
|
12
|
+
# (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
|
13
|
+
# DACL_SECURITY_INFORMATION).
|
14
|
+
#
|
15
|
+
# - write:
|
16
|
+
# ruby examples/read_registry_key_security.rb --username msfadmin --password msfadmin -i 4 --sd 01000480000000000000000000000000140000000200340002000000000214003f000f00010100000000000512000000000218000000060001020000000000052000000020020000 -o w 192.168.172.138 'HKLM\SECURITY\Policy\PolEKList'
|
17
|
+
# This will try to connect to \\192.168.172.138 with the msfadmin:msfadmin
|
18
|
+
# credentialas and write the given security descriptor to the
|
19
|
+
# `HKLM\SECURITY\Policy\PolEKList` registry key with the security information 4
|
20
|
+
# (DACL_SECURITY_INFORMATION).
|
21
|
+
|
22
|
+
require 'bundler/setup'
|
23
|
+
require 'optparse'
|
24
|
+
require 'ruby_smb'
|
25
|
+
|
26
|
+
OPERATIONS = %w{read write}
|
27
|
+
OPERATION_ALIASES = { "r" => "read", "w" => "write" }
|
28
|
+
|
29
|
+
args = ARGV.dup
|
30
|
+
options = {
|
31
|
+
domain: '.',
|
32
|
+
username: '',
|
33
|
+
password: '',
|
34
|
+
smbv1: true,
|
35
|
+
smbv2: true,
|
36
|
+
smbv3: true,
|
37
|
+
target: nil,
|
38
|
+
key: nil,
|
39
|
+
operation: 'read',
|
40
|
+
info: RubySMB::Field::SecurityDescriptor::OWNER_SECURITY_INFORMATION | RubySMB::Field::SecurityDescriptor::GROUP_SECURITY_INFORMATION | RubySMB::Field::SecurityDescriptor::DACL_SECURITY_INFORMATION,
|
41
|
+
sd: nil
|
42
|
+
}
|
43
|
+
options[:key] = args.pop
|
44
|
+
options[:target ] = args.pop
|
45
|
+
optparser = OptionParser.new do |opts|
|
46
|
+
opts.banner = "Usage: #{File.basename(__FILE__)} [options] target reg_key"
|
47
|
+
opts.on('--[no-]smbv1', "Enable or disable SMBv1 (default: #{options[:smbv1] ? 'Enabled' : 'Disabled'})") do |smbv1|
|
48
|
+
options[:smbv1] = smbv1
|
49
|
+
end
|
50
|
+
opts.on('--[no-]smbv2', "Enable or disable SMBv2 (default: #{options[:smbv2] ? 'Enabled' : 'Disabled'})") do |smbv2|
|
51
|
+
options[:smbv2] = smbv2
|
52
|
+
end
|
53
|
+
opts.on('--[no-]smbv3', "Enable or disable SMBv3 (default: #{options[:smbv3] ? 'Enabled' : 'Disabled'})") do |smbv3|
|
54
|
+
options[:smbv3] = smbv3
|
55
|
+
end
|
56
|
+
opts.on('-u', '--username [USERNAME]', "The account's username (default: #{options[:username]})") do |username|
|
57
|
+
if username.include?('\\')
|
58
|
+
options[:domain], options[:username] = username.split('\\', 2)
|
59
|
+
else
|
60
|
+
options[:username] = username
|
61
|
+
end
|
62
|
+
end
|
63
|
+
opts.on('-p', '--password [PASSWORD]', "The account's password (default: #{options[:password]})") do |password|
|
64
|
+
options[:password] = password
|
65
|
+
end
|
66
|
+
operation_list = (OPERATION_ALIASES.keys + OPERATIONS).join(', ')
|
67
|
+
opts.on('-o', '--operation OPERATION', OPERATIONS, OPERATION_ALIASES, "The operation to perform on the registry key (default: #{options[:operation]})", "(#{operation_list})") do |operation|
|
68
|
+
options[:operation] = operation
|
69
|
+
end
|
70
|
+
opts.on('-i', '--info [SECURITY INFORMATION]', Integer, "The security information value (default: #{options[:info]})") do |password|
|
71
|
+
options[:info] = password
|
72
|
+
end
|
73
|
+
opts.on('-s', '--sd [SECURITY DESCRIPTOR]', "The security descriptor to write as an hex string") do |sd|
|
74
|
+
options[:sd] = sd
|
75
|
+
end
|
76
|
+
end
|
77
|
+
optparser.parse!(args)
|
78
|
+
|
79
|
+
if options[:target].nil? || options[:key].nil?
|
80
|
+
abort(optparser.help)
|
81
|
+
end
|
82
|
+
|
83
|
+
sock = TCPSocket.new options[:target], 445
|
84
|
+
dispatcher = RubySMB::Dispatcher::Socket.new(sock)
|
85
|
+
|
86
|
+
client = RubySMB::Client.new(dispatcher, smb1: options[:smbv1], smb2: options[:smbv2], smb3: options[:smbv3], username: options[:username], password: options[:password], domain: options[:domain])
|
87
|
+
protocol = client.negotiate
|
88
|
+
status = client.authenticate
|
89
|
+
|
90
|
+
puts "#{protocol}: #{status}"
|
91
|
+
|
92
|
+
case options[:operation]
|
93
|
+
when 'read', 'r'
|
94
|
+
puts "Read registry key #{options[:key]} security descriptor with security information #{options[:info]}"
|
95
|
+
security_descriptor = client.get_key_security_descriptor(options[:target], options[:key], options[:info])
|
96
|
+
puts "Security descriptor: #{security_descriptor.b.bytes.map {|c| "%02x" % c.ord}.join}"
|
97
|
+
when 'write', 'w'
|
98
|
+
unless options[:sd] && !options[:sd].empty?
|
99
|
+
puts "Security descriptor missing"
|
100
|
+
abort(optparser.help)
|
101
|
+
end
|
102
|
+
puts "Write security descriptor #{options[:sd]} to registry key #{options[:key]} with security information #{options[:info]}"
|
103
|
+
sd = options[:sd].chars.each_slice(2).map {|c| c.join.to_i(16).chr}.join
|
104
|
+
status = client.set_key_security_descriptor(options[:target], options[:key], sd, options[:info])
|
105
|
+
puts "Success!"
|
106
|
+
end
|
107
|
+
|
108
|
+
client.disconnect!
|
109
|
+
|
@@ -40,6 +40,18 @@ module RubySMB
|
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
|
+
def get_key_security_descriptor(host, key, security_information = RubySMB::Field::SecurityDescriptor::OWNER_SECURITY_INFORMATION)
|
44
|
+
connect_to_winreg(host) do |named_pipe|
|
45
|
+
named_pipe.get_key_security_descriptor(key, security_information)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def set_key_security_descriptor(host, key, security_descriptor, security_information = RubySMB::Field::SecurityDescriptor::OWNER_SECURITY_INFORMATION)
|
50
|
+
connect_to_winreg(host) do |named_pipe|
|
51
|
+
named_pipe.set_key_security_descriptor(key, security_descriptor, security_information)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
43
55
|
end
|
44
56
|
end
|
45
57
|
end
|
data/lib/ruby_smb/dcerpc/ndr.rb
CHANGED
@@ -567,8 +567,11 @@ module RubySMB::Dcerpc::Ndr
|
|
567
567
|
def get_max_count(val)
|
568
568
|
if is_a?(BinData::Stringz)
|
569
569
|
max_count = val.to_s.strip.length
|
570
|
-
#
|
571
|
-
|
570
|
+
# Add one to count the terminator. According to
|
571
|
+
# https://pubs.opengroup.org/onlinepubs/9629399/chap14.htm#tagcjh_19_03_04_02,
|
572
|
+
# the NDR String must contain at least one element, the terminator. So,
|
573
|
+
# add one even if it is an empty string.
|
574
|
+
max_count += 1
|
572
575
|
return max_count
|
573
576
|
else
|
574
577
|
return val.to_s.length
|
@@ -622,8 +625,11 @@ module RubySMB::Dcerpc::Ndr
|
|
622
625
|
def update_actual_count(val)
|
623
626
|
if is_a?(BinData::Stringz)
|
624
627
|
@actual_count = val.to_s.strip.length
|
625
|
-
#
|
626
|
-
|
628
|
+
# Add one to count the terminator. According to
|
629
|
+
# https://pubs.opengroup.org/onlinepubs/9629399/chap14.htm#tagcjh_19_03_04,
|
630
|
+
# the NDR String must contain at least one element, the terminator. So,
|
631
|
+
# add one even if it is an empty string.
|
632
|
+
@actual_count += 1
|
627
633
|
else
|
628
634
|
@actual_count = val.to_s.length
|
629
635
|
end
|
@@ -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
|
@@ -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
|
@@ -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
@@ -1352,6 +1352,15 @@ RSpec.describe RubySMB::Dcerpc::Ndr::NdrVarString do
|
|
1352
1352
|
}
|
1353
1353
|
let(:value) { 'ABCD' }
|
1354
1354
|
end
|
1355
|
+
context 'with an empty string' do
|
1356
|
+
it_behaves_like 'a NDR String', conformant: false, char_size: 1, null_terminated: false do
|
1357
|
+
let(:binary_stream) {
|
1358
|
+
"\x00\x00\x00\x00"\
|
1359
|
+
"\x00\x00\x00\x00".b
|
1360
|
+
}
|
1361
|
+
let(:value) { '' }
|
1362
|
+
end
|
1363
|
+
end
|
1355
1364
|
end
|
1356
1365
|
|
1357
1366
|
RSpec.describe RubySMB::Dcerpc::Ndr::NdrVarStringz do
|
@@ -1368,6 +1377,16 @@ RSpec.describe RubySMB::Dcerpc::Ndr::NdrVarStringz do
|
|
1368
1377
|
}
|
1369
1378
|
let(:value) { 'ABCD' }
|
1370
1379
|
end
|
1380
|
+
context 'with an empty string' do
|
1381
|
+
it_behaves_like 'a NDR String', conformant: false, char_size: 1, null_terminated: true do
|
1382
|
+
let(:binary_stream) {
|
1383
|
+
"\x00\x00\x00\x00"\
|
1384
|
+
"\x01\x00\x00\x00"\
|
1385
|
+
"\x00".b
|
1386
|
+
}
|
1387
|
+
let(:value) { '' }
|
1388
|
+
end
|
1389
|
+
end
|
1371
1390
|
end
|
1372
1391
|
|
1373
1392
|
RSpec.describe RubySMB::Dcerpc::Ndr::NdrVarWideString do
|
@@ -1383,6 +1402,15 @@ RSpec.describe RubySMB::Dcerpc::Ndr::NdrVarWideString do
|
|
1383
1402
|
}
|
1384
1403
|
let(:value) { 'ABCD'.encode('utf-16le') }
|
1385
1404
|
end
|
1405
|
+
context 'with an empty string' do
|
1406
|
+
it_behaves_like 'a NDR String', conformant: false, char_size: 2, null_terminated: false do
|
1407
|
+
let(:binary_stream) {
|
1408
|
+
"\x00\x00\x00\x00"\
|
1409
|
+
"\x00\x00\x00\x00".b
|
1410
|
+
}
|
1411
|
+
let(:value) { '' }
|
1412
|
+
end
|
1413
|
+
end
|
1386
1414
|
end
|
1387
1415
|
|
1388
1416
|
RSpec.describe RubySMB::Dcerpc::Ndr::NdrVarWideStringz do
|
@@ -1398,6 +1426,16 @@ RSpec.describe RubySMB::Dcerpc::Ndr::NdrVarWideStringz do
|
|
1398
1426
|
}
|
1399
1427
|
let(:value) { 'ABCD'.encode('utf-16le') }
|
1400
1428
|
end
|
1429
|
+
context 'with an empty string' do
|
1430
|
+
it_behaves_like 'a NDR String', conformant: false, char_size: 2, null_terminated: true do
|
1431
|
+
let(:binary_stream) {
|
1432
|
+
"\x00\x00\x00\x00"\
|
1433
|
+
"\x01\x00\x00\x00"\
|
1434
|
+
"\x00\x00".b
|
1435
|
+
}
|
1436
|
+
let(:value) { '' }
|
1437
|
+
end
|
1438
|
+
end
|
1401
1439
|
end
|
1402
1440
|
|
1403
1441
|
RSpec.describe RubySMB::Dcerpc::Ndr::NdrConfVarString do
|
@@ -1415,6 +1453,16 @@ RSpec.describe RubySMB::Dcerpc::Ndr::NdrConfVarString do
|
|
1415
1453
|
}
|
1416
1454
|
let(:value) { 'ABCD' }
|
1417
1455
|
end
|
1456
|
+
context 'with an empty string' do
|
1457
|
+
it_behaves_like 'a NDR String', conformant: true, char_size: 1, null_terminated: false do
|
1458
|
+
let(:binary_stream) {
|
1459
|
+
"\x00\x00\x00\x00"\
|
1460
|
+
"\x00\x00\x00\x00"\
|
1461
|
+
"\x00\x00\x00\x00".b
|
1462
|
+
}
|
1463
|
+
let(:value) { '' }
|
1464
|
+
end
|
1465
|
+
end
|
1418
1466
|
end
|
1419
1467
|
|
1420
1468
|
RSpec.describe RubySMB::Dcerpc::Ndr::NdrConfVarStringz do
|
@@ -1432,6 +1480,17 @@ RSpec.describe RubySMB::Dcerpc::Ndr::NdrConfVarStringz do
|
|
1432
1480
|
}
|
1433
1481
|
let(:value) { 'ABCD' }
|
1434
1482
|
end
|
1483
|
+
context 'with an empty string' do
|
1484
|
+
it_behaves_like 'a NDR String', conformant: true, char_size: 1, null_terminated: true do
|
1485
|
+
let(:binary_stream) {
|
1486
|
+
"\x01\x00\x00\x00"\
|
1487
|
+
"\x00\x00\x00\x00"\
|
1488
|
+
"\x01\x00\x00\x00"\
|
1489
|
+
"\x00".b
|
1490
|
+
}
|
1491
|
+
let(:value) { '' }
|
1492
|
+
end
|
1493
|
+
end
|
1435
1494
|
end
|
1436
1495
|
|
1437
1496
|
RSpec.describe RubySMB::Dcerpc::Ndr::NdrConfVarWideString do
|
@@ -1448,6 +1507,16 @@ RSpec.describe RubySMB::Dcerpc::Ndr::NdrConfVarWideString do
|
|
1448
1507
|
}
|
1449
1508
|
let(:value) { 'ABCD'.encode('utf-16le') }
|
1450
1509
|
end
|
1510
|
+
context 'with an empty string' do
|
1511
|
+
it_behaves_like 'a NDR String', conformant: true, char_size: 2, null_terminated: false do
|
1512
|
+
let(:binary_stream) {
|
1513
|
+
"\x00\x00\x00\x00"\
|
1514
|
+
"\x00\x00\x00\x00"\
|
1515
|
+
"\x00\x00\x00\x00".b
|
1516
|
+
}
|
1517
|
+
let(:value) { '' }
|
1518
|
+
end
|
1519
|
+
end
|
1451
1520
|
end
|
1452
1521
|
|
1453
1522
|
RSpec.describe RubySMB::Dcerpc::Ndr::NdrConfVarWideStringz do
|
@@ -1464,6 +1533,17 @@ RSpec.describe RubySMB::Dcerpc::Ndr::NdrConfVarWideStringz do
|
|
1464
1533
|
}
|
1465
1534
|
let(:value) { 'ABCD'.encode('utf-16le') }
|
1466
1535
|
end
|
1536
|
+
context 'with an empty string' do
|
1537
|
+
it_behaves_like 'a NDR String', conformant: true, char_size: 1, null_terminated: true do
|
1538
|
+
let(:binary_stream) {
|
1539
|
+
"\x01\x00\x00\x00"\
|
1540
|
+
"\x00\x00\x00\x00"\
|
1541
|
+
"\x01\x00\x00\x00"\
|
1542
|
+
"\x00\x00".b
|
1543
|
+
}
|
1544
|
+
let(:value) { '' }
|
1545
|
+
end
|
1546
|
+
end
|
1467
1547
|
end
|
1468
1548
|
|
1469
1549
|
|
@@ -73,12 +73,7 @@ RSpec.describe RubySMB::Dcerpc::Winreg do
|
|
73
73
|
before :example do
|
74
74
|
allow(described_class::OpenKeyRequest).to receive(:new).and_return(openkey_request_packet)
|
75
75
|
allow(openkey_request_packet).to receive(:sam_desired).and_return(regsam)
|
76
|
-
allow(regsam).to
|
77
|
-
:read_control= => nil,
|
78
|
-
:key_query_value= => nil,
|
79
|
-
:key_enumerate_sub_keys= => nil,
|
80
|
-
:key_notify= => nil,
|
81
|
-
)
|
76
|
+
allow(regsam).to receive(:maximum_allowed=)
|
82
77
|
allow(winreg).to receive(:dcerpc_request).and_return(response)
|
83
78
|
allow(described_class::OpenKeyResponse).to receive(:read).and_return(open_key_response)
|
84
79
|
allow(open_key_response).to receive_messages(
|
@@ -94,10 +89,7 @@ RSpec.describe RubySMB::Dcerpc::Winreg do
|
|
94
89
|
|
95
90
|
it 'sets the expected user rights on the request packet' do
|
96
91
|
winreg.open_key(handle, sub_key)
|
97
|
-
expect(regsam).to have_received(:
|
98
|
-
expect(regsam).to have_received(:key_query_value=).with(1)
|
99
|
-
expect(regsam).to have_received(:key_enumerate_sub_keys=).with(1)
|
100
|
-
expect(regsam).to have_received(:key_notify=).with(1)
|
92
|
+
expect(regsam).to have_received(:maximum_allowed=).with(1)
|
101
93
|
end
|
102
94
|
|
103
95
|
it 'sends the expected dcerpc request' do
|
@@ -132,12 +124,13 @@ RSpec.describe RubySMB::Dcerpc::Winreg do
|
|
132
124
|
describe '#query_value' do
|
133
125
|
let(:handle) { double('Handle') }
|
134
126
|
let(:value_name) { double('Value Name') }
|
135
|
-
let(:query_value_request_packet)
|
136
|
-
let(:lp_data)
|
127
|
+
let(:query_value_request_packet) { double('Query Value Request Packet #1') }
|
128
|
+
let(:lp_data) { double('LpData #2') }
|
137
129
|
let(:response1) { double('Response #1') }
|
138
130
|
let(:response2) { double('Response #2') }
|
139
131
|
let(:query_value_response1) { double('Query Value Response #1') }
|
140
132
|
let(:query_value_response2) { double('Query Value Response #2') }
|
133
|
+
let(:lp_type) { double('Type') }
|
141
134
|
let(:data) { double('Data') }
|
142
135
|
let(:lpcb_data) { double('LpcbData') }
|
143
136
|
let(:max_count) { 5 }
|
@@ -164,8 +157,9 @@ RSpec.describe RubySMB::Dcerpc::Winreg do
|
|
164
157
|
allow(described_class::QueryValueResponse).to receive(:read).with(response2).and_return(query_value_response2)
|
165
158
|
allow(query_value_response1).to receive(:error_status).and_return(WindowsError::Win32::ERROR_SUCCESS)
|
166
159
|
allow(query_value_response2).to receive_messages(
|
167
|
-
:
|
168
|
-
:
|
160
|
+
error_status: WindowsError::Win32::ERROR_SUCCESS,
|
161
|
+
lp_type: lp_type,
|
162
|
+
data: data
|
169
163
|
)
|
170
164
|
allow(query_value_response1).to receive(:lpcb_data).and_return(lpcb_data)
|
171
165
|
allow(lpcb_data).to receive(:to_i).and_return(max_count)
|
@@ -234,8 +228,9 @@ RSpec.describe RubySMB::Dcerpc::Winreg do
|
|
234
228
|
end
|
235
229
|
|
236
230
|
it 'returns the expected response data' do
|
237
|
-
expect(winreg.query_value(handle, value_name)).to eq(data)
|
231
|
+
expect(winreg.query_value(handle, value_name)).to eq(RubySMB::Dcerpc::Winreg::RegValue.new(lp_type, data))
|
238
232
|
end
|
233
|
+
|
239
234
|
end
|
240
235
|
|
241
236
|
describe '#close_key' do
|
@@ -529,13 +524,14 @@ RSpec.describe RubySMB::Dcerpc::Winreg do
|
|
529
524
|
let(:value_name) { 'registry_value_name' }
|
530
525
|
let(:root_key_handle) { double('Root Key Handle') }
|
531
526
|
let(:subkey_handle) { double('Subkey Handle') }
|
532
|
-
let(:
|
527
|
+
let(:data) { double('Reg value data') }
|
528
|
+
let(:reg_value) { RubySMB::Dcerpc::Winreg::RegValue.new(nil, data) }
|
533
529
|
before :example do
|
534
530
|
allow(winreg).to receive_messages(
|
535
531
|
:bind => nil,
|
536
532
|
:open_root_key => root_key_handle,
|
537
533
|
:open_key => subkey_handle,
|
538
|
-
:query_value =>
|
534
|
+
:query_value => reg_value,
|
539
535
|
:close_key => nil
|
540
536
|
)
|
541
537
|
end
|
@@ -572,7 +568,7 @@ RSpec.describe RubySMB::Dcerpc::Winreg do
|
|
572
568
|
end
|
573
569
|
|
574
570
|
it 'returns expect registry key value' do
|
575
|
-
expect(winreg.read_registry_key_value(key, value_name)).to eq(
|
571
|
+
expect(winreg.read_registry_key_value(key, value_name)).to eq(data)
|
576
572
|
end
|
577
573
|
end
|
578
574
|
|
@@ -864,4 +860,257 @@ RSpec.describe RubySMB::Dcerpc::Winreg do
|
|
864
860
|
end
|
865
861
|
end
|
866
862
|
end
|
863
|
+
|
864
|
+
describe '#get_key_security_descriptor' do
|
865
|
+
let(:root_key) { 'HKLM' }
|
866
|
+
let(:sub_key) { 'my\\sub\\key\\path' }
|
867
|
+
let(:key) { "#{root_key}\\#{sub_key}" }
|
868
|
+
let(:root_key_handle) { double('Root Key Handle') }
|
869
|
+
let(:subkey_handle) { double('Subkey Handle') }
|
870
|
+
before :example do
|
871
|
+
allow(winreg).to receive_messages(
|
872
|
+
:bind => nil,
|
873
|
+
:open_root_key => root_key_handle,
|
874
|
+
:open_key => subkey_handle,
|
875
|
+
:get_key_security => nil,
|
876
|
+
:close_key => nil
|
877
|
+
)
|
878
|
+
end
|
879
|
+
|
880
|
+
it 'binds a DCERPC connection to the expected remote endpoint' do
|
881
|
+
winreg.get_key_security_descriptor(key)
|
882
|
+
expect(winreg).to have_received(:bind).with(endpoint: RubySMB::Dcerpc::Winreg)
|
883
|
+
end
|
884
|
+
|
885
|
+
it 'does not bind a DCERPC connection if #bind argument is false' do
|
886
|
+
winreg.get_key_security_descriptor(key, bind: false)
|
887
|
+
expect(winreg).to_not have_received(:bind)
|
888
|
+
end
|
889
|
+
|
890
|
+
it 'opens the expected root key' do
|
891
|
+
winreg.get_key_security_descriptor(key)
|
892
|
+
expect(winreg).to have_received(:open_root_key).with(root_key)
|
893
|
+
end
|
894
|
+
|
895
|
+
it 'opens the expected registry key' do
|
896
|
+
winreg.get_key_security_descriptor(key)
|
897
|
+
expect(winreg).to have_received(:open_key).with(root_key_handle, sub_key)
|
898
|
+
end
|
899
|
+
|
900
|
+
it 'calls #get_key_security with the expected arguments' do
|
901
|
+
winreg.get_key_security_descriptor(key)
|
902
|
+
security_information = RubySMB::Field::SecurityDescriptor::OWNER_SECURITY_INFORMATION
|
903
|
+
expect(winreg).to have_received(:get_key_security).with(subkey_handle, security_information)
|
904
|
+
end
|
905
|
+
|
906
|
+
context 'with a non-default security informaiton' do
|
907
|
+
it 'calls #get_key_security with the expected arguments' do
|
908
|
+
security_information = RubySMB::Field::SecurityDescriptor::GROUP_SECURITY_INFORMATION
|
909
|
+
winreg.get_key_security_descriptor(key, security_information)
|
910
|
+
expect(winreg).to have_received(:get_key_security).with(subkey_handle, security_information)
|
911
|
+
end
|
912
|
+
end
|
913
|
+
end
|
914
|
+
|
915
|
+
describe '#get_key_security' do
|
916
|
+
let(:handle) { double('Handle') }
|
917
|
+
let(:get_key_security_request) { double('GetKeySecurity Request') }
|
918
|
+
let(:response) {
|
919
|
+
'0000020000100000940000000010000000000000940000000100048078000000880000'\
|
920
|
+
'0000000000140000000200640004000000000214003f000f0001010000000000051200'\
|
921
|
+
'0000000218000000060001020000000000052000000020020000000218000900060001'\
|
922
|
+
'0200000000000520000000200200000002180009000600010200000000000520000000'\
|
923
|
+
'2002000001020000000000052000000020020000010100000000000512000000000000'\
|
924
|
+
'00'.unhexlify
|
925
|
+
}
|
926
|
+
let(:security_descriptor) {
|
927
|
+
'01000480780000008800000000000000140000000200640004000000000214003f000f'\
|
928
|
+
'0001010000000000051200000000021800000006000102000000000005200000002002'\
|
929
|
+
'0000000218000900060001020000000000052000000020020000000218000900060001'\
|
930
|
+
'0200000000000520000000200200000102000000000005200000002002000001010000'\
|
931
|
+
'0000000512000000'.unhexlify
|
932
|
+
}
|
933
|
+
before :example do
|
934
|
+
allow(described_class::GetKeySecurityRequest).to receive(:new).and_return(get_key_security_request)
|
935
|
+
allow(winreg).to receive(:dcerpc_request).and_return(response)
|
936
|
+
end
|
937
|
+
|
938
|
+
it 'create the expected GetKeySecurityRequest packet with the default options' do
|
939
|
+
opts = {
|
940
|
+
hkey: handle,
|
941
|
+
security_information: RubySMB::Field::SecurityDescriptor::OWNER_SECURITY_INFORMATION,
|
942
|
+
prpc_security_descriptor_in: { cb_in_security_descriptor: 4096 }
|
943
|
+
}
|
944
|
+
winreg.get_key_security(handle)
|
945
|
+
expect(described_class::GetKeySecurityRequest).to have_received(:new).with(opts)
|
946
|
+
end
|
947
|
+
|
948
|
+
it 'create the expected SaveKeyRequest packet with custom options' do
|
949
|
+
security_information = RubySMB::Field::SecurityDescriptor::GROUP_SECURITY_INFORMATION
|
950
|
+
opts = {
|
951
|
+
hkey: handle,
|
952
|
+
security_information: security_information,
|
953
|
+
prpc_security_descriptor_in: { cb_in_security_descriptor: 4096 }
|
954
|
+
}
|
955
|
+
winreg.get_key_security(handle, security_information)
|
956
|
+
expect(described_class::GetKeySecurityRequest).to have_received(:new).with(opts)
|
957
|
+
end
|
958
|
+
|
959
|
+
it 'sends the expected dcerpc request' do
|
960
|
+
winreg.get_key_security(handle)
|
961
|
+
expect(winreg).to have_received(:dcerpc_request).with(get_key_security_request)
|
962
|
+
end
|
963
|
+
|
964
|
+
it 'creates a GetKeySecurityResponse structure from the expected dcerpc response' do
|
965
|
+
expect(described_class::GetKeySecurityResponse).to receive(:read).with(response).and_call_original
|
966
|
+
winreg.get_key_security(handle)
|
967
|
+
end
|
968
|
+
|
969
|
+
context 'when an IOError occurs while parsing the response' do
|
970
|
+
it 'raises a RubySMB::Dcerpc::Error::InvalidPacket' do
|
971
|
+
allow(described_class::GetKeySecurityResponse).to receive(:read).and_raise(IOError)
|
972
|
+
expect { winreg.get_key_security(handle) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
|
973
|
+
end
|
974
|
+
end
|
975
|
+
|
976
|
+
context 'when the response error status is not WindowsError::Win32::ERROR_SUCCESS' do
|
977
|
+
it 'raises a RubySMB::Dcerpc::Error::WinregError' do
|
978
|
+
response[-4..-1] = [WindowsError::Win32::ERROR_INVALID_DATA.value].pack('V')
|
979
|
+
expect { winreg.get_key_security(handle) }.to raise_error(RubySMB::Dcerpc::Error::WinregError)
|
980
|
+
end
|
981
|
+
end
|
982
|
+
|
983
|
+
it 'returns the expected security descriptor' do
|
984
|
+
expect(winreg.get_key_security(handle)).to eq(security_descriptor)
|
985
|
+
end
|
986
|
+
end
|
987
|
+
|
988
|
+
describe '#set_key_security_descriptor' do
|
989
|
+
let(:root_key) { 'HKLM' }
|
990
|
+
let(:sub_key) { 'my\\sub\\key\\path' }
|
991
|
+
let(:key) { "#{root_key}\\#{sub_key}" }
|
992
|
+
let(:security_descriptor) { 'Security Descriptor' }
|
993
|
+
let(:root_key_handle) { double('Root Key Handle') }
|
994
|
+
let(:subkey_handle) { double('Subkey Handle') }
|
995
|
+
before :example do
|
996
|
+
allow(winreg).to receive_messages(
|
997
|
+
:bind => nil,
|
998
|
+
:open_root_key => root_key_handle,
|
999
|
+
:open_key => subkey_handle,
|
1000
|
+
:set_key_security => nil,
|
1001
|
+
:close_key => nil
|
1002
|
+
)
|
1003
|
+
end
|
1004
|
+
|
1005
|
+
it 'binds a DCERPC connection to the expected remote endpoint' do
|
1006
|
+
winreg.set_key_security_descriptor(key, security_descriptor)
|
1007
|
+
expect(winreg).to have_received(:bind).with(endpoint: RubySMB::Dcerpc::Winreg)
|
1008
|
+
end
|
1009
|
+
|
1010
|
+
it 'does not bind a DCERPC connection if #bind argument is false' do
|
1011
|
+
winreg.set_key_security_descriptor(key, security_descriptor, bind: false)
|
1012
|
+
expect(winreg).to_not have_received(:bind)
|
1013
|
+
end
|
1014
|
+
|
1015
|
+
it 'opens the expected root key' do
|
1016
|
+
winreg.set_key_security_descriptor(key, security_descriptor)
|
1017
|
+
expect(winreg).to have_received(:open_root_key).with(root_key)
|
1018
|
+
end
|
1019
|
+
|
1020
|
+
it 'opens the expected registry key' do
|
1021
|
+
winreg.set_key_security_descriptor(key, security_descriptor)
|
1022
|
+
expect(winreg).to have_received(:open_key).with(root_key_handle, sub_key)
|
1023
|
+
end
|
1024
|
+
|
1025
|
+
it 'calls #set_key_security with the expected arguments' do
|
1026
|
+
winreg.set_key_security_descriptor(key, security_descriptor)
|
1027
|
+
security_information = RubySMB::Field::SecurityDescriptor::OWNER_SECURITY_INFORMATION
|
1028
|
+
expect(winreg).to have_received(:set_key_security).with(subkey_handle, security_descriptor, security_information)
|
1029
|
+
end
|
1030
|
+
|
1031
|
+
context 'with a non-default security informaiton' do
|
1032
|
+
it 'calls #get_key_security with the expected arguments' do
|
1033
|
+
security_information = RubySMB::Field::SecurityDescriptor::GROUP_SECURITY_INFORMATION
|
1034
|
+
winreg.set_key_security_descriptor(key, security_descriptor, security_information)
|
1035
|
+
expect(winreg).to have_received(:set_key_security).with(subkey_handle, security_descriptor, security_information)
|
1036
|
+
end
|
1037
|
+
end
|
1038
|
+
end
|
1039
|
+
|
1040
|
+
describe '#set_key_security' do
|
1041
|
+
let(:handle) { double('Handle') }
|
1042
|
+
let(:set_key_security_request) { double('GetKeySecurity Request') }
|
1043
|
+
let(:response) { '00000000'.unhexlify }
|
1044
|
+
let(:security_descriptor) {
|
1045
|
+
'0100048014000000240000000000000030000000010200000000000520000000200200'\
|
1046
|
+
'0001010000000000051200000002007c0005000000000214003f000f00010100000000'\
|
1047
|
+
'0005120000000002180000000600010200000000000520000000200200000002180009'\
|
1048
|
+
'0006000102000000000005200000002002000000021800090006000102000000000005'\
|
1049
|
+
'2000000020020000000218000900060001020000000000052000000020020000'.unhexlify
|
1050
|
+
}
|
1051
|
+
before :example do
|
1052
|
+
allow(described_class::SetKeySecurityRequest).to receive(:new).and_return(set_key_security_request)
|
1053
|
+
allow(winreg).to receive(:dcerpc_request).and_return(response)
|
1054
|
+
end
|
1055
|
+
|
1056
|
+
it 'create the expected SetKeySecurityRequest packet with the default options' do
|
1057
|
+
opts = {
|
1058
|
+
hkey: handle,
|
1059
|
+
security_information: RubySMB::Field::SecurityDescriptor::OWNER_SECURITY_INFORMATION,
|
1060
|
+
prpc_security_descriptor: {
|
1061
|
+
lp_security_descriptor: security_descriptor.bytes,
|
1062
|
+
cb_in_security_descriptor: security_descriptor.size,
|
1063
|
+
cb_out_security_descriptor: security_descriptor.size
|
1064
|
+
}
|
1065
|
+
}
|
1066
|
+
winreg.set_key_security(handle, security_descriptor)
|
1067
|
+
expect(described_class::SetKeySecurityRequest).to have_received(:new).with(opts)
|
1068
|
+
end
|
1069
|
+
|
1070
|
+
it 'create the expected SaveKeyRequest packet with custom options' do
|
1071
|
+
security_information = RubySMB::Field::SecurityDescriptor::GROUP_SECURITY_INFORMATION
|
1072
|
+
opts = {
|
1073
|
+
hkey: handle,
|
1074
|
+
security_information: security_information,
|
1075
|
+
prpc_security_descriptor: {
|
1076
|
+
lp_security_descriptor: security_descriptor.bytes,
|
1077
|
+
cb_in_security_descriptor: security_descriptor.size,
|
1078
|
+
cb_out_security_descriptor: security_descriptor.size
|
1079
|
+
}
|
1080
|
+
}
|
1081
|
+
winreg.set_key_security(handle, security_descriptor, security_information)
|
1082
|
+
expect(described_class::SetKeySecurityRequest).to have_received(:new).with(opts)
|
1083
|
+
end
|
1084
|
+
|
1085
|
+
it 'sends the expected dcerpc request' do
|
1086
|
+
winreg.set_key_security(handle, security_descriptor)
|
1087
|
+
expect(winreg).to have_received(:dcerpc_request).with(set_key_security_request)
|
1088
|
+
end
|
1089
|
+
|
1090
|
+
it 'creates a SetKeySecurityResponse structure from the expected dcerpc response' do
|
1091
|
+
expect(described_class::SetKeySecurityResponse).to receive(:read).with(response).and_call_original
|
1092
|
+
winreg.set_key_security(handle, security_descriptor)
|
1093
|
+
end
|
1094
|
+
|
1095
|
+
context 'when an IOError occurs while parsing the response' do
|
1096
|
+
it 'raises a RubySMB::Dcerpc::Error::InvalidPacket' do
|
1097
|
+
allow(described_class::SetKeySecurityResponse).to receive(:read).and_raise(IOError)
|
1098
|
+
expect { winreg.set_key_security(handle, security_descriptor) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
|
1099
|
+
end
|
1100
|
+
end
|
1101
|
+
|
1102
|
+
context 'when the response error status is not WindowsError::Win32::ERROR_SUCCESS' do
|
1103
|
+
it 'raises a RubySMB::Dcerpc::Error::WinregError' do
|
1104
|
+
response[-4..-1] = [WindowsError::Win32::ERROR_INVALID_DATA.value].pack('V')
|
1105
|
+
expect { winreg.set_key_security(handle, security_descriptor) }.to raise_error(RubySMB::Dcerpc::Error::WinregError)
|
1106
|
+
end
|
1107
|
+
end
|
1108
|
+
|
1109
|
+
it 'returns the expected error status' do
|
1110
|
+
expect(winreg.set_key_security(handle, security_descriptor)).to eq(WindowsError::Win32::ERROR_SUCCESS)
|
1111
|
+
end
|
1112
|
+
end
|
1113
|
+
|
1114
|
+
|
1115
|
+
|
867
1116
|
end
|
data.tar.gz.sig
CHANGED
Binary file
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby_smb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.3.
|
4
|
+
version: 3.3.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Metasploit Hackers
|
@@ -38,7 +38,7 @@ cert_chain:
|
|
38
38
|
DgscAao7wB3xW2BWEp1KnaDWkf1x9ttgoBEYyuYwU7uatB67kBQG1PKvLt79wHvz
|
39
39
|
Dxs+KOjGbBRfMnPgVGYkORKVrZIwlaboHbDKxcVW5xv+oZc7KYXWGg==
|
40
40
|
-----END CERTIFICATE-----
|
41
|
-
date: 2024-04-
|
41
|
+
date: 2024-04-30 00:00:00.000000000 Z
|
42
42
|
dependencies:
|
43
43
|
- !ruby/object:Gem::Dependency
|
44
44
|
name: redcarpet
|
@@ -219,6 +219,7 @@ files:
|
|
219
219
|
- examples/read_file.rb
|
220
220
|
- examples/read_file_encryption.rb
|
221
221
|
- examples/read_registry_key_value.rb
|
222
|
+
- examples/registry_key_security_descriptor.rb
|
222
223
|
- examples/rename_file.rb
|
223
224
|
- examples/tree_connect.rb
|
224
225
|
- examples/virtual_file_server.rb
|
@@ -375,6 +376,8 @@ files:
|
|
375
376
|
- lib/ruby_smb/dcerpc/winreg/enum_key_response.rb
|
376
377
|
- lib/ruby_smb/dcerpc/winreg/enum_value_request.rb
|
377
378
|
- lib/ruby_smb/dcerpc/winreg/enum_value_response.rb
|
379
|
+
- lib/ruby_smb/dcerpc/winreg/get_key_security_request.rb
|
380
|
+
- lib/ruby_smb/dcerpc/winreg/get_key_security_response.rb
|
378
381
|
- lib/ruby_smb/dcerpc/winreg/open_key_request.rb
|
379
382
|
- lib/ruby_smb/dcerpc/winreg/open_key_response.rb
|
380
383
|
- lib/ruby_smb/dcerpc/winreg/open_root_key_request.rb
|
@@ -386,6 +389,8 @@ files:
|
|
386
389
|
- lib/ruby_smb/dcerpc/winreg/regsam.rb
|
387
390
|
- lib/ruby_smb/dcerpc/winreg/save_key_request.rb
|
388
391
|
- lib/ruby_smb/dcerpc/winreg/save_key_response.rb
|
392
|
+
- lib/ruby_smb/dcerpc/winreg/set_key_security_request.rb
|
393
|
+
- lib/ruby_smb/dcerpc/winreg/set_key_security_response.rb
|
389
394
|
- lib/ruby_smb/dcerpc/wkssvc.rb
|
390
395
|
- lib/ruby_smb/dcerpc/wkssvc/netr_wksta_get_info_request.rb
|
391
396
|
- lib/ruby_smb/dcerpc/wkssvc/netr_wksta_get_info_response.rb
|
@@ -959,7 +964,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
959
964
|
- !ruby/object:Gem::Version
|
960
965
|
version: '0'
|
961
966
|
requirements: []
|
962
|
-
rubygems_version: 3.4
|
967
|
+
rubygems_version: 3.1.4
|
963
968
|
signing_key:
|
964
969
|
specification_version: 4
|
965
970
|
summary: A pure Ruby implementation of the SMB Protocol Family
|
metadata.gz.sig
CHANGED
Binary file
|