ruby_smb 3.3.12 → 3.3.14
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
- data/cortex.yaml +2 -0
- data/lib/ruby_smb/dcerpc/error.rb +10 -0
- data/lib/ruby_smb/dcerpc/gkdi/gkdi_ffc_dh_key.rb +17 -0
- data/lib/ruby_smb/dcerpc/gkdi/gkdi_ffc_dh_parameters.rb +17 -0
- data/lib/ruby_smb/dcerpc/gkdi/gkdi_get_key_request.rb +26 -0
- data/lib/ruby_smb/dcerpc/gkdi/gkdi_get_key_response.rb +23 -0
- data/lib/ruby_smb/dcerpc/gkdi/gkdi_group_key_envelope.rb +51 -0
- data/lib/ruby_smb/dcerpc/gkdi.rb +54 -0
- data/lib/ruby_smb/dcerpc/request.rb +5 -0
- data/lib/ruby_smb/dcerpc/samr/samr_change_password_user_request.rb +31 -0
- data/lib/ruby_smb/dcerpc/samr/samr_change_password_user_response.rb +21 -0
- data/lib/ruby_smb/dcerpc/samr/samr_get_members_in_group_response.rb +1 -1
- data/lib/ruby_smb/dcerpc/samr/samr_unicode_change_password_user2_request.rb +27 -0
- data/lib/ruby_smb/dcerpc/samr/samr_unicode_change_password_user2_response.rb +21 -0
- data/lib/ruby_smb/dcerpc/samr.rb +213 -3
- data/lib/ruby_smb/dcerpc.rb +1 -0
- data/lib/ruby_smb/version.rb +1 -1
- data/spec/lib/ruby_smb/dcerpc/samr/encrypted_nt_owf_password_spec.rb +10 -0
- data/spec/lib/ruby_smb/dcerpc/samr/sampr_encrypted_user_password_spec.rb +9 -0
- data/spec/lib/ruby_smb/dcerpc/samr/samr_change_password_user_request_spec.rb +28 -0
- data/spec/lib/ruby_smb/dcerpc/samr/samr_change_password_user_response_spec.rb +16 -0
- data/spec/lib/ruby_smb/dcerpc/samr/samr_unicode_change_password_user2_request_spec.rb +22 -0
- data/spec/lib/ruby_smb/dcerpc/samr/samr_unicode_change_password_user2_response_spec.rb +16 -0
- data/spec/lib/ruby_smb/dcerpc/samr/user_properties_spec.rb +76 -0
- metadata +31 -33
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- 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: c0e82037a7cede300c72e18aca227e16dd6f6c67c46e739aae546ff990562a20
|
4
|
+
data.tar.gz: ac24976008cf479989fbea0edc88ceafec163c998a7d5a87ea4b085ae1f6fcd6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c9f2bae08d955e0a977b5614a577ff1801f8b977a675f21a70ec7dac2b695d6215d91cd3f69b37b354022aba93494be64687b90e96c8a7b75390384eb7dd0b99
|
7
|
+
data.tar.gz: de80907d4e9d1d91de05ca1b363ba94da81f2f39fd089bad724d1b6c2b5fae8ed8048b66ac84238174f573dbb362e49d809734446e5381b1914bc5cd9b8286ce
|
data/cortex.yaml
CHANGED
@@ -70,6 +70,16 @@ module RubySMB
|
|
70
70
|
super(msg)
|
71
71
|
end
|
72
72
|
end
|
73
|
+
|
74
|
+
class GkdiError < DcerpcError
|
75
|
+
include RubySMB::Error::UnexpectedStatusCode::Mixin
|
76
|
+
|
77
|
+
def initialize(msg, status_code: nil)
|
78
|
+
self.status_code = status_code unless status_code.nil?
|
79
|
+
|
80
|
+
super(msg)
|
81
|
+
end
|
82
|
+
end
|
73
83
|
end
|
74
84
|
end
|
75
85
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module RubySMB
|
2
|
+
module Dcerpc
|
3
|
+
module Gkdi
|
4
|
+
|
5
|
+
# [2.2.3.1 FFC DH Key](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-gkdi/f8770f01-036d-4bf6-a4cf-1bd0e3913404)
|
6
|
+
class GkdiFfcDhKey < BinData::Record
|
7
|
+
endian :little
|
8
|
+
|
9
|
+
uint8_array :magic, initial_length: 4, initial_value: [ 0x44, 0x48, 0x50, 0x42 ]
|
10
|
+
uint32 :key_length
|
11
|
+
uint8_array :field_order, initial_length: :key_length
|
12
|
+
uint8_array :generator, initial_length: :key_length
|
13
|
+
uint8_array :public_key, initial_length: :key_length
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module RubySMB
|
2
|
+
module Dcerpc
|
3
|
+
module Gkdi
|
4
|
+
|
5
|
+
# [2.2.2 FFC DH Parameters](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-gkdi/e15ae269-ee21-446a-a480-de3ea243db5f)
|
6
|
+
class GkdiFfcDhParameters < BinData::Record
|
7
|
+
endian :little
|
8
|
+
|
9
|
+
uint32 :parameters_length, initial_value: -> { (key_length * 2) + offset_of(generator) }
|
10
|
+
uint8_array :magic, initial_length: 4, initial_value: [ 0x44, 0x48, 0x50, 0x4d ]
|
11
|
+
uint32 :key_length
|
12
|
+
uint8_array :field_order, initial_length: :key_length
|
13
|
+
uint8_array :generator, initial_length: :key_length
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module RubySMB
|
2
|
+
module Dcerpc
|
3
|
+
module Gkdi
|
4
|
+
|
5
|
+
# [3.1.4.1 GetKey (Opnum 0)](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-gkdi/4cac87a3-521e-4918-a272-240f8fabed39)
|
6
|
+
class GkdiGetKeyRequest < BinData::Record
|
7
|
+
attr_reader :opnum
|
8
|
+
|
9
|
+
endian :little
|
10
|
+
|
11
|
+
ndr_uint32 :cb_target_sd
|
12
|
+
ndr_conf_array :pb_target_sd, type: :ndr_uint8
|
13
|
+
uuid_ptr :p_root_key_id
|
14
|
+
ndr_int32 :l0_key_id
|
15
|
+
ndr_int32 :l1_key_id
|
16
|
+
ndr_int32 :l2_key_id
|
17
|
+
|
18
|
+
def initialize_instance
|
19
|
+
super
|
20
|
+
@opnum = GKDI_GET_KEY
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module RubySMB
|
2
|
+
module Dcerpc
|
3
|
+
module Gkdi
|
4
|
+
|
5
|
+
# [3.1.4.1 GetKey (Opnum 0)](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-gkdi/4cac87a3-521e-4918-a272-240f8fabed39)
|
6
|
+
class GkdiGetKeyResponse < BinData::Record
|
7
|
+
attr_reader :opnum
|
8
|
+
|
9
|
+
endian :little
|
10
|
+
|
11
|
+
ndr_uint32 :pcb_out
|
12
|
+
ndr_byte_conf_array_ptr :pbb_out
|
13
|
+
ndr_uint32 :error_status
|
14
|
+
|
15
|
+
def initialize_instance
|
16
|
+
super
|
17
|
+
@opnum = GKDI_GET_KEY
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module RubySMB
|
2
|
+
module Dcerpc
|
3
|
+
module Gkdi
|
4
|
+
|
5
|
+
# [2.2.4 Group Key Envelope](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-gkdi/192c061c-e740-4aa0-ab1d-6954fb3e58f7)
|
6
|
+
class GkdiGroupKeyEnvelope < BinData::Record
|
7
|
+
endian :little
|
8
|
+
|
9
|
+
uint32 :version
|
10
|
+
uint8_array :magic, initial_length: 4, initial_value: [ 0x4b, 0x44, 0x53, 0x5b ]
|
11
|
+
uint32 :dw_flags
|
12
|
+
uint32 :l0_index
|
13
|
+
uint32 :l1_index
|
14
|
+
uint32 :l2_index
|
15
|
+
uuid :root_key_identifier
|
16
|
+
uint32 :cb_kdf_algorithm
|
17
|
+
uint32 :cb_kdf_parameters, initial_value: -> { kdf_parameters.length }
|
18
|
+
uint32 :cb_secret_agreement_algorithm
|
19
|
+
uint32 :cb_secret_agreement_parameters
|
20
|
+
uint32 :private_key_length
|
21
|
+
uint32 :public_key_length
|
22
|
+
uint32 :cb_l1_key
|
23
|
+
uint32 :cb_l2_key
|
24
|
+
uint32 :cb_domain_name
|
25
|
+
uint32 :cb_forest_name
|
26
|
+
stringz16 :kdf_algorithm
|
27
|
+
struct :kdf_parameters, only_if: -> { cb_kdf_parameters > 0 } do
|
28
|
+
uint8_array :block0, initial_length: 8, initial_value: [ 0, 0, 0, 0, 1, 0, 0, 0 ]
|
29
|
+
uint32 :length_of_hash_name, initial_value: -> { hash_algorithm_name.length }
|
30
|
+
uint8_array :block1, initial_length: 4, initial_value: [ 0, 0, 0, 0 ]
|
31
|
+
stringz16 :hash_algorithm_name
|
32
|
+
end
|
33
|
+
stringz16 :secret_agreement_algorithm
|
34
|
+
uint8_array :secret_agreement_parameters, initial_length: :cb_secret_agreement_parameters
|
35
|
+
stringz16 :domain_name
|
36
|
+
stringz16 :forest_name
|
37
|
+
uint8_array :l1_key, initial_length: 64, only_if: -> { cb_l1_key != 0 }
|
38
|
+
uint8_array :l2_key, initial_length: :l2_key_length, only_if: -> { cb_l2_key != 0 }
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def l2_key_length
|
43
|
+
return 0 if cb_l2_key == 0
|
44
|
+
return 64 if (dw_flags & (1 << 31)) == 0
|
45
|
+
|
46
|
+
public_key_length
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module RubySMB
|
2
|
+
module Dcerpc
|
3
|
+
module Gkdi
|
4
|
+
|
5
|
+
# [2.1 Transport](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-gkdi/2ca63ad2-2464-4a41-ba84-2e0270e95e86)
|
6
|
+
UUID = 'b9785960-524f-11df-8b6d-83dcded72085'
|
7
|
+
VER_MAJOR = 1
|
8
|
+
VER_MINOR = 0
|
9
|
+
|
10
|
+
# Operation numbers
|
11
|
+
GKDI_GET_KEY = 0x0000
|
12
|
+
|
13
|
+
require 'ruby_smb/dcerpc/gkdi/gkdi_get_key_request'
|
14
|
+
require 'ruby_smb/dcerpc/gkdi/gkdi_get_key_response'
|
15
|
+
require 'ruby_smb/dcerpc/gkdi/gkdi_ffc_dh_key'
|
16
|
+
require 'ruby_smb/dcerpc/gkdi/gkdi_ffc_dh_parameters'
|
17
|
+
require 'ruby_smb/dcerpc/gkdi/gkdi_group_key_envelope'
|
18
|
+
|
19
|
+
def gkdi_get_key(target_sd, root_key_id, l0_key_id, l1_key_id, l2_key_id)
|
20
|
+
target_sd = target_sd.to_binary_s if target_sd.respond_to?(:to_binary_s)
|
21
|
+
|
22
|
+
gkdi_get_key_request = GkdiGetKeyRequest.new(
|
23
|
+
cb_target_sd: target_sd.length,
|
24
|
+
pb_target_sd: target_sd.unpack('C*'),
|
25
|
+
p_root_key_id: root_key_id,
|
26
|
+
l0_key_id: l0_key_id,
|
27
|
+
l1_key_id: l1_key_id,
|
28
|
+
l2_key_id: l2_key_id
|
29
|
+
)
|
30
|
+
|
31
|
+
response = dcerpc_request(
|
32
|
+
gkdi_get_key_request,
|
33
|
+
auth_level: @auth_level,
|
34
|
+
auth_type: @auth_type
|
35
|
+
)
|
36
|
+
begin
|
37
|
+
gkdi_get_key_response = GkdiGetKeyResponse.read(response)
|
38
|
+
rescue IOError
|
39
|
+
raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading CertServerRequestResponse'
|
40
|
+
end
|
41
|
+
unless gkdi_get_key_response.error_status == WindowsError::NTStatus::STATUS_SUCCESS
|
42
|
+
status_code = WindowsError::Win32.find_by_retval(gkdi_get_key_response.error_status.value).first
|
43
|
+
raise RubySMB::Dcerpc::Error::GkdiError.new(
|
44
|
+
"Error returned with gkdi_get_key: #{status_code}",
|
45
|
+
status_code: status_code
|
46
|
+
)
|
47
|
+
end
|
48
|
+
|
49
|
+
GkdiGroupKeyEnvelope.read(gkdi_get_key_response.pbb_out.snapshot.pack('C*'))
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -79,6 +79,8 @@ module RubySMB
|
|
79
79
|
samr_set_information_user2_request Samr::SAMR_SET_INFORMATION_USER2
|
80
80
|
samr_delete_user_request Samr::SAMR_DELETE_USER
|
81
81
|
samr_query_information_domain_request Samr::SAMR_QUERY_INFORMATION_DOMAIN
|
82
|
+
samr_unicode_change_password_user2_request Samr::SAMR_UNICODE_CHANGE_PASSWORD_USER2
|
83
|
+
samr_change_password_user_request Samr::SAMR_CHANGE_PASSWORD_USER
|
82
84
|
string :default
|
83
85
|
end
|
84
86
|
choice 'Wkssvc', selection: -> { opnum } do
|
@@ -122,6 +124,9 @@ module RubySMB
|
|
122
124
|
lsar_close_handle_request Lsarpc::LSAR_CLOSE_HANDLE
|
123
125
|
lsar_lookup_sids_request Lsarpc::LSAR_LOOKUP_SIDS
|
124
126
|
end
|
127
|
+
choice 'Gkdi', selection: -> { opnum } do
|
128
|
+
gkdi_get_key_request Gkdi::GKDI_GET_KEY
|
129
|
+
end
|
125
130
|
string :default
|
126
131
|
end
|
127
132
|
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module RubySMB
|
2
|
+
module Dcerpc
|
3
|
+
module Samr
|
4
|
+
|
5
|
+
# [3.1.5.10.1 SamrChangePasswordUser (Opnum 38)](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/9699d8ca-e1a4-433c-a8c3-d7bebeb01476)
|
6
|
+
class SamrChangePasswordUserRequest < BinData::Record
|
7
|
+
attr_reader :opnum
|
8
|
+
|
9
|
+
endian :little
|
10
|
+
|
11
|
+
sampr_handle :user_handle
|
12
|
+
ndr_uint8 :lm_present
|
13
|
+
pencrypted_nt_owf_password :old_lm_encrypted_with_new_lm
|
14
|
+
pencrypted_nt_owf_password :new_lm_encrypted_with_old_lm
|
15
|
+
ndr_uint8 :nt_present
|
16
|
+
pencrypted_nt_owf_password :old_nt_encrypted_with_new_nt
|
17
|
+
pencrypted_nt_owf_password :new_nt_encrypted_with_old_nt
|
18
|
+
ndr_uint8 :nt_cross_encryption_present
|
19
|
+
pencrypted_nt_owf_password :new_nt_encrypted_with_new_nt
|
20
|
+
ndr_uint8 :lm_cross_encryption_present
|
21
|
+
pencrypted_nt_owf_password :new_lm_encrypted_with_new_nt
|
22
|
+
|
23
|
+
def initialize_instance
|
24
|
+
super
|
25
|
+
@opnum = SAMR_CHANGE_PASSWORD_USER
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module RubySMB
|
2
|
+
module Dcerpc
|
3
|
+
module Samr
|
4
|
+
|
5
|
+
# [3.1.5.10.1 SamrChangePasswordUser (Opnum 38)](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/9699d8ca-e1a4-433c-a8c3-d7bebeb01476)
|
6
|
+
class SamrChangePasswordUserResponse < BinData::Record
|
7
|
+
attr_reader :opnum
|
8
|
+
|
9
|
+
endian :little
|
10
|
+
|
11
|
+
ndr_uint32 :error_status
|
12
|
+
|
13
|
+
def initialize_instance
|
14
|
+
super
|
15
|
+
@opnum = SAMR_CHANGE_PASSWORD_USER
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -14,7 +14,7 @@ module RubySMB
|
|
14
14
|
extend Ndr::PointerClassPlugin
|
15
15
|
end
|
16
16
|
|
17
|
-
# [
|
17
|
+
# [3.1.5.8.3 SamrGetMembersInGroup (Opnum 25)](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/3ed5030d-88a3-42ca-a6e0-8c12aa2fdfbd)
|
18
18
|
class SamrGetMembersInGroupResponse < BinData::Record
|
19
19
|
attr_reader :opnum
|
20
20
|
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module RubySMB
|
2
|
+
module Dcerpc
|
3
|
+
module Samr
|
4
|
+
|
5
|
+
# [3.1.5.10.3 SamrUnicodeChangePasswordUser2 (Opnum 55)](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/acb3204a-da8b-478e-9139-1ea589edb880)
|
6
|
+
class SamrUnicodeChangePasswordUser2Request < BinData::Record
|
7
|
+
attr_reader :opnum
|
8
|
+
|
9
|
+
endian :little
|
10
|
+
|
11
|
+
prpc_unicode_string :server_name
|
12
|
+
rpc_unicode_string :user_name
|
13
|
+
psampr_encrypted_user_password :new_password_encrypted_with_old_nt
|
14
|
+
pencrypted_nt_owf_password :old_nt_owf_password_encrypted_with_new_nt
|
15
|
+
ndr_uint8 :lm_present
|
16
|
+
psampr_encrypted_user_password :new_password_encrypted_with_old_lm
|
17
|
+
pencrypted_nt_owf_password :old_lm_owf_password_encrypted_with_new_nt
|
18
|
+
|
19
|
+
def initialize_instance
|
20
|
+
super
|
21
|
+
@opnum = SAMR_UNICODE_CHANGE_PASSWORD_USER2
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module RubySMB
|
2
|
+
module Dcerpc
|
3
|
+
module Samr
|
4
|
+
|
5
|
+
# [3.1.5.10.3 SamrUnicodeChangePasswordUser2 (Opnum 55)](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/acb3204a-da8b-478e-9139-1ea589edb880)
|
6
|
+
class SamrUnicodeChangePasswordUser2Response < BinData::Record
|
7
|
+
attr_reader :opnum
|
8
|
+
|
9
|
+
endian :little
|
10
|
+
|
11
|
+
ndr_uint32 :error_status
|
12
|
+
|
13
|
+
def initialize_instance
|
14
|
+
super
|
15
|
+
@opnum = SAMR_UNICODE_CHANGE_PASSWORD_USER2
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/ruby_smb/dcerpc/samr.rb
CHANGED
@@ -24,8 +24,10 @@ module RubySMB
|
|
24
24
|
SAMR_GET_MEMBERS_IN_GROUP = 0x0019
|
25
25
|
SAMR_OPEN_USER = 0x0022
|
26
26
|
SAMR_DELETE_USER = 0x0023
|
27
|
+
SAMR_CHANGE_PASSWORD_USER = 0x0026
|
27
28
|
SAMR_GET_GROUPS_FOR_USER = 0x0027
|
28
29
|
SAMR_CREATE_USER2_IN_DOMAIN = 0x0032
|
30
|
+
SAMR_UNICODE_CHANGE_PASSWORD_USER2 = 0x0037
|
29
31
|
SAMR_SET_INFORMATION_USER2 = 0x003a
|
30
32
|
SAMR_CONNECT5 = 0x0040
|
31
33
|
SAMR_RID_TO_SID = 0x0041
|
@@ -318,6 +320,58 @@ module RubySMB
|
|
318
320
|
extend Ndr::PointerClassPlugin
|
319
321
|
end
|
320
322
|
|
323
|
+
# [2.2.7.3 ENCRYPTED_NT_OWF_PASSWORD](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/ce061fef-6d4f-4802-bd5d-26b11f14f4a6)
|
324
|
+
class EncryptedNtOwfPassword < Ndr::NdrStruct
|
325
|
+
default_parameter byte_align: 4
|
326
|
+
ndr_fixed_byte_array :buffer, initial_length: 16
|
327
|
+
|
328
|
+
# [2.2.11.1.2 Encrypting a 64-bit block with a 7-byte key](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/ebdb15df-8d0d-4347-9d62-082e6eccac40)
|
329
|
+
def self.to_output_key(input_key)
|
330
|
+
output_key = []
|
331
|
+
input_key = input_key.unpack('C'*7)
|
332
|
+
output_key.append(input_key[0] >> 0x01)
|
333
|
+
output_key.append(((input_key[0]&0x01)<<6) | (input_key[1]>>2))
|
334
|
+
output_key.append(((input_key[1]&0x03)<<5) | (input_key[2]>>3))
|
335
|
+
output_key.append(((input_key[2]&0x07)<<4) | (input_key[3]>>4))
|
336
|
+
output_key.append(((input_key[3]&0x0F)<<3) | (input_key[4]>>5))
|
337
|
+
output_key.append(((input_key[4]&0x1F)<<2) | (input_key[5]>>6))
|
338
|
+
output_key.append(((input_key[5]&0x3F)<<1) | (input_key[6]>>7))
|
339
|
+
output_key.append(input_key[6] & 0x7F)
|
340
|
+
|
341
|
+
output_key = output_key.map {|x| (x << 1) & 0xFE}
|
342
|
+
|
343
|
+
output_key.pack('C'*8)
|
344
|
+
end
|
345
|
+
|
346
|
+
# [2.2.11.1 DES-ECB-LM](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/3f5ec79d-b449-4ab2-9423-c4dccbe0b184)
|
347
|
+
def self.encrypt_hash(hash:, key:)
|
348
|
+
block1 = hash[0..7]
|
349
|
+
block2 = hash[8..]
|
350
|
+
key1 = to_output_key(key[0..6])
|
351
|
+
key2 = to_output_key(key[7..13]) # The last two bytes are ignored
|
352
|
+
|
353
|
+
cipher1 = OpenSSL::Cipher.new('des-ecb').tap do |cipher|
|
354
|
+
cipher.encrypt
|
355
|
+
cipher.key = key1
|
356
|
+
end
|
357
|
+
|
358
|
+
cipher2 = OpenSSL::Cipher.new('des-ecb').tap do |cipher|
|
359
|
+
cipher.encrypt
|
360
|
+
cipher.key = key2
|
361
|
+
end
|
362
|
+
|
363
|
+
cipher1.update(block1) + cipher2.update(block2)
|
364
|
+
end
|
365
|
+
end
|
366
|
+
|
367
|
+
EncryptedLmOwfPassword = EncryptedNtOwfPassword
|
368
|
+
|
369
|
+
class PencryptedNtOwfPassword < EncryptedNtOwfPassword
|
370
|
+
extend Ndr::PointerClassPlugin
|
371
|
+
end
|
372
|
+
|
373
|
+
PencryptedLmOwfPassword = PencryptedNtOwfPassword
|
374
|
+
|
321
375
|
# [2.2.7.4 SAMPR_ULONG_ARRAY](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/2feb3806-4db2-45b7-90d2-86c8336a31ba)
|
322
376
|
class SamprUlongArray < Ndr::NdrStruct
|
323
377
|
default_parameter byte_align: 4
|
@@ -333,6 +387,28 @@ module RubySMB
|
|
333
387
|
ndr_uint16_array_ptr :buffer
|
334
388
|
end
|
335
389
|
|
390
|
+
# [2.2.6.21 SAMPR_ENCRYPTED_USER_PASSWORD](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/23f9ef4c-cf3e-4330-9287-ea4799b03201)
|
391
|
+
class SamprEncryptedUserPassword < Ndr::NdrStruct
|
392
|
+
default_parameter byte_align: 4
|
393
|
+
ndr_fixed_byte_array :buffer, initial_length: 516
|
394
|
+
|
395
|
+
def self.encrypt_password(password, old_password_nt)
|
396
|
+
# see: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/5fe3c4c4-e71b-440d-b2fd-8448bfaf6e04
|
397
|
+
password = password.encode('UTF-16LE').force_encoding('ASCII-8BIT')
|
398
|
+
buffer = password.rjust(512, "\x00") + [ password.length ].pack('V')
|
399
|
+
cipher = OpenSSL::Cipher.new('RC4').tap do |cipher|
|
400
|
+
cipher.encrypt
|
401
|
+
cipher.key = old_password_nt
|
402
|
+
end
|
403
|
+
cipher.update(buffer)
|
404
|
+
end
|
405
|
+
end
|
406
|
+
|
407
|
+
class PsamprEncryptedUserPassword < SamprEncryptedUserPassword
|
408
|
+
extend Ndr::PointerClassPlugin
|
409
|
+
end
|
410
|
+
|
411
|
+
|
336
412
|
# [2.2.6.22 SAMPR_ENCRYPTED_USER_PASSWORD_NEW](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/112ecc94-1cbe-41cd-b669-377402c20786)
|
337
413
|
class SamprEncryptedUserPasswordNew < BinData::Record
|
338
414
|
ndr_fixed_byte_array :buffer, initial_length: 532
|
@@ -413,12 +489,22 @@ module RubySMB
|
|
413
489
|
ndr_uint32 :user_account_control
|
414
490
|
end
|
415
491
|
|
492
|
+
# [2.2.6.25 SAMPR_USER_INTERNAL1_INFORMATION](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/50d17755-c6b8-40bd-8cac-bd6cfa31adf2)
|
493
|
+
class SamprUserInternal1Information < BinData::Record
|
494
|
+
encrypted_nt_owf_password :encrypted_nt_owf_password
|
495
|
+
encrypted_nt_owf_password :encrypted_lm_owf_password
|
496
|
+
ndr_uint8 :nt_password_present
|
497
|
+
ndr_uint8 :lm_password_present
|
498
|
+
ndr_uint8 :password_expired
|
499
|
+
end
|
500
|
+
|
416
501
|
# [2.2.6.29 SAMPR_USER_INFO_BUFFER](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/9496c26e-490b-4e76-827f-2695fc216f35)
|
417
502
|
class SamprUserInfoBuffer < BinData::Record
|
418
503
|
ndr_uint16 :tag
|
419
504
|
choice :member, selection: :tag do
|
420
505
|
user_control_information USER_CONTROL_INFORMATION
|
421
506
|
sampr_user_internal4_information_new USER_INTERNAL4_INFORMATION_NEW
|
507
|
+
sampr_user_internal1_information USER_INTERNAL1_INFORMATION
|
422
508
|
end
|
423
509
|
end
|
424
510
|
|
@@ -436,16 +522,25 @@ module RubySMB
|
|
436
522
|
# [2.2.10.1 USER_PROPERTIES](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/8263e7ab-aba9-43d2-8a36-3a9cb2dd3dad)
|
437
523
|
class UserProperties < BinData::Record
|
438
524
|
endian :little
|
525
|
+
hide :bytes_remaining
|
439
526
|
|
440
527
|
uint32 :reserved1
|
441
|
-
|
528
|
+
# Length, in bytes, of the entire structure, starting from the :reserved4 field (offset 12):
|
529
|
+
uint32 :struct_length, value: -> { num_bytes - 12}
|
442
530
|
uint16 :reserved2
|
443
531
|
uint16 :reserved3
|
444
532
|
string :reserved4, length: 96
|
445
533
|
uint16 :property_signature, initial_value: 0x50
|
446
|
-
|
447
|
-
|
534
|
+
count_bytes_remaining :bytes_remaining
|
535
|
+
# When there are zero `user_property` elements in the `:user_properties` field, this field MUST be omitted;
|
536
|
+
# the resultant `UserProperties` structure has a constant size of 0x6F bytes.
|
537
|
+
uint16 :property_count, value: -> { user_properties.size }, onlyif: :display_user_properties?
|
538
|
+
array :user_properties, type: :user_property, read_until: -> { array.size == property_count }, onlyif: :display_user_properties?
|
448
539
|
uint8 :reserved5
|
540
|
+
|
541
|
+
def display_user_properties?
|
542
|
+
(bytes_remaining > 1 && reading?) || user_properties.size > 0
|
543
|
+
end
|
449
544
|
end
|
450
545
|
|
451
546
|
# [2.2.10.7 KERB_KEY_DATA_NEW](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/447520a5-e1cc-48cc-8fdc-b90db57f7eac)
|
@@ -523,6 +618,10 @@ module RubySMB
|
|
523
618
|
require 'ruby_smb/dcerpc/samr/samr_get_groups_for_user_response'
|
524
619
|
require 'ruby_smb/dcerpc/samr/samr_set_information_user2_request'
|
525
620
|
require 'ruby_smb/dcerpc/samr/samr_set_information_user2_response'
|
621
|
+
require 'ruby_smb/dcerpc/samr/samr_change_password_user_request'
|
622
|
+
require 'ruby_smb/dcerpc/samr/samr_change_password_user_response'
|
623
|
+
require 'ruby_smb/dcerpc/samr/samr_unicode_change_password_user2_request'
|
624
|
+
require 'ruby_smb/dcerpc/samr/samr_unicode_change_password_user2_response'
|
526
625
|
require 'ruby_smb/dcerpc/samr/samr_delete_user_request'
|
527
626
|
require 'ruby_smb/dcerpc/samr/samr_delete_user_response'
|
528
627
|
require 'ruby_smb/dcerpc/samr/samr_query_information_domain_request'
|
@@ -882,6 +981,117 @@ module RubySMB
|
|
882
981
|
nil
|
883
982
|
end
|
884
983
|
|
984
|
+
# Change the password on a user object.
|
985
|
+
#
|
986
|
+
# @param user_handle [SamprHandle] Handle representing the user to change the password for
|
987
|
+
# @param old_password [String] The previous password (either this or old_nt_hash must be specified)
|
988
|
+
# @param new_password [String] The password to set on the account
|
989
|
+
# @param new_nt_hash [String] The new password's NT hash
|
990
|
+
# @param new_lm_hash [String] The new password's LM hash
|
991
|
+
# @param old_nt_hash [String] The previous password's NT hash (either this or old_password must be specified)
|
992
|
+
# @param old_lm_hash [String] The previous password's LM hash (currently ignored)
|
993
|
+
# @return nothing is returned on success
|
994
|
+
# @raise [RubySMB::Dcerpc::Error::SamrError] if the response error status
|
995
|
+
# is not STATUS_SUCCESS
|
996
|
+
def samr_change_password_user(user_handle:, old_password:nil, new_password:nil, new_nt_hash:nil, new_lm_hash:nil, old_nt_hash:nil, old_lm_hash:nil)
|
997
|
+
if new_password.nil? == new_nt_hash.nil?
|
998
|
+
raise ArgumentError.new('Provide either new password or new password hashes, but not both')
|
999
|
+
end
|
1000
|
+
|
1001
|
+
if old_password.nil? == old_nt_hash.nil?
|
1002
|
+
raise ArgumentError.new('Provide either old password or old password hashes, but not both')
|
1003
|
+
end
|
1004
|
+
|
1005
|
+
if old_password
|
1006
|
+
old_lm_hash = Net::NTLM.lm_hash(old_password[0..13])
|
1007
|
+
old_nt_hash = Net::NTLM.ntlm_hash(old_password)
|
1008
|
+
end
|
1009
|
+
|
1010
|
+
if new_nt_hash.nil?
|
1011
|
+
new_nt_hash = Net::NTLM::ntlm_hash(new_password)
|
1012
|
+
new_lm_hash = Net::NTLM.lm_hash(new_password[0..13])
|
1013
|
+
elsif new_lm_hash.nil?
|
1014
|
+
new_lm_hash = Net::NTLM.lm_hash('')
|
1015
|
+
end
|
1016
|
+
|
1017
|
+
samr_change_password_user_request = SamrChangePasswordUserRequest.new(
|
1018
|
+
user_handle: user_handle,
|
1019
|
+
lm_present: 0,
|
1020
|
+
old_lm_encrypted_with_new_lm: nil,
|
1021
|
+
new_lm_encrypted_with_old_lm: nil,
|
1022
|
+
nt_present: 1,
|
1023
|
+
old_nt_encrypted_with_new_nt: PencryptedNtOwfPassword.new(buffer: EncryptedNtOwfPassword.encrypt_hash(hash: old_nt_hash, key: new_nt_hash)),
|
1024
|
+
new_nt_encrypted_with_old_nt: PencryptedNtOwfPassword.new(buffer: EncryptedNtOwfPassword.encrypt_hash(hash: new_nt_hash, key: old_nt_hash)),
|
1025
|
+
nt_cross_encryption_present: 0,
|
1026
|
+
new_nt_encrypted_with_new_lm: nil,
|
1027
|
+
lm_cross_encryption_present: 1,
|
1028
|
+
new_lm_encrypted_with_new_nt: PencryptedNtOwfPassword.new(buffer: EncryptedNtOwfPassword.encrypt_hash(hash: new_lm_hash, key: new_nt_hash)),
|
1029
|
+
)
|
1030
|
+
response = dcerpc_request(samr_change_password_user_request)
|
1031
|
+
begin
|
1032
|
+
samr_unicode_change_password_user2_response = SamrChangePasswordUserResponse.read(response)
|
1033
|
+
rescue IOError
|
1034
|
+
raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading SamrUnicodeChangePasswordUser2Response'
|
1035
|
+
end
|
1036
|
+
unless samr_unicode_change_password_user2_response.error_status == WindowsError::NTStatus::STATUS_SUCCESS
|
1037
|
+
raise RubySMB::Dcerpc::Error::SamrError,
|
1038
|
+
"Error returned while changing user password: "\
|
1039
|
+
"#{WindowsError::NTStatus.find_by_retval(samr_unicode_change_password_user2_response.error_status.value).join(',')}"
|
1040
|
+
end
|
1041
|
+
|
1042
|
+
nil
|
1043
|
+
end
|
1044
|
+
|
1045
|
+
|
1046
|
+
# Change the password on a user.
|
1047
|
+
#
|
1048
|
+
# @param server_name [String] The server name; can be ignored by the server
|
1049
|
+
# @param target_username [String] The user for which we're changing the password
|
1050
|
+
# @param old_password [String] The previous password (either this or old_nt_hash must be specified)
|
1051
|
+
# @param new_password [String] The password to set on the account
|
1052
|
+
# @param old_nt_hash [String] The previous password's NT hash (either this or old_password must be specified)
|
1053
|
+
# @param old_lm_hash [String] The previous password's LM hash (currently ignored)
|
1054
|
+
# @return nothing is returned on success
|
1055
|
+
# @raise [RubySMB::Dcerpc::Error::SamrError] if the response error status
|
1056
|
+
# is not STATUS_SUCCESS
|
1057
|
+
def samr_unicode_change_password_user2(server_name: "", target_username:, old_password:nil, new_password:, old_nt_hash:nil, old_lm_hash:nil)
|
1058
|
+
#if old_lm_hash.nil? != old_nt_hash.nil?
|
1059
|
+
# raise ArgumentError.new('If providing the previous NT/LM hash, must provide both')
|
1060
|
+
#end
|
1061
|
+
if old_password.nil? == old_nt_hash.nil?
|
1062
|
+
raise ArgumentError.new('Provide either old password or old password hashes, but not both')
|
1063
|
+
end
|
1064
|
+
|
1065
|
+
if old_password
|
1066
|
+
old_lm_hash = Net::NTLM.lm_hash(old_password[0..13])
|
1067
|
+
old_nt_hash = Net::NTLM.ntlm_hash(old_password)
|
1068
|
+
end
|
1069
|
+
|
1070
|
+
new_nt_hash = Net::NTLM::ntlm_hash(new_password)
|
1071
|
+
|
1072
|
+
samr_unicode_change_password_user2_request = SamrUnicodeChangePasswordUser2Request.new(
|
1073
|
+
server_name: server_name,
|
1074
|
+
user_name: target_username,
|
1075
|
+
new_password_encrypted_with_old_nt: SamprEncryptedUserPassword.new(buffer: SamprEncryptedUserPassword.encrypt_password(new_password, old_nt_hash)),
|
1076
|
+
old_nt_owf_password_encrypted_with_new_nt: PencryptedNtOwfPassword.new(buffer: EncryptedNtOwfPassword.encrypt_hash(hash: old_nt_hash, key: new_nt_hash)),
|
1077
|
+
lm_present: 0
|
1078
|
+
)
|
1079
|
+
samr_unicode_change_password_user2_request
|
1080
|
+
response = dcerpc_request(samr_unicode_change_password_user2_request)
|
1081
|
+
begin
|
1082
|
+
samr_unicode_change_password_user2_response = SamrUnicodeChangePasswordUser2Response.read(response)
|
1083
|
+
rescue IOError
|
1084
|
+
raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading SamrUnicodeChangePasswordUser2Response'
|
1085
|
+
end
|
1086
|
+
unless samr_unicode_change_password_user2_response.error_status == WindowsError::NTStatus::STATUS_SUCCESS
|
1087
|
+
raise RubySMB::Dcerpc::Error::SamrError,
|
1088
|
+
"Error returned while changing user password: "\
|
1089
|
+
"#{WindowsError::NTStatus.find_by_retval(samr_unicode_change_password_user2_response.error_status.value).join(',')}"
|
1090
|
+
end
|
1091
|
+
|
1092
|
+
nil
|
1093
|
+
end
|
1094
|
+
|
885
1095
|
# Closes (that is, releases server-side resources used by) any context
|
886
1096
|
# handle obtained from this RPC interface
|
887
1097
|
#
|
data/lib/ruby_smb/dcerpc.rb
CHANGED
@@ -50,6 +50,7 @@ module RubySMB
|
|
50
50
|
require 'ruby_smb/dcerpc/icpr'
|
51
51
|
require 'ruby_smb/dcerpc/efsrpc'
|
52
52
|
require 'ruby_smb/dcerpc/lsarpc'
|
53
|
+
require 'ruby_smb/dcerpc/gkdi'
|
53
54
|
require 'ruby_smb/dcerpc/request'
|
54
55
|
require 'ruby_smb/dcerpc/response'
|
55
56
|
require 'ruby_smb/dcerpc/rpc_auth3'
|
data/lib/ruby_smb/version.rb
CHANGED
@@ -0,0 +1,10 @@
|
|
1
|
+
RSpec.describe RubySMB::Dcerpc::Samr::EncryptedNtOwfPassword do
|
2
|
+
it 'Creates output key' do
|
3
|
+
expect(described_class.to_output_key('ABCDEFG')).to eq ["40a09068442A188E"].pack('H*')
|
4
|
+
expect(described_class.to_output_key('AAAAAAA')).to eq ["40A05028140A0482"].pack('H*')
|
5
|
+
end
|
6
|
+
|
7
|
+
it 'Encrypts a hash' do
|
8
|
+
expect(described_class.encrypt_hash(hash: 'AAAAAAAAAAAAAAAA', key: 'BBBBBBBBBBBBBB')).to eq ["8cd90c3de08ecda28cd90c3de08ecda2"].pack('H*')
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
RSpec.describe RubySMB::Dcerpc::Samr::SamprEncryptedUserPassword do
|
2
|
+
|
3
|
+
it 'Encrypts correctly' do
|
4
|
+
password = 'newPassword1!'
|
5
|
+
old_password_nt = 'AAAAAAAAAAAAAAAA'
|
6
|
+
expected = ['c2cbe63dc0a3cda1baab695ce4f0352b774592b214a905796a6ba9fd30e0ffc56d60812bfd7f45420f5332922b50cfdcde3133e3e45c5eb6c16023006cb4ff7d41f54fa009a64fa66b00fa41094d7db6c4cc9a430a7ad43122047b696d934645974fee7551dcafac28c0869106417fd3fbfc34a87a56d6141aac2b6d134723f2224791b39749bc93f4405f78ba09dcd9b4d29e72ae0c873a8d468323793fffccc2a9d8dc4d975c42064208d898df71ef0889b2e5a9cfa6c8c2758eb15b6fdd332d6d7d2829f3a3bc2a7ecd7f87d1fd4aed25d93de6a7baf8e0247e2f5b831ca7646eef7a11e2f9410574707ef85c9db8cc125fb6254fe1e111a662006343299fcb8f8fb641cb1d188ff6e5c50334ca199603a93907093e6d35d80b2dade79360bc672870d29cdf5f80120ac53e9ce3c3718d0f8097cdae2318b8e27108fc1066491e5b034f55c1e8ff00a53d2eb7b0e0ffc10236a5a530795b84f33d66eb51388d6da112886c8ea482af0ec7e9c0a549a561244ee9185b5387b05d3c5e74d88e355aef22dab1d5039d0a0caa22437f6e520121ef5d21da729bb0cdee5cbb3b450bf1d0fcafad5ac518b0535628e2a96a2d0d2f8acd3e42147e700c2889cbc92c5533f1889b49d41c0ae9a05fc0a754060c0680296de5c712a3299cdd5c646582348fc2e32a68ae4fc2a3b91fb423adc617a20b28c1d6297f14a870329e6aa802d22ba97c'].pack('H*')
|
7
|
+
expect(described_class.encrypt_password(password, old_password_nt)).to eq expected
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
RSpec.describe RubySMB::Dcerpc::Samr::SamrChangePasswordUserRequest do
|
2
|
+
subject(:packet) { described_class.new }
|
3
|
+
|
4
|
+
describe '#initialize_instance' do
|
5
|
+
it 'sets #opnum to SAMR_CHANGE_PASSWORD_USER constant' do
|
6
|
+
expect(packet.opnum).to eq(RubySMB::Dcerpc::Samr::SAMR_CHANGE_PASSWORD_USER)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'reads itself' do
|
11
|
+
uuid = RubySMB::Dcerpc::Uuid.new
|
12
|
+
uuid.set(SecureRandom.uuid)
|
13
|
+
new_packet = described_class.new({
|
14
|
+
user_handle: RubySMB::Dcerpc::Samr::SamprHandle.new(context_handle_attributes: 42, :context_handle_uuid => uuid),
|
15
|
+
lm_present: 1,
|
16
|
+
old_lm_encrypted_with_new_lm: RubySMB::Dcerpc::Samr::PencryptedNtOwfPassword.new(buffer: SecureRandom::bytes(16)),
|
17
|
+
new_lm_encrypted_with_old_lm: RubySMB::Dcerpc::Samr::PencryptedNtOwfPassword.new(buffer: SecureRandom::bytes(16)),
|
18
|
+
nt_present: 1,
|
19
|
+
old_nt_encrypted_with_new_nt: RubySMB::Dcerpc::Samr::PencryptedNtOwfPassword.new(buffer: SecureRandom::bytes(16)),
|
20
|
+
new_nt_encrypted_with_old_nt: RubySMB::Dcerpc::Samr::PencryptedNtOwfPassword.new(buffer: SecureRandom::bytes(16)),
|
21
|
+
nt_cross_encryption_present: 1,
|
22
|
+
new_nt_encrypted_with_new_nt: RubySMB::Dcerpc::Samr::PencryptedNtOwfPassword.new(buffer: SecureRandom::bytes(16)),
|
23
|
+
lm_cross_encryption_present: 1,
|
24
|
+
new_lm_encrypted_with_new_nt: RubySMB::Dcerpc::Samr::PencryptedNtOwfPassword.new(buffer: SecureRandom::bytes(16))
|
25
|
+
})
|
26
|
+
expect(packet.read(new_packet.to_binary_s)).to eq(new_packet)
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
RSpec.describe RubySMB::Dcerpc::Samr::SamrChangePasswordUserResponse do
|
2
|
+
subject(:packet) { described_class.new }
|
3
|
+
|
4
|
+
describe '#initialize_instance' do
|
5
|
+
it 'sets #opnum to SAMR_CHANGE_PASSWORD_USER constant' do
|
6
|
+
expect(packet.opnum).to eq(RubySMB::Dcerpc::Samr::SAMR_CHANGE_PASSWORD_USER)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'reads itself' do
|
11
|
+
new_packet = described_class.new({
|
12
|
+
error_status: 4
|
13
|
+
})
|
14
|
+
expect(packet.read(new_packet.to_binary_s)).to eq(new_packet)
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
RSpec.describe RubySMB::Dcerpc::Samr::SamrUnicodeChangePasswordUser2Request do
|
2
|
+
subject(:packet) { described_class.new }
|
3
|
+
|
4
|
+
describe '#initialize_instance' do
|
5
|
+
it 'sets #opnum to SAMR_UNICODE_CHANGE_PASSWORD_USER2 constant' do
|
6
|
+
expect(packet.opnum).to eq(RubySMB::Dcerpc::Samr::SAMR_UNICODE_CHANGE_PASSWORD_USER2)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'reads itself' do
|
11
|
+
new_packet = described_class.new({
|
12
|
+
server_name: 'my-server',
|
13
|
+
user_name: 'user.person',
|
14
|
+
new_password_encrypted_with_old_nt: RubySMB::Dcerpc::Samr::PsamprEncryptedUserPassword.new(buffer: SecureRandom::bytes(516)),
|
15
|
+
pencrypted_nt_owf_password: RubySMB::Dcerpc::Samr::PencryptedNtOwfPassword.new(buffer: SecureRandom::bytes(16)),
|
16
|
+
lm_present: 1,
|
17
|
+
new_password_encrypted_with_old_lm: RubySMB::Dcerpc::Samr::PsamprEncryptedUserPassword.new(buffer: SecureRandom::bytes(516)),
|
18
|
+
old_lm_owf_password_encrypted_with_new_nt: RubySMB::Dcerpc::Samr::PencryptedNtOwfPassword.new(buffer: SecureRandom::bytes(16)),
|
19
|
+
})
|
20
|
+
expect(packet.read(new_packet.to_binary_s)).to eq(new_packet)
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
RSpec.describe RubySMB::Dcerpc::Samr::SamrUnicodeChangePasswordUser2Response do
|
2
|
+
subject(:packet) { described_class.new }
|
3
|
+
|
4
|
+
describe '#initialize_instance' do
|
5
|
+
it 'sets #opnum to SAMR_UNICODE_CHANGE_PASSWORD_USER2 constant' do
|
6
|
+
expect(packet.opnum).to eq(RubySMB::Dcerpc::Samr::SAMR_UNICODE_CHANGE_PASSWORD_USER2)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'reads itself' do
|
11
|
+
new_packet = described_class.new({
|
12
|
+
error_status: 4
|
13
|
+
})
|
14
|
+
expect(packet.read(new_packet.to_binary_s)).to eq(new_packet)
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
RSpec.describe RubySMB::Dcerpc::Samr::UserProperties do
|
2
|
+
describe '#read' do
|
3
|
+
context 'when reading a structure with no user properties' do
|
4
|
+
let(:binary) { [ 0, 0x63, 0, 0, 0x50, 0].pack('L<L<S<S<x96<SC') }
|
5
|
+
let(:subject) { described_class.read(binary) }
|
6
|
+
|
7
|
+
it 'does not include the property_count' do
|
8
|
+
expect(subject.property_count?).to be_falsey
|
9
|
+
expect(subject.snapshot).to_not include(:property_count)
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'does not include the user_properties' do
|
13
|
+
expect(subject.user_properties?).to be_falsey
|
14
|
+
expect(subject.snapshot).to_not include(:user_properties)
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'serializes to the value that was read' do
|
18
|
+
expect(subject.to_binary_s).to eq(binary)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'when reading a structure with two user properties' do
|
23
|
+
let(:user_property1) { RubySMB::Dcerpc::Samr::UserProperty.new(property_name: 'key1', property_value: 'value1') }
|
24
|
+
let(:user_property2) { RubySMB::Dcerpc::Samr::UserProperty.new(property_name: 'key2', property_value: 'value2') }
|
25
|
+
let(:user_properties) { user_property1.to_binary_s + user_property2.to_binary_s }
|
26
|
+
let(:binary) { [ 0, 0x63 + 2 + user_properties.length, 0, 0, 0x50, 2].pack('L<L<S<S<x96<S<S') + user_properties + "\x00".b }
|
27
|
+
let(:subject) { described_class.read(binary) }
|
28
|
+
|
29
|
+
it 'includes the property_count' do
|
30
|
+
expect(subject.property_count?).to be_truthy
|
31
|
+
expect(subject.property_count).to eq(2)
|
32
|
+
expect(subject.snapshot).to include(:property_count)
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'includes the user_properties' do
|
36
|
+
expect(subject.user_properties?).to be_truthy
|
37
|
+
expect(subject.user_properties).to eq([user_property1, user_property2])
|
38
|
+
expect(subject.snapshot).to include(:user_properties)
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'serializes to the value that was read' do
|
42
|
+
expect(subject.to_binary_s).to eq(binary)
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'when #user_properties is cleared' do
|
46
|
+
before(:each) { subject.user_properties.clear }
|
47
|
+
|
48
|
+
it 'does not include the property_count' do
|
49
|
+
expect(subject.property_count?).to be_falsey
|
50
|
+
expect(subject.snapshot).to_not include(:property_count)
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'does not include the user_properties' do
|
54
|
+
expect(subject.user_properties?).to be_falsey
|
55
|
+
expect(subject.snapshot).to_not include(:user_properties)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe '#initialize' do
|
62
|
+
let(:subject) { described_class.new }
|
63
|
+
|
64
|
+
it 'initializes #struct_length to 0x63' do
|
65
|
+
expect(subject.struct_length).to eq(0x63)
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'initializes #property_signature to 0x50' do
|
69
|
+
expect(subject.property_signature).to eq(0x50)
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'does not include user_properties' do
|
73
|
+
expect(subject.user_properties).to be_empty
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
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.14
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Metasploit Hackers
|
@@ -10,36 +10,10 @@ authors:
|
|
10
10
|
- Dev Mohanty
|
11
11
|
- Christophe De La Fuente
|
12
12
|
- Spencer McIntyre
|
13
|
-
autorequire:
|
13
|
+
autorequire:
|
14
14
|
bindir: bin
|
15
|
-
cert_chain:
|
16
|
-
-
|
17
|
-
-----BEGIN CERTIFICATE-----
|
18
|
-
MIIERDCCAqygAwIBAgIBATANBgkqhkiG9w0BAQsFADAmMSQwIgYDVQQDDBttc2Zk
|
19
|
-
ZXYvREM9bWV0YXNwbG9pdC9EQz1jb20wHhcNMjMxMDMwMTYwNDI1WhcNMjUxMDI5
|
20
|
-
MTYwNDI1WjAmMSQwIgYDVQQDDBttc2ZkZXYvREM9bWV0YXNwbG9pdC9EQz1jb20w
|
21
|
-
ggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQDZN/EKv+yVjwiKWvjAVhjF
|
22
|
-
aWNYI0E9bJ5d1qKd29omRYX9a+OOKBCu5+394fyF5RjwU4mYGr2iopX9ixRJrWXH
|
23
|
-
ojs70tEvV1CmvP9rhz7JKzQQoJOkinrz4d+StIylxVxVdgm7DeiB3ruTwvl7qKUv
|
24
|
-
piWzhrBFiVU6XIEAwq6wNEmnv2D+Omyf4h0Tf99hc6G0QmBnU3XydqvnZ+AzUbBV
|
25
|
-
24RH3+NQoigLbvK4M5aOeYhk19di58hznebOw6twHzNczshrBeMFQp985ScNgsvF
|
26
|
-
rL+7HNNwpcpngERwZfzDNn7iYN5X3cyvTcykShtsuPMa5zXsYo42LZrsTF87DW38
|
27
|
-
D8sxL6Dgdqu25Mltdw9m+iD4rHSfb1KJYEoNO+WwBJLO2Y4d6G1CR66tVeWsZspb
|
28
|
-
zneOVC+sDuil7hOm+6a7Y2yrrRyT6IfL/07DywjPAIRUp5+Jn8ZrkWRNo2AOwWBG
|
29
|
-
k5gz7SfJPHuyVnPlxoMA0MTFCUnnnbyHu882TGoJGgMCAwEAAaN9MHswCQYDVR0T
|
30
|
-
BAIwADALBgNVHQ8EBAMCBLAwHQYDVR0OBBYEFIQfNa4E889ZE334cwU7eNu2hScH
|
31
|
-
MCAGA1UdEQQZMBeBFW1zZmRldkBtZXRhc3Bsb2l0LmNvbTAgBgNVHRIEGTAXgRVt
|
32
|
-
c2ZkZXZAbWV0YXNwbG9pdC5jb20wDQYJKoZIhvcNAQELBQADggGBAMfzvKcV27p7
|
33
|
-
pctmpW2JmIXLMrjNLyGJAxELH/t9pJueXdga7uj2fJkYQDbwGw5x4MGyFqhqJLH4
|
34
|
-
l/qsUF3PyAXDTSWLVaqXQVWO+IIHxecG0XjPXTNudzMU0hzqbqiBKvsW7/a3V5BP
|
35
|
-
SWlFzrFkoXWlPouFpoakyYMJjpW4SGdPzRv7pM4OhXtkXpHiRvx5985FrHgHlI89
|
36
|
-
NSIuIUbp8zqk4hP1i9MV0Lc/vTf2gOmo+RHnjqG1NiYfMCYyY/Mcd4W36kGOl468
|
37
|
-
I8VDTwgCufkAzFu7BJ5yCOueqtDcuq+d3YhAyU7NI4+Ja8EwazOnB+07sWhKpg7z
|
38
|
-
yuQ1mWYPmZfVQpoSVv1CvXsoqJYXVPBBLOacKKSj8ArVG6pPn9Bej7IOQdblaFjl
|
39
|
-
DgscAao7wB3xW2BWEp1KnaDWkf1x9ttgoBEYyuYwU7uatB67kBQG1PKvLt79wHvz
|
40
|
-
Dxs+KOjGbBRfMnPgVGYkORKVrZIwlaboHbDKxcVW5xv+oZc7KYXWGg==
|
41
|
-
-----END CERTIFICATE-----
|
42
|
-
date: 2024-11-22 00:00:00.000000000 Z
|
15
|
+
cert_chain: []
|
16
|
+
date: 2025-04-30 00:00:00.000000000 Z
|
43
17
|
dependencies:
|
44
18
|
- !ruby/object:Gem::Dependency
|
45
19
|
name: redcarpet
|
@@ -279,6 +253,12 @@ files:
|
|
279
253
|
- lib/ruby_smb/dcerpc/epm/epm_twrt.rb
|
280
254
|
- lib/ruby_smb/dcerpc/error.rb
|
281
255
|
- lib/ruby_smb/dcerpc/fault.rb
|
256
|
+
- lib/ruby_smb/dcerpc/gkdi.rb
|
257
|
+
- lib/ruby_smb/dcerpc/gkdi/gkdi_ffc_dh_key.rb
|
258
|
+
- lib/ruby_smb/dcerpc/gkdi/gkdi_ffc_dh_parameters.rb
|
259
|
+
- lib/ruby_smb/dcerpc/gkdi/gkdi_get_key_request.rb
|
260
|
+
- lib/ruby_smb/dcerpc/gkdi/gkdi_get_key_response.rb
|
261
|
+
- lib/ruby_smb/dcerpc/gkdi/gkdi_group_key_envelope.rb
|
282
262
|
- lib/ruby_smb/dcerpc/icpr.rb
|
283
263
|
- lib/ruby_smb/dcerpc/icpr/cert_server_request_request.rb
|
284
264
|
- lib/ruby_smb/dcerpc/icpr/cert_server_request_response.rb
|
@@ -328,6 +308,8 @@ files:
|
|
328
308
|
- lib/ruby_smb/dcerpc/samr.rb
|
329
309
|
- lib/ruby_smb/dcerpc/samr/rpc_sid.rb
|
330
310
|
- lib/ruby_smb/dcerpc/samr/sampr_domain_info_buffer.rb
|
311
|
+
- lib/ruby_smb/dcerpc/samr/samr_change_password_user_request.rb
|
312
|
+
- lib/ruby_smb/dcerpc/samr/samr_change_password_user_response.rb
|
331
313
|
- lib/ruby_smb/dcerpc/samr/samr_close_handle_request.rb
|
332
314
|
- lib/ruby_smb/dcerpc/samr/samr_close_handle_response.rb
|
333
315
|
- lib/ruby_smb/dcerpc/samr/samr_connect_request.rb
|
@@ -362,6 +344,8 @@ files:
|
|
362
344
|
- lib/ruby_smb/dcerpc/samr/samr_rid_to_sid_response.rb
|
363
345
|
- lib/ruby_smb/dcerpc/samr/samr_set_information_user2_request.rb
|
364
346
|
- lib/ruby_smb/dcerpc/samr/samr_set_information_user2_response.rb
|
347
|
+
- lib/ruby_smb/dcerpc/samr/samr_unicode_change_password_user2_request.rb
|
348
|
+
- lib/ruby_smb/dcerpc/samr/samr_unicode_change_password_user2_response.rb
|
365
349
|
- lib/ruby_smb/dcerpc/sec_trailer.rb
|
366
350
|
- lib/ruby_smb/dcerpc/srvsvc.rb
|
367
351
|
- lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all.rb
|
@@ -713,7 +697,11 @@ files:
|
|
713
697
|
- spec/lib/ruby_smb/dcerpc/rpc_auth3_spec.rb
|
714
698
|
- spec/lib/ruby_smb/dcerpc/rpc_security_attributes_spec.rb
|
715
699
|
- spec/lib/ruby_smb/dcerpc/rrp_rpc_unicode_string_spec.rb
|
700
|
+
- spec/lib/ruby_smb/dcerpc/samr/encrypted_nt_owf_password_spec.rb
|
716
701
|
- spec/lib/ruby_smb/dcerpc/samr/rpc_sid_spec.rb
|
702
|
+
- spec/lib/ruby_smb/dcerpc/samr/sampr_encrypted_user_password_spec.rb
|
703
|
+
- spec/lib/ruby_smb/dcerpc/samr/samr_change_password_user_request_spec.rb
|
704
|
+
- spec/lib/ruby_smb/dcerpc/samr/samr_change_password_user_response_spec.rb
|
717
705
|
- spec/lib/ruby_smb/dcerpc/samr/samr_close_handle_request_spec.rb
|
718
706
|
- spec/lib/ruby_smb/dcerpc/samr/samr_close_handle_response_spec.rb
|
719
707
|
- spec/lib/ruby_smb/dcerpc/samr/samr_connect_request_spec.rb
|
@@ -736,6 +724,9 @@ files:
|
|
736
724
|
- spec/lib/ruby_smb/dcerpc/samr/samr_rid_to_sid_response_spec.rb
|
737
725
|
- spec/lib/ruby_smb/dcerpc/samr/samr_set_information_user2_request_spec.rb
|
738
726
|
- spec/lib/ruby_smb/dcerpc/samr/samr_set_information_user2_response_spec.rb
|
727
|
+
- spec/lib/ruby_smb/dcerpc/samr/samr_unicode_change_password_user2_request_spec.rb
|
728
|
+
- spec/lib/ruby_smb/dcerpc/samr/samr_unicode_change_password_user2_response_spec.rb
|
729
|
+
- spec/lib/ruby_smb/dcerpc/samr/user_properties_spec.rb
|
739
730
|
- spec/lib/ruby_smb/dcerpc/samr_spec.rb
|
740
731
|
- spec/lib/ruby_smb/dcerpc/sec_trailer_spec.rb
|
741
732
|
- spec/lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all_spec.rb
|
@@ -985,7 +976,7 @@ homepage: https://github.com/rapid7/ruby_smb
|
|
985
976
|
licenses:
|
986
977
|
- BSD-3-clause
|
987
978
|
metadata: {}
|
988
|
-
post_install_message:
|
979
|
+
post_install_message:
|
989
980
|
rdoc_options: []
|
990
981
|
require_paths:
|
991
982
|
- lib
|
@@ -1000,8 +991,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
1000
991
|
- !ruby/object:Gem::Version
|
1001
992
|
version: '0'
|
1002
993
|
requirements: []
|
1003
|
-
rubygems_version: 3.
|
1004
|
-
signing_key:
|
994
|
+
rubygems_version: 3.4.19
|
995
|
+
signing_key:
|
1005
996
|
specification_version: 4
|
1006
997
|
summary: A pure Ruby implementation of the SMB Protocol Family
|
1007
998
|
test_files:
|
@@ -1057,7 +1048,11 @@ test_files:
|
|
1057
1048
|
- spec/lib/ruby_smb/dcerpc/rpc_auth3_spec.rb
|
1058
1049
|
- spec/lib/ruby_smb/dcerpc/rpc_security_attributes_spec.rb
|
1059
1050
|
- spec/lib/ruby_smb/dcerpc/rrp_rpc_unicode_string_spec.rb
|
1051
|
+
- spec/lib/ruby_smb/dcerpc/samr/encrypted_nt_owf_password_spec.rb
|
1060
1052
|
- spec/lib/ruby_smb/dcerpc/samr/rpc_sid_spec.rb
|
1053
|
+
- spec/lib/ruby_smb/dcerpc/samr/sampr_encrypted_user_password_spec.rb
|
1054
|
+
- spec/lib/ruby_smb/dcerpc/samr/samr_change_password_user_request_spec.rb
|
1055
|
+
- spec/lib/ruby_smb/dcerpc/samr/samr_change_password_user_response_spec.rb
|
1061
1056
|
- spec/lib/ruby_smb/dcerpc/samr/samr_close_handle_request_spec.rb
|
1062
1057
|
- spec/lib/ruby_smb/dcerpc/samr/samr_close_handle_response_spec.rb
|
1063
1058
|
- spec/lib/ruby_smb/dcerpc/samr/samr_connect_request_spec.rb
|
@@ -1080,6 +1075,9 @@ test_files:
|
|
1080
1075
|
- spec/lib/ruby_smb/dcerpc/samr/samr_rid_to_sid_response_spec.rb
|
1081
1076
|
- spec/lib/ruby_smb/dcerpc/samr/samr_set_information_user2_request_spec.rb
|
1082
1077
|
- spec/lib/ruby_smb/dcerpc/samr/samr_set_information_user2_response_spec.rb
|
1078
|
+
- spec/lib/ruby_smb/dcerpc/samr/samr_unicode_change_password_user2_request_spec.rb
|
1079
|
+
- spec/lib/ruby_smb/dcerpc/samr/samr_unicode_change_password_user2_response_spec.rb
|
1080
|
+
- spec/lib/ruby_smb/dcerpc/samr/user_properties_spec.rb
|
1083
1081
|
- spec/lib/ruby_smb/dcerpc/samr_spec.rb
|
1084
1082
|
- spec/lib/ruby_smb/dcerpc/sec_trailer_spec.rb
|
1085
1083
|
- spec/lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all_spec.rb
|
checksums.yaml.gz.sig
DELETED
Binary file
|
data.tar.gz.sig
DELETED
Binary file
|
metadata.gz.sig
DELETED
Binary file
|