ruby_smb 3.1.2 → 3.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/examples/file_server.rb +6 -68
- data/examples/virtual_file_server.rb +10 -62
- data/lib/ruby_smb/client/authentication.rb +29 -4
- data/lib/ruby_smb/client/negotiation.rb +2 -0
- data/lib/ruby_smb/client.rb +18 -3
- data/lib/ruby_smb/dcerpc/error.rb +13 -0
- data/lib/ruby_smb/dcerpc/fault.rb +83 -0
- data/lib/ruby_smb/dcerpc/ndr.rb +19 -8
- data/lib/ruby_smb/dcerpc/request.rb +15 -10
- data/lib/ruby_smb/dcerpc/rrp_rpc_unicode_string.rb +5 -0
- data/lib/ruby_smb/dcerpc/samr/samr_create_user2_in_domain_request.rb +24 -0
- data/lib/ruby_smb/dcerpc/samr/samr_create_user2_in_domain_response.rb +24 -0
- data/lib/ruby_smb/dcerpc/samr/samr_delete_user_request.rb +21 -0
- data/lib/ruby_smb/dcerpc/samr/samr_delete_user_response.rb +22 -0
- data/lib/ruby_smb/dcerpc/samr/samr_enumerate_domains_in_sam_server_request.rb +25 -0
- data/lib/ruby_smb/dcerpc/samr/samr_enumerate_domains_in_sam_server_response.rb +25 -0
- data/lib/ruby_smb/dcerpc/samr/samr_enumerate_users_in_domain_response.rb +0 -31
- data/lib/ruby_smb/dcerpc/samr/samr_get_alias_membership_response.rb +1 -14
- data/lib/ruby_smb/dcerpc/samr/samr_lookup_names_in_domain_request.rb +23 -0
- data/lib/ruby_smb/dcerpc/samr/samr_lookup_names_in_domain_response.rb +23 -0
- data/lib/ruby_smb/dcerpc/samr/samr_set_information_user2_request.rb +23 -0
- data/lib/ruby_smb/dcerpc/samr/samr_set_information_user2_response.rb +21 -0
- data/lib/ruby_smb/dcerpc/samr.rb +453 -83
- data/lib/ruby_smb/dcerpc.rb +1 -0
- data/lib/ruby_smb/error.rb +4 -0
- data/lib/ruby_smb/gss.rb +1 -0
- data/lib/ruby_smb/ntlm/client.rb +74 -0
- data/lib/ruby_smb/ntlm.rb +1 -0
- data/lib/ruby_smb/server/cli.rb +121 -0
- data/lib/ruby_smb/server.rb +1 -0
- data/lib/ruby_smb/smb1/packet/session_setup_request.rb +11 -0
- data/lib/ruby_smb/smb1/pipe.rb +4 -1
- data/lib/ruby_smb/smb2/pipe.rb +4 -2
- data/lib/ruby_smb/version.rb +1 -1
- data/spec/lib/ruby_smb/client_spec.rb +1 -0
- data/spec/lib/ruby_smb/dcerpc/samr/samr_create_user2_in_domain_request_spec.rb +69 -0
- data/spec/lib/ruby_smb/dcerpc/samr/samr_create_user2_in_domain_response_spec.rb +69 -0
- data/spec/lib/ruby_smb/dcerpc/samr/samr_delete_user_request_spec.rb +42 -0
- data/spec/lib/ruby_smb/dcerpc/samr/samr_delete_user_response_spec.rb +51 -0
- data/spec/lib/ruby_smb/dcerpc/samr/samr_enumerate_domains_in_sam_server_request_spec.rb +60 -0
- data/spec/lib/ruby_smb/dcerpc/samr/samr_enumerate_domains_in_sam_server_response_spec.rb +75 -0
- data/spec/lib/ruby_smb/dcerpc/samr/samr_enumerate_users_in_domain_response_spec.rb +0 -195
- data/spec/lib/ruby_smb/dcerpc/samr/samr_lookup_names_in_domain_request_spec.rb +62 -0
- data/spec/lib/ruby_smb/dcerpc/samr/samr_lookup_names_in_domain_response_spec.rb +54 -0
- data/spec/lib/ruby_smb/dcerpc/samr/samr_set_information_user2_request_spec.rb +67 -0
- data/spec/lib/ruby_smb/dcerpc/samr/samr_set_information_user2_response_spec.rb +35 -0
- data/spec/lib/ruby_smb/dcerpc/samr_spec.rb +194 -0
- data/spec/lib/ruby_smb/ntlm/client/session_spec.rb +114 -0
- data/spec/lib/ruby_smb/ntlm/client_spec.rb +36 -0
- data.tar.gz.sig +0 -0
- metadata +39 -2
- metadata.gz.sig +0 -0
data/lib/ruby_smb/dcerpc/samr.rb
CHANGED
@@ -6,91 +6,26 @@ module RubySMB
|
|
6
6
|
VER_MAJOR = 1
|
7
7
|
VER_MINOR = 0
|
8
8
|
|
9
|
-
# Operation numbers
|
10
|
-
SAMR_CONNECT = 0x0000
|
11
|
-
SAMR_CLOSE_HANDLE = 0x0001
|
12
|
-
SAMR_LOOKUP_DOMAIN_IN_SAM_SERVER = 0x0005
|
13
|
-
SAMR_OPEN_DOMAIN = 0x0007
|
14
|
-
SAMR_ENUMERATE_USERS_IN_DOMAIN = 0x000D
|
15
|
-
SAMR_GET_ALIAS_MEMBERSHIP = 0x0010
|
16
|
-
SAMR_OPEN_USER = 0x0022
|
17
|
-
SAMR_GET_GROUPS_FOR_USER = 0x0027
|
18
|
-
SAMR_RID_TO_SID = 0x0041
|
19
|
-
|
20
|
-
class SamprHandle < Ndr::NdrContextHandle; end
|
21
|
-
|
22
|
-
# [2.2.10.2 USER_PROPERTY](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/7c0f2eca-1783-450b-b5a0-754cf11f22c9)
|
23
|
-
class UserProperty < BinData::Record
|
24
|
-
endian :little
|
25
|
-
|
26
|
-
uint16 :name_length, initial_value: -> { property_name.num_bytes }
|
27
|
-
uint16 :value_length, initial_value: -> { property_value.num_bytes }
|
28
|
-
uint16 :reserved
|
29
|
-
string16 :property_name, read_length: :name_length
|
30
|
-
string :property_value, read_length: :value_length
|
31
|
-
end
|
32
|
-
|
33
|
-
# [2.2.10.1 USER_PROPERTIES](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/8263e7ab-aba9-43d2-8a36-3a9cb2dd3dad)
|
34
|
-
class UserProperties < BinData::Record
|
35
|
-
endian :little
|
36
|
-
|
37
|
-
uint32 :reserved1
|
38
|
-
uint32 :struct_length, initial_value: -> { num_bytes - 12 }
|
39
|
-
uint16 :reserved2
|
40
|
-
uint16 :reserved3
|
41
|
-
string :reserved4, length: 96
|
42
|
-
uint16 :property_signature, initial_value: 0x50
|
43
|
-
uint16 :property_count, initial_value: -> { user_properties.size }
|
44
|
-
array :user_properties, type: :user_property, initial_length: :property_count
|
45
|
-
uint8 :reserved5
|
46
|
-
end
|
47
|
-
|
48
|
-
class KerbKeyDataNew < BinData::Record
|
49
|
-
endian :little
|
50
|
-
|
51
|
-
uint16 :reserved1
|
52
|
-
uint16 :reserved2
|
53
|
-
uint32 :reserved3
|
54
|
-
uint32 :iteration_count
|
55
|
-
uint32 :key_type
|
56
|
-
uint32 :key_length
|
57
|
-
uint32 :key_offset
|
58
|
-
end
|
59
|
-
|
60
|
-
# [2.2.10.6 Primary:Kerberos-Newer-Keys - KERB_STORED_CREDENTIAL_NEW](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/08cb3ca7-954b-45e3-902e-77512fe3ba8e)
|
61
|
-
class KerbStoredCredentialNew < BinData::Record
|
62
|
-
endian :little
|
63
|
-
|
64
|
-
uint16 :revision
|
65
|
-
uint16 :flags
|
66
|
-
uint16 :credential_count
|
67
|
-
uint16 :service_credential_count
|
68
|
-
uint16 :old_credential_count
|
69
|
-
uint16 :older_credential_count
|
70
|
-
uint16 :default_salt_length
|
71
|
-
uint16 :default_salt_maximum_length
|
72
|
-
uint32 :default_salt_offset
|
73
|
-
uint32 :default_iteration_count
|
74
|
-
array :credentials, type: :kerb_key_data_new, initial_length: :credential_count
|
75
|
-
array :service_credentials, type: :kerb_key_data_new, initial_length: :service_credential_count
|
76
|
-
array :old_credentials, type: :kerb_key_data_new, initial_length: :old_credential_count
|
77
|
-
array :older_credentials, type: :kerb_key_data_new, initial_length: :older_credential_count
|
78
|
-
string :default_salt, read_length: -> { credentials.map { |e| e.key_offset }.min - @obj.abs_offset }
|
79
|
-
string :key_values, read_length: -> { credentials.map { |e| e.key_length }.sum }
|
80
|
-
|
81
|
-
def get_key_values
|
82
|
-
credentials.map do |credential|
|
83
|
-
offset = credential.key_offset - key_values.abs_offset
|
84
|
-
key_values[offset, credential.key_length]
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
|
90
9
|
#################################
|
91
10
|
# Constants #
|
92
11
|
#################################
|
93
12
|
|
13
|
+
# Operation numbers
|
14
|
+
SAMR_CONNECT = 0x0000
|
15
|
+
SAMR_CLOSE_HANDLE = 0x0001
|
16
|
+
SAMR_LOOKUP_DOMAIN_IN_SAM_SERVER = 0x0005
|
17
|
+
SAMR_ENUMERATE_DOMAINS_IN_SAM_SERVER = 0x0006
|
18
|
+
SAMR_OPEN_DOMAIN = 0x0007
|
19
|
+
SAMR_ENUMERATE_USERS_IN_DOMAIN = 0x000D
|
20
|
+
SAMR_GET_ALIAS_MEMBERSHIP = 0x0010
|
21
|
+
SAMR_LOOKUP_NAMES_IN_DOMAIN = 0x0011
|
22
|
+
SAMR_OPEN_USER = 0x0022
|
23
|
+
SAMR_DELETE_USER = 0x0023
|
24
|
+
SAMR_GET_GROUPS_FOR_USER = 0x0027
|
25
|
+
SAMR_CREATE_USER2_IN_DOMAIN = 0x0032
|
26
|
+
SAMR_SET_INFORMATION_USER2 = 0x003a
|
27
|
+
SAMR_CONNECT5 = 0x0040
|
28
|
+
SAMR_RID_TO_SID = 0x0041
|
94
29
|
|
95
30
|
################
|
96
31
|
# ACCESS_MASK Values
|
@@ -204,6 +139,33 @@ module RubySMB
|
|
204
139
|
USER_ALL_SECURITYDESCRIPTOR = 0x10000000
|
205
140
|
USER_ALL_UNDEFINED_MASK = 0xC0000000
|
206
141
|
|
142
|
+
# [2.2.6.28 USER_INFORMATION_CLASS Values](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/6b0dff90-5ac0-429a-93aa-150334adabf6)
|
143
|
+
USER_GENERAL_INFORMATION = 1
|
144
|
+
USER_PREFERENCES_INFORMATION = 2
|
145
|
+
USER_LOGON_INFORMATION = 3
|
146
|
+
USER_LOGON_HOURS_INFORMATION = 4
|
147
|
+
USER_ACCOUNT_INFORMATION = 5
|
148
|
+
USER_NAME_INFORMATION = 6
|
149
|
+
USER_ACCOUNT_NAME_INFORMATION = 7
|
150
|
+
USER_FULL_NAME_INFORMATION = 8
|
151
|
+
USER_PRIMARY_GROUP_INFORMATION = 9
|
152
|
+
USER_HOME_INFORMATION = 10
|
153
|
+
USER_SCRIPT_INFORMATION = 11
|
154
|
+
USER_PROFILE_INFORMATION = 12
|
155
|
+
USER_ADMIN_COMMENT_INFORMATION = 13
|
156
|
+
USER_WORK_STATIONS_INFORMATION = 14
|
157
|
+
USER_CONTROL_INFORMATION = 16
|
158
|
+
USER_EXPIRES_INFORMATION = 17
|
159
|
+
USER_INTERNAL1_INFORMATION = 18
|
160
|
+
USER_PARAMETERS_INFORMATION = 20
|
161
|
+
USER_ALL_INFORMATION = 21
|
162
|
+
USER_INTERNAL4_INFORMATION = 23
|
163
|
+
USER_INTERNAL5_INFORMATION = 24
|
164
|
+
USER_INTERNAL4_INFORMATION_NEW = 25
|
165
|
+
USER_INTERNAL5_INFORMATION_NEW = 26
|
166
|
+
USER_INTERNAL7_INFORMATION = 31
|
167
|
+
USER_INTERNAL8_INFORMATION = 32
|
168
|
+
|
207
169
|
# [2.2.1.9 ACCOUNT_TYPE Values](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/e742be45-665d-4576-b872-0bc99d1e1fbe)
|
208
170
|
SAM_DOMAIN_OBJECT = 0x00000000
|
209
171
|
SAM_GROUP_OBJECT = 0x10000000
|
@@ -300,14 +262,229 @@ module RubySMB
|
|
300
262
|
0xffffff74 => 'rc4_hmac'
|
301
263
|
}
|
302
264
|
|
265
|
+
# [2.2.3.9 SAMPR_RID_ENUMERATION](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/5c94a35a-e7f2-4675-af34-741f5a8ee1a2)
|
266
|
+
class SamprRidEnumeration < Ndr::NdrStruct
|
267
|
+
default_parameters byte_align: 4
|
268
|
+
endian :little
|
269
|
+
|
270
|
+
ndr_uint32 :relative_id
|
271
|
+
rpc_unicode_string :name
|
272
|
+
end
|
273
|
+
|
274
|
+
class SamprRidEnumerationArray < Ndr::NdrConfArray
|
275
|
+
default_parameter type: :sampr_rid_enumeration
|
276
|
+
end
|
277
|
+
|
278
|
+
class PsamprRidEnumerationArray < SamprRidEnumerationArray
|
279
|
+
extend Ndr::PointerClassPlugin
|
280
|
+
end
|
281
|
+
|
282
|
+
# [2.2.3.10 SAMPR_ENUMERATION_BUFFER](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/c53161a4-38e8-4a28-a33e-0d378fce03dd)
|
283
|
+
class SamprEnumerationBuffer < Ndr::NdrStruct
|
284
|
+
default_parameters byte_align: 4
|
285
|
+
endian :little
|
286
|
+
|
287
|
+
ndr_uint32 :entries_read
|
288
|
+
psampr_rid_enumeration_array :buffer
|
289
|
+
end
|
290
|
+
|
291
|
+
class PsamprEnumerationBuffer < SamprEnumerationBuffer
|
292
|
+
extend Ndr::PointerClassPlugin
|
293
|
+
end
|
294
|
+
|
295
|
+
class SamprHandle < Ndr::NdrContextHandle; end
|
296
|
+
|
297
|
+
class PulongArray < Ndr::NdrConfArray
|
298
|
+
default_parameter type: :ndr_uint32
|
299
|
+
extend Ndr::PointerClassPlugin
|
300
|
+
end
|
301
|
+
|
302
|
+
# [2.2.7.4 SAMPR_ULONG_ARRAY](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/2feb3806-4db2-45b7-90d2-86c8336a31ba)
|
303
|
+
class SamprUlongArray < Ndr::NdrStruct
|
304
|
+
default_parameter byte_align: 4
|
305
|
+
|
306
|
+
ndr_uint32 :element_count, initial_value: -> { elements.size }
|
307
|
+
pulong_array :elements
|
308
|
+
end
|
309
|
+
|
310
|
+
# [2.2.2.4 RPC_SHORT_BLOB](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/77dbfdbb-6627-4871-ab12-5333929347dc)
|
311
|
+
class RpcShortBlob < BinData::Record
|
312
|
+
ndr_uint16 :buffer_length, initial_value: -> { buffer.length }
|
313
|
+
ndr_uint16 :max_length, initial_value: -> { buffer.length }
|
314
|
+
ndr_uint16_array_ptr :buffer
|
315
|
+
end
|
316
|
+
|
317
|
+
# [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)
|
318
|
+
class SamprEncryptedUserPasswordNew < BinData::Record
|
319
|
+
ndr_fixed_byte_array :buffer, initial_length: 532
|
320
|
+
|
321
|
+
def self.encrypt_password(password, key)
|
322
|
+
# see: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/5fe3c4c4-e71b-440d-b2fd-8448bfaf6e04
|
323
|
+
password = password.encode('UTF-16LE').force_encoding('ASCII-8bit')
|
324
|
+
buffer = password.rjust(512, "\x00") + [ password.length ].pack('V')
|
325
|
+
salt = SecureRandom.random_bytes(16)
|
326
|
+
key = OpenSSL::Digest::MD5.new(salt + key).digest
|
327
|
+
cipher = OpenSSL::Cipher.new('RC4').tap do |cipher|
|
328
|
+
cipher.encrypt
|
329
|
+
cipher.key = key
|
330
|
+
end
|
331
|
+
cipher.update(buffer) + salt
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
# [2.2.6.5 SAMPR_LOGON_HOURS](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/d83c356b-7dda-4096-8270-5c581f84a4d9)
|
336
|
+
class SamprLogonHours < BinData::Record
|
337
|
+
ndr_uint16 :units_per_week
|
338
|
+
ndr_byte_array_ptr :logon_hours
|
339
|
+
end
|
340
|
+
|
341
|
+
# [2.2.7.11 SAMPR_SR_SECURITY_DESCRIPTOR](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/675e37d9-bb97-4f14-bba2-be081c87cd5d)
|
342
|
+
class SamprSrSecurityDescriptor < BinData::Record
|
343
|
+
ndr_uint32 :buffer_length, initial_value: -> { buffer.length }
|
344
|
+
ndr_byte_array_ptr :buffer
|
345
|
+
end
|
346
|
+
|
347
|
+
# [2.2.6.6 SAMPR_USER_ALL_INFORMATION](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/dc966b81-da27-4dae-a28c-ec16534f1cb9)
|
348
|
+
class SamprUserAllInformation < BinData::Record
|
349
|
+
ndr_uint64 :last_logon
|
350
|
+
ndr_uint64 :last_logoff
|
351
|
+
ndr_uint64 :password_last_set
|
352
|
+
ndr_uint64 :account_expires
|
353
|
+
ndr_uint64 :password_can_change
|
354
|
+
ndr_uint64 :password_must_change
|
355
|
+
rpc_unicode_string :user_name
|
356
|
+
rpc_unicode_string :full_name
|
357
|
+
rpc_unicode_string :home_directory
|
358
|
+
rpc_unicode_string :home_directory_drive
|
359
|
+
rpc_unicode_string :script_path
|
360
|
+
rpc_unicode_string :profile_path
|
361
|
+
rpc_unicode_string :admin_comment
|
362
|
+
rpc_unicode_string :work_stations
|
363
|
+
rpc_unicode_string :user_comment
|
364
|
+
rpc_unicode_string :parameters
|
365
|
+
rpc_short_blob :lm_owf_password
|
366
|
+
rpc_short_blob :nt_owf_password
|
367
|
+
rpc_unicode_string :private_data
|
368
|
+
sampr_sr_security_descriptor :security_descriptor
|
369
|
+
ndr_uint32 :user_id
|
370
|
+
ndr_uint32 :primary_group_id
|
371
|
+
ndr_uint32 :user_account_control
|
372
|
+
ndr_uint32 :which_fields
|
373
|
+
sampr_logon_hours :logon_hours
|
374
|
+
ndr_uint16 :bad_password_count
|
375
|
+
ndr_uint16 :logon_count
|
376
|
+
ndr_uint16 :country_code
|
377
|
+
ndr_uint16 :code_page
|
378
|
+
ndr_uint8 :lm_password_present
|
379
|
+
ndr_uint8 :nt_password_present
|
380
|
+
ndr_uint8 :password_expired
|
381
|
+
ndr_uint8 :private_data_sensitive
|
382
|
+
end
|
383
|
+
|
384
|
+
# [2.2.6.25 SAMPR_USER_INTERNAL4_INFORMATION_NEW](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/b2f614b9-0312-421a-abed-10ee002ef780)
|
385
|
+
class SamprUserInternal4InformationNew < BinData::Record
|
386
|
+
sampr_user_all_information :i1
|
387
|
+
sampr_encrypted_user_password_new :user_password
|
388
|
+
end
|
389
|
+
|
390
|
+
# [2.2.6.3 USER_CONTROL_INFORMATION](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/eb5f1508-ede1-4ff1-be82-55f3e2ef1633)
|
391
|
+
class UserControlInformation < BinData::Record
|
392
|
+
endian :little
|
393
|
+
|
394
|
+
ndr_uint32 :user_account_control
|
395
|
+
end
|
396
|
+
|
397
|
+
# [2.2.6.29 SAMPR_USER_INFO_BUFFER](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/9496c26e-490b-4e76-827f-2695fc216f35)
|
398
|
+
class SamprUserInfoBuffer < BinData::Record
|
399
|
+
ndr_uint16 :tag
|
400
|
+
choice :member, selection: :tag do
|
401
|
+
user_control_information USER_CONTROL_INFORMATION
|
402
|
+
sampr_user_internal4_information_new USER_INTERNAL4_INFORMATION_NEW
|
403
|
+
end
|
404
|
+
end
|
405
|
+
|
406
|
+
# [2.2.10.2 USER_PROPERTY](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/7c0f2eca-1783-450b-b5a0-754cf11f22c9)
|
407
|
+
class UserProperty < BinData::Record
|
408
|
+
endian :little
|
409
|
+
|
410
|
+
uint16 :name_length, initial_value: -> { property_name.num_bytes }
|
411
|
+
uint16 :value_length, initial_value: -> { property_value.num_bytes }
|
412
|
+
uint16 :reserved
|
413
|
+
string16 :property_name, read_length: :name_length
|
414
|
+
string :property_value, read_length: :value_length
|
415
|
+
end
|
416
|
+
|
417
|
+
# [2.2.10.1 USER_PROPERTIES](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/8263e7ab-aba9-43d2-8a36-3a9cb2dd3dad)
|
418
|
+
class UserProperties < BinData::Record
|
419
|
+
endian :little
|
420
|
+
|
421
|
+
uint32 :reserved1
|
422
|
+
uint32 :struct_length, initial_value: -> { num_bytes - 12 }
|
423
|
+
uint16 :reserved2
|
424
|
+
uint16 :reserved3
|
425
|
+
string :reserved4, length: 96
|
426
|
+
uint16 :property_signature, initial_value: 0x50
|
427
|
+
uint16 :property_count, initial_value: -> { user_properties.size }
|
428
|
+
array :user_properties, type: :user_property, initial_length: :property_count
|
429
|
+
uint8 :reserved5
|
430
|
+
end
|
431
|
+
|
432
|
+
# [2.2.10.7 KERB_KEY_DATA_NEW](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/447520a5-e1cc-48cc-8fdc-b90db57f7eac)
|
433
|
+
class KerbKeyDataNew < BinData::Record
|
434
|
+
endian :little
|
435
|
+
|
436
|
+
uint16 :reserved1
|
437
|
+
uint16 :reserved2
|
438
|
+
uint32 :reserved3
|
439
|
+
uint32 :iteration_count
|
440
|
+
uint32 :key_type
|
441
|
+
uint32 :key_length
|
442
|
+
uint32 :key_offset
|
443
|
+
end
|
444
|
+
|
445
|
+
# [2.2.10.6 Primary:Kerberos-Newer-Keys - KERB_STORED_CREDENTIAL_NEW](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/08cb3ca7-954b-45e3-902e-77512fe3ba8e)
|
446
|
+
class KerbStoredCredentialNew < BinData::Record
|
447
|
+
endian :little
|
448
|
+
|
449
|
+
uint16 :revision
|
450
|
+
uint16 :flags
|
451
|
+
uint16 :credential_count
|
452
|
+
uint16 :service_credential_count
|
453
|
+
uint16 :old_credential_count
|
454
|
+
uint16 :older_credential_count
|
455
|
+
uint16 :default_salt_length
|
456
|
+
uint16 :default_salt_maximum_length
|
457
|
+
uint32 :default_salt_offset
|
458
|
+
uint32 :default_iteration_count
|
459
|
+
array :credentials, type: :kerb_key_data_new, initial_length: :credential_count
|
460
|
+
array :service_credentials, type: :kerb_key_data_new, initial_length: :service_credential_count
|
461
|
+
array :old_credentials, type: :kerb_key_data_new, initial_length: :old_credential_count
|
462
|
+
array :older_credentials, type: :kerb_key_data_new, initial_length: :older_credential_count
|
463
|
+
string :default_salt, read_length: -> { credentials.map { |e| e.key_offset }.min - @obj.abs_offset }
|
464
|
+
string :key_values, read_length: -> { credentials.map { |e| e.key_length }.sum }
|
465
|
+
|
466
|
+
def get_key_values
|
467
|
+
credentials.map do |credential|
|
468
|
+
offset = credential.key_offset - key_values.abs_offset
|
469
|
+
key_values[offset, credential.key_length]
|
470
|
+
end
|
471
|
+
end
|
472
|
+
end
|
473
|
+
|
303
474
|
require 'ruby_smb/dcerpc/samr/rpc_sid'
|
304
475
|
|
305
476
|
require 'ruby_smb/dcerpc/samr/samr_connect_request'
|
306
477
|
require 'ruby_smb/dcerpc/samr/samr_connect_response'
|
478
|
+
require 'ruby_smb/dcerpc/samr/samr_create_user2_in_domain_request'
|
479
|
+
require 'ruby_smb/dcerpc/samr/samr_create_user2_in_domain_response'
|
307
480
|
require 'ruby_smb/dcerpc/samr/samr_lookup_domain_in_sam_server_request'
|
308
481
|
require 'ruby_smb/dcerpc/samr/samr_lookup_domain_in_sam_server_response'
|
482
|
+
require 'ruby_smb/dcerpc/samr/samr_lookup_names_in_domain_request'
|
483
|
+
require 'ruby_smb/dcerpc/samr/samr_lookup_names_in_domain_response'
|
309
484
|
require 'ruby_smb/dcerpc/samr/samr_open_domain_request'
|
310
485
|
require 'ruby_smb/dcerpc/samr/samr_open_domain_response'
|
486
|
+
require 'ruby_smb/dcerpc/samr/samr_enumerate_domains_in_sam_server_request'
|
487
|
+
require 'ruby_smb/dcerpc/samr/samr_enumerate_domains_in_sam_server_response'
|
311
488
|
require 'ruby_smb/dcerpc/samr/samr_enumerate_users_in_domain_request'
|
312
489
|
require 'ruby_smb/dcerpc/samr/samr_enumerate_users_in_domain_response'
|
313
490
|
require 'ruby_smb/dcerpc/samr/samr_rid_to_sid_request'
|
@@ -320,6 +497,10 @@ module RubySMB
|
|
320
497
|
require 'ruby_smb/dcerpc/samr/samr_open_user_response'
|
321
498
|
require 'ruby_smb/dcerpc/samr/samr_get_groups_for_user_request'
|
322
499
|
require 'ruby_smb/dcerpc/samr/samr_get_groups_for_user_response'
|
500
|
+
require 'ruby_smb/dcerpc/samr/samr_set_information_user2_request'
|
501
|
+
require 'ruby_smb/dcerpc/samr/samr_set_information_user2_response'
|
502
|
+
require 'ruby_smb/dcerpc/samr/samr_delete_user_request'
|
503
|
+
require 'ruby_smb/dcerpc/samr/samr_delete_user_response'
|
323
504
|
|
324
505
|
# Returns a handle to a server object.
|
325
506
|
#
|
@@ -352,6 +533,75 @@ module RubySMB
|
|
352
533
|
samr_connect_response.server_handle
|
353
534
|
end
|
354
535
|
|
536
|
+
# Create a new user.
|
537
|
+
#
|
538
|
+
# @param domain_handle [RubySMB::Dcerpc::Samr::SamprHandle] RPC context
|
539
|
+
# handle representing the domain object
|
540
|
+
# @param name [String] The name of the account to add
|
541
|
+
# @param account_type [Integer] The type of account to add, one of either
|
542
|
+
# USER_NORMAL_ACCOUNT, USER_WORKSTATION_TRUST_ACCOUNT, or
|
543
|
+
# USER_SERVER_TRUST_ACCOUNT
|
544
|
+
# @param desired_access [Integer] The access requested on the returned
|
545
|
+
# object
|
546
|
+
# @return [RubySMB::Dcerpc::Samr::SamprHandle] handle to the server object.
|
547
|
+
# @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a
|
548
|
+
# SamrConnectResponse packet
|
549
|
+
# @raise [RubySMB::Dcerpc::Error::SamrError] if the response error status
|
550
|
+
# is not STATUS_SUCCESS
|
551
|
+
def samr_create_user2_in_domain(domain_handle:, name:, account_type: USER_NORMAL_ACCOUNT, desired_access: GROUP_ALL_ACCESS)
|
552
|
+
samr_create_request = SamrCreateUser2InDomainRequest.new(
|
553
|
+
domain_handle: domain_handle,
|
554
|
+
name: name,
|
555
|
+
account_type: account_type,
|
556
|
+
desired_access: desired_access
|
557
|
+
)
|
558
|
+
response = dcerpc_request(samr_create_request)
|
559
|
+
begin
|
560
|
+
samr_create_response = SamrCreateUser2InDomainResponse.read(response)
|
561
|
+
rescue IOError
|
562
|
+
raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading SamrCreateUser2InDomainResponse'
|
563
|
+
end
|
564
|
+
unless samr_create_response.error_status == WindowsError::NTStatus::STATUS_SUCCESS
|
565
|
+
raise RubySMB::Dcerpc::Error::SamrError,
|
566
|
+
"Error returned with samr_create_user2_in_domain: "\
|
567
|
+
"#{WindowsError::NTStatus.find_by_retval(samr_create_response.error_status.value).join(',')}"
|
568
|
+
end
|
569
|
+
|
570
|
+
{
|
571
|
+
user_handle: samr_create_response.user_handle,
|
572
|
+
granted_access: samr_create_response.granted_access.to_i,
|
573
|
+
relative_id: samr_create_response.relative_id.to_i
|
574
|
+
}
|
575
|
+
end
|
576
|
+
|
577
|
+
# Delete an existing user.
|
578
|
+
#
|
579
|
+
# @param user_handle [RubySMB::Dcerpc::Samr::SamprHandle] RPC context
|
580
|
+
# handle representing the user object to delete
|
581
|
+
# @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a
|
582
|
+
# SamrDeleteUserResponse packet
|
583
|
+
# @raise [RubySMB::Dcerpc::Error::SamrError] if the response error status
|
584
|
+
# is not STATUS_SUCCESS
|
585
|
+
def samr_delete_user(user_handle:)
|
586
|
+
samr_delete_user_request = SamrDeleteUserRequest.new(
|
587
|
+
user_handle: user_handle
|
588
|
+
)
|
589
|
+
|
590
|
+
response = dcerpc_request(samr_delete_user_request)
|
591
|
+
begin
|
592
|
+
samr_delete_user_response = SamrDeleteUserResponse.read(response)
|
593
|
+
rescue IOError
|
594
|
+
raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading SamrDeleteUserResponse'
|
595
|
+
end
|
596
|
+
unless samr_delete_user_response.error_status == WindowsError::NTStatus::STATUS_SUCCESS
|
597
|
+
raise RubySMB::Dcerpc::Error::SamrError,
|
598
|
+
"Error returned while deleting user in SAM server: "\
|
599
|
+
"#{WindowsError::NTStatus.find_by_retval(samr_delete_user_response.error_status.value).join(',')}"
|
600
|
+
end
|
601
|
+
|
602
|
+
nil
|
603
|
+
end
|
604
|
+
|
355
605
|
# Obtains the SID of a domain object
|
356
606
|
#
|
357
607
|
# @param server_handle [RubySMB::Dcerpc::Samr::SamprHandle] RPC context
|
@@ -382,6 +632,50 @@ module RubySMB
|
|
382
632
|
samr_lookup_domain_in_sam_server_response.domain_id
|
383
633
|
end
|
384
634
|
|
635
|
+
# Obtains the SID of a domain object
|
636
|
+
#
|
637
|
+
# @param domain_handle [RubySMB::Dcerpc::Samr::SamprHandle] RPC context
|
638
|
+
# handle representing the domain object
|
639
|
+
# @param name [Array<String>] An array of string account names to
|
640
|
+
# translate to RIDs.
|
641
|
+
# @return [Hash<String, Hash<Symbol, Integer>>, Nil] Returns a hash mapping
|
642
|
+
# the requested names to their information. Nil is returned if one or
|
643
|
+
# more names could not be found.
|
644
|
+
# @raise [RubySMB::Dcerpc::Error::SamrError] if the response error status
|
645
|
+
# is not STATUS_SUCCESS, STATUS_NONE_MAPPED, or STATUS_SOME_NOT_MAPPED
|
646
|
+
def samr_lookup_names_in_domain(domain_handle:, names:)
|
647
|
+
raise ArgumentError.new('names may not be longer than 1000') if names.length > 1000
|
648
|
+
|
649
|
+
samr_lookup_request = SamrLookupNamesInDomainRequest.new(
|
650
|
+
domain_handle: domain_handle,
|
651
|
+
names_count: names.length,
|
652
|
+
names: names
|
653
|
+
)
|
654
|
+
samr_lookup_request.names.set_max_count(1000)
|
655
|
+
response = dcerpc_request(samr_lookup_request)
|
656
|
+
begin
|
657
|
+
samr_lookup_response = SamrLookupNamesInDomainResponse.read(response)
|
658
|
+
rescue IOError
|
659
|
+
raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading SamrLookupNamesInDomainResponse'
|
660
|
+
end
|
661
|
+
return nil if samr_lookup_response.error_status == WindowsError::NTStatus::STATUS_NONE_MAPPED
|
662
|
+
return nil if samr_lookup_response.error_status == WindowsError::NTStatus::STATUS_SOME_NOT_MAPPED
|
663
|
+
unless samr_lookup_response.error_status == WindowsError::NTStatus::STATUS_SUCCESS
|
664
|
+
raise RubySMB::Dcerpc::Error::SamrError,
|
665
|
+
"Error returned during names lookup in SAM server: "\
|
666
|
+
"#{WindowsError::NTStatus.find_by_retval(samr_lookup_response.error_status.value).join(',')}"
|
667
|
+
end
|
668
|
+
|
669
|
+
result = {}
|
670
|
+
names.each_with_index do |name, index|
|
671
|
+
result[name] = {
|
672
|
+
rid: samr_lookup_response.relative_ids.elements[index].to_i,
|
673
|
+
use: samr_lookup_response.use.elements[index].to_i
|
674
|
+
}
|
675
|
+
end
|
676
|
+
result
|
677
|
+
end
|
678
|
+
|
385
679
|
# Returns a handle to a domain object.
|
386
680
|
#
|
387
681
|
# @param server_handle [RubySMB::Dcerpc::Samr::SamprHandle] RPC context
|
@@ -415,11 +709,58 @@ module RubySMB
|
|
415
709
|
samr_open_domain_response.domain_handle
|
416
710
|
end
|
417
711
|
|
712
|
+
# Enumerates all domains on the remote server.
|
713
|
+
#
|
714
|
+
# @param server_handle [RubySMB::Dcerpc::Samr::SamprHandle] RPC context
|
715
|
+
# handle representing the server object
|
716
|
+
# @param enumeration_context [Integer] a cookie used by the server to
|
717
|
+
# resume an enumeration
|
718
|
+
# @return [Array<String>] an array containing the domain names
|
719
|
+
# @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a
|
720
|
+
# SamrEnumerateDomainsInSamServerResponse packet
|
721
|
+
# @raise [RubySMB::Dcerpc::Error::SamrError] if the response error status
|
722
|
+
# is not STATUS_SUCCESS
|
723
|
+
def samr_enumerate_domains_in_sam_server(server_handle:, enumeration_context: 0)
|
724
|
+
samr_enum_domains_request = SamrEnumerateDomainsInSamServerRequest.new(
|
725
|
+
server_handle: server_handle,
|
726
|
+
enumeration_context: enumeration_context,
|
727
|
+
prefered_maximum_length: 0xFFFFFFFF
|
728
|
+
)
|
729
|
+
res = []
|
730
|
+
loop do
|
731
|
+
samr_enum_domains_request.enumeration_context = enumeration_context
|
732
|
+
response = dcerpc_request(samr_enum_domains_request)
|
733
|
+
begin
|
734
|
+
samr_enum_domains_reponse = SamrEnumerateDomainsInSamServerResponse.read(response)
|
735
|
+
rescue IOError
|
736
|
+
raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading SamrEnumerateDomainsInSamServerResponse'
|
737
|
+
end
|
738
|
+
unless samr_enum_domains_reponse.error_status == WindowsError::NTStatus::STATUS_SUCCESS ||
|
739
|
+
samr_enum_domains_reponse.error_status == WindowsError::NTStatus::STATUS_MORE_ENTRIES
|
740
|
+
raise RubySMB::Dcerpc::Error::SamrError,
|
741
|
+
"Error returned during domains enumeration in SAM server: "\
|
742
|
+
"#{WindowsError::NTStatus.find_by_retval(samr_enum_domains_reponse.error_status.value).join(',')}"
|
743
|
+
end
|
744
|
+
samr_enum_domains_reponse.buffer.buffer.each_with_object(res) do |entry, array|
|
745
|
+
array << entry.name.buffer
|
746
|
+
end
|
747
|
+
break unless samr_enum_domains_reponse.error_status == WindowsError::NTStatus::STATUS_MORE_ENTRIES
|
748
|
+
|
749
|
+
enumeration_context = samr_enum_domains_reponse.enumeration_context
|
750
|
+
end
|
751
|
+
|
752
|
+
res
|
753
|
+
end
|
754
|
+
|
418
755
|
# Enumerates all users in the specified domain.
|
419
756
|
#
|
420
757
|
# @param domain_handle [RubySMB::Dcerpc::Samr::SamprHandle] RPC context
|
421
758
|
# handle representing the domain object
|
422
|
-
# @
|
759
|
+
# @param enumeration_context [Integer] a cookie used by the server to
|
760
|
+
# resume an enumeration
|
761
|
+
# @param user_account_control [Integer] a value to use for filtering on
|
762
|
+
# the userAccountControl attribute
|
763
|
+
# @return [Hash<Integer, String>] hash mapping RID and username
|
423
764
|
# @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a
|
424
765
|
# SamrEnumerateUsersInDomainResponse packet
|
425
766
|
# @raise [RubySMB::Dcerpc::Error::SamrError] if the response error status
|
@@ -486,6 +827,35 @@ module RubySMB
|
|
486
827
|
samr_rid_to_sid_response.sid
|
487
828
|
end
|
488
829
|
|
830
|
+
# Update attributes on a user object.
|
831
|
+
#
|
832
|
+
# @param user_handle [RubySMB::Dcerpc::Samr::SamprHandle] An RPC context
|
833
|
+
# representing a user object.
|
834
|
+
# @param user_info: [RubySMB::Dcerpc::Samr::SamprUserInfoBuffer] the user
|
835
|
+
# information to set.
|
836
|
+
# @return nothing is returned on success
|
837
|
+
# @raise [RubySMB::Dcerpc::Error::SamrError] if the response error status
|
838
|
+
# is not STATUS_SUCCESS
|
839
|
+
def samr_set_information_user2(user_handle:, user_info:)
|
840
|
+
samr_set_information_user2_request = SamrSetInformationUser2Request.new(
|
841
|
+
user_handle: user_handle,
|
842
|
+
buffer: user_info
|
843
|
+
)
|
844
|
+
response = dcerpc_request(samr_set_information_user2_request)
|
845
|
+
begin
|
846
|
+
samr_set_information_user2_response = SamrSetInformationUser2Response.read(response)
|
847
|
+
rescue IOError
|
848
|
+
raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading SamrSetInformationUser2Response'
|
849
|
+
end
|
850
|
+
unless samr_set_information_user2_response.error_status == WindowsError::NTStatus::STATUS_SUCCESS
|
851
|
+
raise RubySMB::Dcerpc::Error::SamrError,
|
852
|
+
"Error returned while setting user information: "\
|
853
|
+
"#{WindowsError::NTStatus.find_by_retval(samr_set_information_user2_response.error_status.value).join(',')}"
|
854
|
+
end
|
855
|
+
|
856
|
+
nil
|
857
|
+
end
|
858
|
+
|
489
859
|
# Closes (that is, releases server-side resources used by) any context
|
490
860
|
# handle obtained from this RPC interface
|
491
861
|
#
|
@@ -541,7 +911,7 @@ module RubySMB
|
|
541
911
|
"Error returned while getting alias membership: "\
|
542
912
|
"#{WindowsError::NTStatus.find_by_retval(samr_get_alias_membership_reponse.error_status.value).join(',')}"
|
543
913
|
end
|
544
|
-
return [] if samr_get_alias_membership_reponse.membership.
|
914
|
+
return [] if samr_get_alias_membership_reponse.membership.element_count == 0
|
545
915
|
samr_get_alias_membership_reponse.membership.elements.to_ary
|
546
916
|
end
|
547
917
|
|
data/lib/ruby_smb/dcerpc.rb
CHANGED
data/lib/ruby_smb/error.rb
CHANGED
@@ -99,6 +99,10 @@ module RubySMB
|
|
99
99
|
# unsupported protocol.
|
100
100
|
class NegotiationFailure < RubySMBError; end
|
101
101
|
|
102
|
+
# Raised when Authentication fails, possibly due to an
|
103
|
+
# unsupported GSS mechanism type.
|
104
|
+
class AuthenticationFailure < RubySMBError; end
|
105
|
+
|
102
106
|
# Raised when trying to parse raw binary into a BitField and the data
|
103
107
|
# is invalid.
|
104
108
|
class InvalidBitField < RubySMBError; end
|
data/lib/ruby_smb/gss.rb
CHANGED
@@ -14,6 +14,7 @@ module RubySMB
|
|
14
14
|
# @param asn The ASN object to apply the traversal path on.
|
15
15
|
# @param [Array] path The path to traverse, each element is passed to the
|
16
16
|
# ASN object's #value's #[] operator.
|
17
|
+
# @return [OpenSSL::ASN1::Sequence, nil]
|
17
18
|
def self.asn1dig(asn, *path)
|
18
19
|
path.each do |part|
|
19
20
|
return nil unless asn&.value
|