ruby_smb 3.2.0 → 3.3.0
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/.github/workflows/verify.yml +8 -9
- data/README.md +1 -0
- data/cortex.yaml +15 -0
- data/examples/dump_secrets_from_sid.rb +2 -1
- data/lib/ruby_smb/client.rb +6 -4
- data/lib/ruby_smb/dcerpc/alter_context.rb +30 -0
- data/lib/ruby_smb/dcerpc/alter_context_resp.rb +42 -0
- data/lib/ruby_smb/dcerpc/bind.rb +3 -35
- data/lib/ruby_smb/dcerpc/bind_ack.rb +0 -31
- data/lib/ruby_smb/dcerpc/client.rb +10 -4
- data/lib/ruby_smb/dcerpc/drsr.rb +13 -13
- data/lib/ruby_smb/dcerpc/encrypting_file_system/efs_rpc_decrypt_file_srv_request.rb +22 -0
- data/lib/ruby_smb/dcerpc/encrypting_file_system/efs_rpc_decrypt_file_srv_response.rb +21 -0
- data/lib/ruby_smb/dcerpc/encrypting_file_system/efs_rpc_query_recover_agents_request.rb +20 -0
- data/lib/ruby_smb/dcerpc/encrypting_file_system/efs_rpc_query_recover_agents_response.rb +21 -0
- data/lib/ruby_smb/dcerpc/encrypting_file_system/efs_rpc_query_users_on_file_request.rb +20 -0
- data/lib/ruby_smb/dcerpc/encrypting_file_system/efs_rpc_query_users_on_file_response.rb +21 -0
- data/lib/ruby_smb/dcerpc/encrypting_file_system.rb +52 -0
- data/lib/ruby_smb/dcerpc/icpr.rb +3 -2
- data/lib/ruby_smb/dcerpc/ndr.rb +148 -3
- data/lib/ruby_smb/dcerpc/p_cont_list_t.rb +37 -0
- data/lib/ruby_smb/dcerpc/p_result_list_t.rb +13 -0
- data/lib/ruby_smb/dcerpc/p_result_t.rb +15 -0
- data/lib/ruby_smb/dcerpc/port_any_t.rb +11 -0
- data/lib/ruby_smb/dcerpc/request.rb +8 -3
- data/lib/ruby_smb/dcerpc/response.rb +6 -1
- data/lib/ruby_smb/dcerpc/samr.rb +4 -2
- data/lib/ruby_smb/dcerpc.rb +165 -122
- data/lib/ruby_smb/dispatcher/socket.rb +1 -1
- data/lib/ruby_smb/field/file_time.rb +2 -2
- data/lib/ruby_smb/field/utime.rb +2 -2
- data/lib/ruby_smb/generic_packet.rb +2 -2
- data/lib/ruby_smb/gss/provider/ntlm.rb +12 -5
- data/lib/ruby_smb/ntlm/client.rb +4 -0
- data/lib/ruby_smb/ntlm/custom/string_encoder.rb +22 -0
- data/lib/ruby_smb/ntlm.rb +37 -0
- data/lib/ruby_smb/server/server_client/share_io.rb +2 -2
- data/lib/ruby_smb/server/server_client/tree_connect.rb +2 -2
- data/lib/ruby_smb/server/share/provider/disk.rb +2 -2
- data/lib/ruby_smb/server/share/provider/processor.rb +25 -0
- data/lib/ruby_smb/server/share/provider/virtual_disk.rb +3 -3
- data/lib/ruby_smb/server/share/provider.rb +48 -1
- data/lib/ruby_smb/smb1/data_block.rb +2 -2
- data/lib/ruby_smb/smb1/packet/nt_create_andx_request.rb +1 -1
- data/lib/ruby_smb/smb1/parameter_block.rb +2 -2
- data/lib/ruby_smb/smb1/pipe.rb +4 -0
- data/lib/ruby_smb/smb2/create_context.rb +5 -2
- data/lib/ruby_smb/smb2/packet/negotiate_request.rb +5 -5
- data/lib/ruby_smb/smb2/packet/negotiate_response.rb +1 -1
- data/lib/ruby_smb/smb2/pipe.rb +4 -0
- data/lib/ruby_smb/smb2/tree.rb +3 -1
- data/lib/ruby_smb/utils.rb +15 -0
- data/lib/ruby_smb/version.rb +1 -1
- data/lib/ruby_smb.rb +2 -0
- data/spec/lib/ruby_smb/client_spec.rb +4 -4
- data/spec/lib/ruby_smb/dcerpc/client_spec.rb +31 -16
- data/spec/lib/ruby_smb/dcerpc/drsr_spec.rb +4 -1
- data/spec/lib/ruby_smb/dcerpc/ndr_spec.rb +198 -0
- data/spec/lib/ruby_smb/dcerpc/request_spec.rb +0 -6
- data/spec/lib/ruby_smb/dcerpc/response_spec.rb +4 -12
- data/spec/lib/ruby_smb/dcerpc/sec_trailer_spec.rb +0 -14
- data/spec/lib/ruby_smb/dcerpc/winreg_spec.rb +2 -2
- data/spec/lib/ruby_smb/smb1/packet/read_andx_request_spec.rb +2 -2
- data/spec/lib/ruby_smb/smb1/packet/write_andx_request_spec.rb +1 -1
- data/spec/lib/ruby_smb/smb2/create_context/create_context_request_spec.rb +35 -0
- data/spec/lib/ruby_smb/smb2/tree_spec.rb +5 -0
- data.tar.gz.sig +0 -0
- metadata +41 -86
- metadata.gz.sig +0 -0
data/lib/ruby_smb/dcerpc/ndr.rb
CHANGED
|
@@ -247,12 +247,22 @@ module RubySMB::Dcerpc::Ndr
|
|
|
247
247
|
|
|
248
248
|
def do_read(io)
|
|
249
249
|
if is_a?(ConfPlugin) && should_process_max_count?
|
|
250
|
-
|
|
250
|
+
max_count = io.readbytes(4).unpack1('L<')
|
|
251
|
+
BinData.trace_message do |tracer|
|
|
252
|
+
tracer.trace_obj("#{debug_name}.max_count", max_count.to_s)
|
|
253
|
+
end
|
|
254
|
+
set_max_count(max_count)
|
|
251
255
|
end
|
|
252
256
|
|
|
253
257
|
if is_a?(VarPlugin)
|
|
254
258
|
@offset = io.readbytes(4).unpack('L<').first
|
|
259
|
+
BinData.trace_message do |tracer|
|
|
260
|
+
tracer.trace_obj("#{debug_name}.offset", @offset.to_s)
|
|
261
|
+
end
|
|
255
262
|
@actual_count = @read_until_index = io.readbytes(4).unpack('L<').first
|
|
263
|
+
BinData.trace_message do |tracer|
|
|
264
|
+
tracer.trace_obj("#{debug_name}.actual_count", @actual_count.to_s)
|
|
265
|
+
end
|
|
256
266
|
end
|
|
257
267
|
|
|
258
268
|
if has_elements_to_read?
|
|
@@ -523,7 +533,11 @@ module RubySMB::Dcerpc::Ndr
|
|
|
523
533
|
|
|
524
534
|
def do_read(io)
|
|
525
535
|
if should_process_max_count?
|
|
526
|
-
|
|
536
|
+
max_count = io.readbytes(4).unpack1('L<')
|
|
537
|
+
BinData.trace_message do |tracer|
|
|
538
|
+
tracer.trace_obj("#{debug_name}.max_count", max_count.to_s)
|
|
539
|
+
end
|
|
540
|
+
set_max_count(max_count)
|
|
527
541
|
end
|
|
528
542
|
super
|
|
529
543
|
end
|
|
@@ -582,7 +596,13 @@ module RubySMB::Dcerpc::Ndr
|
|
|
582
596
|
|
|
583
597
|
def do_read(io)
|
|
584
598
|
@offset = io.readbytes(4).unpack('L<').first
|
|
599
|
+
BinData.trace_message do |tracer|
|
|
600
|
+
tracer.trace_obj("#{debug_name}.offset", @offset.to_s)
|
|
601
|
+
end
|
|
585
602
|
@actual_count = io.readbytes(4).unpack('L<').first
|
|
603
|
+
BinData.trace_message do |tracer|
|
|
604
|
+
tracer.trace_obj("#{debug_name}.actual_count", @actual_count.to_s)
|
|
605
|
+
end
|
|
586
606
|
super if @actual_count > 0
|
|
587
607
|
end
|
|
588
608
|
|
|
@@ -702,7 +722,11 @@ module RubySMB::Dcerpc::Ndr
|
|
|
702
722
|
|
|
703
723
|
def do_read(io)
|
|
704
724
|
if should_process_max_count?
|
|
705
|
-
|
|
725
|
+
max_count = io.readbytes(4).unpack1('L<')
|
|
726
|
+
BinData.trace_message do |tracer|
|
|
727
|
+
tracer.trace_obj("#{debug_name}.max_count", max_count.to_s)
|
|
728
|
+
end
|
|
729
|
+
set_max_count(max_count)
|
|
706
730
|
|
|
707
731
|
# Align the structure according to the alignment rules for the structure
|
|
708
732
|
if respond_to?(:referent_bytes_align)
|
|
@@ -1034,6 +1058,9 @@ module RubySMB::Dcerpc::Ndr
|
|
|
1034
1058
|
end
|
|
1035
1059
|
else
|
|
1036
1060
|
@ref_id = io.readbytes(4).unpack('L<').first
|
|
1061
|
+
BinData.trace_message do |tracer|
|
|
1062
|
+
tracer.trace_obj("#{debug_name}.ref_id", @ref_id.to_s)
|
|
1063
|
+
end
|
|
1037
1064
|
parent_obj = nil
|
|
1038
1065
|
if parent&.is_a?(ConstructedTypePlugin)
|
|
1039
1066
|
parent_obj = parent.get_top_level_constructed_type
|
|
@@ -1288,5 +1315,123 @@ module RubySMB::Dcerpc::Ndr
|
|
|
1288
1315
|
end
|
|
1289
1316
|
end
|
|
1290
1317
|
|
|
1318
|
+
# (IDL/NDR) Pickles as defined in
|
|
1319
|
+
# [(IDL/NDR) # Pickles](https://pubs.opengroup.org/onlinepubs/9668899/chap2.htm#tagcjh_05_01_07)
|
|
1320
|
+
# and
|
|
1321
|
+
# [2.2.6 Type Serialization Version # 1](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rpce/9a1d0f97-eac0-49ab-a197-f1a581c2d6a0)
|
|
1322
|
+
|
|
1323
|
+
# [2.2.6.1 Common Type Header for the Serialization Stream](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rpce/6d75d40e-e2d2-4420-b9e9-8508a726a9ae)
|
|
1324
|
+
class TypeSerialization1CommonTypeHeader < BinData::Record
|
|
1325
|
+
default_parameter byte_align: 8
|
|
1326
|
+
endian :little
|
|
1327
|
+
|
|
1328
|
+
uint8 :version, initial_value: 1
|
|
1329
|
+
uint8 :endianness, initial_value: 0x10
|
|
1330
|
+
uint16 :common_header_length, initial_value: 8
|
|
1331
|
+
uint32 :filler, initial_value: 0xCCCCCCCC
|
|
1332
|
+
end
|
|
1333
|
+
|
|
1334
|
+
# [2.2.6.2 Private Header for Constructed Type](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rpce/63949ba8-bc88-4c0c-9377-23f14b197827)
|
|
1335
|
+
class TypeSerialization1PrivateHeader < BinData::Record
|
|
1336
|
+
default_parameter byte_align: 8
|
|
1337
|
+
endian :little
|
|
1338
|
+
|
|
1339
|
+
uint32 :object_buffer_length, initial_value: -> { buffer_length(@obj) }
|
|
1340
|
+
uint32 :filler, initial_value: 0x00000000
|
|
1341
|
+
|
|
1342
|
+
def buffer_length(obj)
|
|
1343
|
+
parent.respond_to?(:field_length) ? parent.field_length(obj.parent) : 0
|
|
1344
|
+
end
|
|
1345
|
+
end
|
|
1346
|
+
|
|
1347
|
+
# [2.2.6 Type Serialization Version 1](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rpce/9a1d0f97-eac0-49ab-a197-f1a581c2d6a0)
|
|
1348
|
+
#
|
|
1349
|
+
# This structure is not meant to be instantiated directly. Instead, the
|
|
1350
|
+
# structure with the fields to be serialized needs to inherit from
|
|
1351
|
+
# TypeSerialization1. This class will take care of adding the
|
|
1352
|
+
# TypeSerialization1PrivateHeader fields in front of any NDR constructed type
|
|
1353
|
+
# structures and setting the buffer length field (:object_buffer_length) to
|
|
1354
|
+
# the correct value.
|
|
1355
|
+
#
|
|
1356
|
+
# Example:
|
|
1357
|
+
#
|
|
1358
|
+
# class TestStruct < RubySMB::Dcerpc::Ndr::NdrStruct
|
|
1359
|
+
# default_parameters byte_align: 8
|
|
1360
|
+
# endian :little
|
|
1361
|
+
|
|
1362
|
+
# rpc_unicode_string :full_name
|
|
1363
|
+
# ndr_uint32 :user_id
|
|
1364
|
+
# end
|
|
1365
|
+
|
|
1366
|
+
# class TestTypeSerialization1 < RubySMB::Dcerpc::Ndr::TypeSerialization1
|
|
1367
|
+
# default_parameter byte_align: 8
|
|
1368
|
+
# endian :little
|
|
1369
|
+
#
|
|
1370
|
+
# test_struct :data1
|
|
1371
|
+
# uint32 :value1, initial_value: 5
|
|
1372
|
+
# uint32 :value2, initial_value: 6
|
|
1373
|
+
# test_struct :data2
|
|
1374
|
+
# uint32 :value3, initial_value: 7
|
|
1375
|
+
# test_struct :data3
|
|
1376
|
+
# end
|
|
1377
|
+
#
|
|
1378
|
+
# This will result in the following structure:
|
|
1379
|
+
# {
|
|
1380
|
+
# :common_header => {:version=>1, :endianness=>16, :common_header_length=>8, :filler=>3435973836},
|
|
1381
|
+
# :private_header1 => {:object_buffer_length=>12, :filler=>0},
|
|
1382
|
+
# :data1 => {:full_name=>{:buffer_length=>0, :maximum_length=>0, :buffer=>:null}, :user_id=>0},
|
|
1383
|
+
# :value1 => 5,
|
|
1384
|
+
# :value2 => 6,
|
|
1385
|
+
# :private_header2 => {:object_buffer_length=>12, :filler=>0},
|
|
1386
|
+
# :data2 => {:full_name=>{:buffer_length=>0, :maximum_length=>0, :buffer=>:null}, :user_id=>0},
|
|
1387
|
+
# :value3 => 7,
|
|
1388
|
+
# :private_header3 => {:object_buffer_length=>12, :filler=>0},
|
|
1389
|
+
# :data3 => {:full_name=>{:buffer_length=>0, :maximum_length=>0, :buffer=>:null}, :user_id=>0}
|
|
1390
|
+
# }
|
|
1391
|
+
#
|
|
1392
|
+
class TypeSerialization1 < BinData::Record
|
|
1393
|
+
PRIVATE_HEADER_BASE_NAME = 'private_header'.freeze
|
|
1394
|
+
|
|
1395
|
+
default_parameter byte_align: 8
|
|
1396
|
+
endian :little
|
|
1397
|
+
search_prefix :type_serialization1
|
|
1398
|
+
|
|
1399
|
+
common_type_header :common_header
|
|
1400
|
+
|
|
1401
|
+
def field_length(obj)
|
|
1402
|
+
length = 0
|
|
1403
|
+
index = find_index_of(obj)
|
|
1404
|
+
if index
|
|
1405
|
+
each_pair {|n, o| length = o.num_bytes if n == field_names[index + 1]}
|
|
1406
|
+
end
|
|
1407
|
+
length
|
|
1408
|
+
end
|
|
1409
|
+
|
|
1410
|
+
def self.method_missing(symbol, *args, &block)
|
|
1411
|
+
return super if dsl_parser.respond_to?(symbol)
|
|
1412
|
+
|
|
1413
|
+
klass = BinData::RegisteredClasses.lookup(symbol, {endian: dsl_parser.endian, search_prefix: dsl_parser.search_prefix})
|
|
1414
|
+
if klass.new.is_a?(ConstructedTypePlugin)
|
|
1415
|
+
# We cannot have two fields with the same name. So, here we look for
|
|
1416
|
+
# existing TypeSerialization1PrivateHeader fields and just increment
|
|
1417
|
+
# the ending number of the last TypeSerialization1PrivateHeader field
|
|
1418
|
+
# to make the new name unique.
|
|
1419
|
+
names = dsl_parser.fields.find_all do |field|
|
|
1420
|
+
field.prototype.instance_variable_get(:@obj_class) == TypeSerialization1PrivateHeader
|
|
1421
|
+
end.map(&:name).sort
|
|
1422
|
+
if names.empty?
|
|
1423
|
+
new_name = "#{PRIVATE_HEADER_BASE_NAME}1"
|
|
1424
|
+
else
|
|
1425
|
+
num = names.last.match(/#{PRIVATE_HEADER_BASE_NAME}(\d)$/)[1].to_i
|
|
1426
|
+
new_name = "#{PRIVATE_HEADER_BASE_NAME}#{num + 1}"
|
|
1427
|
+
end
|
|
1428
|
+
|
|
1429
|
+
super(:private_header, new_name.to_sym)
|
|
1430
|
+
end
|
|
1431
|
+
|
|
1432
|
+
super
|
|
1433
|
+
end
|
|
1434
|
+
end
|
|
1435
|
+
|
|
1291
1436
|
end
|
|
1292
1437
|
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
module RubySMB
|
|
2
|
+
module Dcerpc
|
|
3
|
+
# The presentation context list and its element as defined in
|
|
4
|
+
# [Connection-oriented PDU Data Types - Declarations](https://pubs.opengroup.org/onlinepubs/9629399/chap12.htm#tagcjh_17_06_03_01)
|
|
5
|
+
class PContElemT < Ndr::NdrStruct
|
|
6
|
+
default_parameter byte_align: 4
|
|
7
|
+
endian :little
|
|
8
|
+
|
|
9
|
+
ndr_uint16 :p_cont_id, label: 'Context ID'
|
|
10
|
+
ndr_uint8 :n_transfer_syn, label: 'Number of transfer syntaxes', initial_value: 1
|
|
11
|
+
ndr_uint8 :reserved
|
|
12
|
+
p_syntax_id_t :abstract_syntax, label: 'Abstract syntax',
|
|
13
|
+
uuid: -> { endpoint::UUID },
|
|
14
|
+
ver_major: -> { endpoint::VER_MAJOR },
|
|
15
|
+
ver_minor: -> { endpoint::VER_MINOR }
|
|
16
|
+
array :transfer_syntaxes, label: 'Transfer syntax', type: :p_syntax_id_t,
|
|
17
|
+
initial_length: -> { n_transfer_syn },
|
|
18
|
+
uuid: -> { Ndr::UUID },
|
|
19
|
+
ver_major: -> { Ndr::VER_MAJOR },
|
|
20
|
+
ver_minor: -> { Ndr::VER_MINOR },
|
|
21
|
+
byte_align: 4
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
class PContListT < Ndr::NdrStruct
|
|
25
|
+
default_parameter byte_align: 4
|
|
26
|
+
endian :little
|
|
27
|
+
|
|
28
|
+
ndr_uint8 :n_context_elem, label: 'Number of context elements', initial_value: -> { 1 }
|
|
29
|
+
ndr_uint8 :reserved
|
|
30
|
+
ndr_uint16 :reserved2
|
|
31
|
+
array :p_cont_elem, label: 'Presentation context elements', type: :p_cont_elem_t,
|
|
32
|
+
initial_length: -> {n_context_elem},
|
|
33
|
+
endpoint: -> {endpoint},
|
|
34
|
+
byte_align: 4
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
module RubySMB
|
|
2
|
+
module Dcerpc
|
|
3
|
+
class PResultListT < Ndr::NdrStruct
|
|
4
|
+
default_parameter byte_align: 4
|
|
5
|
+
endian :little
|
|
6
|
+
|
|
7
|
+
ndr_uint8 :n_results, label: 'Number of results', initial_value: -> { p_results.size }
|
|
8
|
+
ndr_uint8 :reserved
|
|
9
|
+
ndr_uint16 :reserved2
|
|
10
|
+
array :p_results, label: 'Results', type: :p_result_t, initial_length: -> { n_results }, byte_align: 4
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module RubySMB
|
|
2
|
+
module Dcerpc
|
|
3
|
+
class PResultT < Ndr::NdrStruct
|
|
4
|
+
default_parameter byte_align: 4
|
|
5
|
+
endian :little
|
|
6
|
+
|
|
7
|
+
ndr_uint16 :result, label: 'Presentation context negotiation results'
|
|
8
|
+
ndr_uint16 :reason, label: 'Rejection reason'
|
|
9
|
+
p_syntax_id_t :transfer_syntax, label: 'Presentation syntax ID',
|
|
10
|
+
uuid: -> { Ndr::UUID },
|
|
11
|
+
ver_major: -> { Ndr::VER_MAJOR },
|
|
12
|
+
ver_minor: -> { Ndr::VER_MINOR }
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
module RubySMB
|
|
2
|
+
module Dcerpc
|
|
3
|
+
class PortAnyT < Ndr::NdrStruct
|
|
4
|
+
default_parameter byte_align: 2
|
|
5
|
+
endian :little
|
|
6
|
+
|
|
7
|
+
ndr_uint16 :str_length, label: 'Length', initial_value: -> { port_spec.to_binary_s.size }
|
|
8
|
+
stringz :port_spec, label: 'Port string spec', byte_align: 2, onlyif: -> { str_length > 0 }
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -103,9 +103,10 @@ module RubySMB
|
|
|
103
103
|
end
|
|
104
104
|
string :default
|
|
105
105
|
end
|
|
106
|
-
|
|
106
|
+
|
|
107
|
+
string :auth_pad,
|
|
107
108
|
onlyif: -> { has_auth_verifier? },
|
|
108
|
-
length: -> {
|
|
109
|
+
length: -> { calculate_padding_size }
|
|
109
110
|
|
|
110
111
|
# Auth Verifier
|
|
111
112
|
sec_trailer :sec_trailer, onlyif: -> { has_auth_verifier? }
|
|
@@ -113,6 +114,11 @@ module RubySMB
|
|
|
113
114
|
onlyif: -> { has_auth_verifier? },
|
|
114
115
|
read_length: -> { pdu_header.auth_length }
|
|
115
116
|
|
|
117
|
+
# Per the spec (MS_RPCE 2.2.2.11): start of the trailer should be a multiple of 16 bytes offset from the start of the stub
|
|
118
|
+
def calculate_padding_size
|
|
119
|
+
(16 - (stub.num_bytes % 16)) % 16
|
|
120
|
+
end
|
|
121
|
+
|
|
116
122
|
def initialize_instance
|
|
117
123
|
super
|
|
118
124
|
pdu_header.ptype = PTYPE
|
|
@@ -125,7 +131,6 @@ module RubySMB
|
|
|
125
131
|
def has_auth_verifier?
|
|
126
132
|
self.pdu_header.auth_length > 0
|
|
127
133
|
end
|
|
128
|
-
|
|
129
134
|
end
|
|
130
135
|
end
|
|
131
136
|
end
|
|
@@ -18,7 +18,7 @@ module RubySMB
|
|
|
18
18
|
string :stub, label: 'Stub', read_length: -> { stub_length }
|
|
19
19
|
string :auth_pad,
|
|
20
20
|
onlyif: -> { has_auth_verifier? },
|
|
21
|
-
length: -> {
|
|
21
|
+
length: -> { calculate_padding_size }
|
|
22
22
|
|
|
23
23
|
# Auth Verifier
|
|
24
24
|
sec_trailer :sec_trailer, onlyif: -> { has_auth_verifier? }
|
|
@@ -26,6 +26,11 @@ module RubySMB
|
|
|
26
26
|
onlyif: -> { has_auth_verifier? },
|
|
27
27
|
read_length: -> { pdu_header.auth_length }
|
|
28
28
|
|
|
29
|
+
# Per the spec (MS_RPCE 2.2.2.11): start of the trailer should be a multiple of 16 bytes offset from the start of the stub
|
|
30
|
+
def calculate_padding_size
|
|
31
|
+
(16 - (stub.num_bytes % 16)) % 16
|
|
32
|
+
end
|
|
33
|
+
|
|
29
34
|
def initialize_instance
|
|
30
35
|
super
|
|
31
36
|
pdu_header.ptype = PTYPE
|
data/lib/ruby_smb/dcerpc/samr.rb
CHANGED
|
@@ -259,6 +259,8 @@ module RubySMB
|
|
|
259
259
|
3 => 'des-cbc-md5',
|
|
260
260
|
17 => 'aes128-cts-hmac-sha1-96',
|
|
261
261
|
18 => 'aes256-cts-hmac-sha1-96',
|
|
262
|
+
# Windows Server 2008 and later DC includes a KeyType of -140. Not present when the domain functional level is raised to DS_BEHAVIOR_WIN2008 or greater
|
|
263
|
+
# [Appendix_A_24](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/fa61e5fc-f8fb-4d5b-9695-c724af0c3829#Appendix_A_24)
|
|
262
264
|
0xffffff74 => 'rc4_hmac'
|
|
263
265
|
}
|
|
264
266
|
|
|
@@ -320,7 +322,7 @@ module RubySMB
|
|
|
320
322
|
|
|
321
323
|
def self.encrypt_password(password, key)
|
|
322
324
|
# see: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/5fe3c4c4-e71b-440d-b2fd-8448bfaf6e04
|
|
323
|
-
password =
|
|
325
|
+
password = RubySMB::Utils.safe_encode(password, 'UTF-16LE').force_encoding('ASCII-8bit')
|
|
324
326
|
buffer = password.rjust(512, "\x00") + [ password.length ].pack('V')
|
|
325
327
|
salt = SecureRandom.random_bytes(16)
|
|
326
328
|
key = OpenSSL::Digest::MD5.new(salt + key).digest
|
|
@@ -461,7 +463,7 @@ module RubySMB
|
|
|
461
463
|
array :old_credentials, type: :kerb_key_data_new, initial_length: :old_credential_count
|
|
462
464
|
array :older_credentials, type: :kerb_key_data_new, initial_length: :older_credential_count
|
|
463
465
|
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 }
|
|
466
|
+
string :key_values, read_length: -> { credentials.map { |e| e.key_length }.sum(&:to_i) }
|
|
465
467
|
|
|
466
468
|
def get_key_values
|
|
467
469
|
credentials.map do |credential|
|