ruby_smb 3.1.2 → 3.1.5
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/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
|