ruby_smb 3.0.0 → 3.0.4
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/anonymous_auth.rb +29 -6
- data/examples/auth_capture.rb +28 -0
- data/examples/file_server.rb +76 -0
- data/examples/read_file.rb +51 -10
- data/examples/tree_connect.rb +49 -8
- data/lib/ruby_smb/client/authentication.rb +11 -3
- data/lib/ruby_smb/client.rb +16 -2
- data/lib/ruby_smb/create_actions.rb +21 -0
- data/lib/ruby_smb/dcerpc/encrypting_file_system/efs_rpc_encrypt_file_srv_request.rb +20 -0
- data/lib/ruby_smb/dcerpc/encrypting_file_system/efs_rpc_encrypt_file_srv_response.rb +20 -0
- data/lib/ruby_smb/dcerpc/encrypting_file_system/efs_rpc_open_file_raw_request.rb +21 -0
- data/lib/ruby_smb/dcerpc/encrypting_file_system/efs_rpc_open_file_raw_response.rb +21 -0
- data/lib/ruby_smb/dcerpc/encrypting_file_system.rb +44 -0
- data/lib/ruby_smb/dcerpc/print_system/rpc_add_printer_driver_ex_request.rb +22 -0
- data/lib/ruby_smb/dcerpc/print_system/rpc_add_printer_driver_ex_response.rb +20 -0
- data/lib/ruby_smb/dcerpc/print_system/rpc_enum_printer_drivers_request.rb +24 -0
- data/lib/ruby_smb/dcerpc/print_system/rpc_enum_printer_drivers_response.rb +23 -0
- data/lib/ruby_smb/dcerpc/print_system/rpc_get_printer_driver_directory_request.rb +24 -0
- data/lib/ruby_smb/dcerpc/print_system/rpc_get_printer_driver_directory_response.rb +22 -0
- data/lib/ruby_smb/dcerpc/print_system.rb +69 -0
- data/lib/ruby_smb/dcerpc.rb +2 -2
- data/lib/ruby_smb/field/nt_status.rb +20 -1
- data/lib/ruby_smb/fscc/file_information/file_ea_information.rb +14 -0
- data/lib/ruby_smb/fscc/file_information/file_network_open_information.rb +22 -0
- data/lib/ruby_smb/fscc/file_information/file_stream_information.rb +16 -0
- data/lib/ruby_smb/fscc/file_information.rb +29 -0
- data/lib/ruby_smb/fscc/file_system_information/file_fs_attribute_information.rb +46 -0
- data/lib/ruby_smb/fscc/file_system_information/file_fs_volume_information.rb +19 -0
- data/lib/ruby_smb/fscc/file_system_information.rb +22 -0
- data/lib/ruby_smb/fscc.rb +1 -0
- data/lib/ruby_smb/generic_packet.rb +6 -0
- data/lib/ruby_smb/gss/provider/authenticator.rb +4 -0
- data/lib/ruby_smb/gss/provider/ntlm.rb +13 -3
- data/lib/ruby_smb/server/server_client/negotiation.rb +0 -2
- data/lib/ruby_smb/server/server_client/session_setup.rb +43 -32
- data/lib/ruby_smb/server/server_client/share_io.rb +28 -0
- data/lib/ruby_smb/server/server_client/tree_connect.rb +60 -0
- data/lib/ruby_smb/server/server_client.rb +214 -24
- data/lib/ruby_smb/server/session.rb +71 -0
- data/lib/ruby_smb/server/share/provider/disk.rb +437 -0
- data/lib/ruby_smb/server/share/provider/pipe.rb +27 -0
- data/lib/ruby_smb/server/share/provider/processor.rb +76 -0
- data/lib/ruby_smb/server/share/provider.rb +38 -0
- data/lib/ruby_smb/server/share.rb +11 -0
- data/lib/ruby_smb/server.rb +35 -3
- data/lib/ruby_smb/signing.rb +37 -11
- data/lib/ruby_smb/smb1/commands.rb +4 -0
- data/lib/ruby_smb/smb1/tree.rb +87 -79
- data/lib/ruby_smb/smb1.rb +0 -1
- data/lib/ruby_smb/smb2/bit_field/smb2_header_flags.rb +2 -1
- data/lib/ruby_smb/smb2/commands.rb +4 -0
- data/lib/ruby_smb/smb2/create_context/request.rb +64 -0
- data/lib/ruby_smb/smb2/create_context/response.rb +62 -0
- data/lib/ruby_smb/smb2/create_context.rb +74 -22
- data/lib/ruby_smb/smb2/packet/create_request.rb +44 -11
- data/lib/ruby_smb/smb2/packet/create_response.rb +17 -3
- data/lib/ruby_smb/smb2/packet/query_directory_request.rb +1 -1
- data/lib/ruby_smb/smb2/packet/query_directory_response.rb +2 -2
- data/lib/ruby_smb/smb2/packet/query_info_request.rb +43 -0
- data/lib/ruby_smb/smb2/packet/query_info_response.rb +23 -0
- data/lib/ruby_smb/smb2/packet/tree_connect_response.rb +1 -1
- data/lib/ruby_smb/smb2/packet/tree_disconnect_response.rb +1 -0
- data/lib/ruby_smb/smb2/packet.rb +2 -0
- data/lib/ruby_smb/smb2/tree.rb +80 -70
- data/lib/ruby_smb/smb2.rb +11 -0
- data/lib/ruby_smb/smb_error.rb +110 -0
- data/lib/ruby_smb/version.rb +1 -1
- data/lib/ruby_smb.rb +2 -0
- data/ruby_smb.gemspec +1 -1
- data/spec/lib/ruby_smb/client_spec.rb +10 -0
- data/spec/lib/ruby_smb/dcerpc/encrypting_file_system/efs_rpc_encrypt_file_srv_request_spec.rb +30 -0
- data/spec/lib/ruby_smb/dcerpc/encrypting_file_system/efs_rpc_encrypt_file_srv_response_spec.rb +30 -0
- data/spec/lib/ruby_smb/dcerpc/encrypting_file_system/efs_rpc_open_file_raw_request_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/encrypting_file_system/efs_rpc_open_file_raw_response_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/print_system/driver_container_spec.rb +41 -0
- data/spec/lib/ruby_smb/dcerpc/print_system/driver_info2_spec.rb +64 -0
- data/spec/lib/ruby_smb/dcerpc/print_system/rpc_add_printer_driver_ex_request_spec.rb +59 -0
- data/spec/lib/ruby_smb/dcerpc/print_system/rpc_add_printer_driver_ex_response_spec.rb +30 -0
- data/spec/lib/ruby_smb/dcerpc/print_system/rpc_enum_printer_drivers_request_spec.rb +62 -0
- data/spec/lib/ruby_smb/dcerpc/print_system/rpc_enum_printer_drivers_response_spec.rb +54 -0
- data/spec/lib/ruby_smb/dcerpc/print_system/rpc_get_printer_driver_directory_request_spec.rb +62 -0
- data/spec/lib/ruby_smb/dcerpc/print_system/rpc_get_printer_driver_directory_response_spec.rb +46 -0
- data/spec/lib/ruby_smb/field/nt_status_spec.rb +6 -2
- data/spec/lib/ruby_smb/gss/provider/ntlm/authenticator_spec.rb +4 -0
- data/spec/lib/ruby_smb/server/server_client_spec.rb +36 -53
- data/spec/lib/ruby_smb/server/session_spec.rb +38 -0
- data/spec/lib/ruby_smb/server/share/provider/disk_spec.rb +61 -0
- data/spec/lib/ruby_smb/server/share/provider/pipe_spec.rb +31 -0
- data/spec/lib/ruby_smb/server/share/provider_spec.rb +13 -0
- data/spec/lib/ruby_smb/smb1/tree_spec.rb +3 -3
- data/spec/lib/ruby_smb/smb2/bit_field/header_flags_spec.rb +8 -2
- data/spec/lib/ruby_smb/smb2/{create_context_spec.rb → create_context/create_context_request_spec.rb} +1 -1
- data/spec/lib/ruby_smb/smb2/packet/create_request_spec.rb +5 -5
- data/spec/lib/ruby_smb/smb2/packet/create_response_spec.rb +9 -5
- data/spec/lib/ruby_smb/smb2/packet/query_directory_response_spec.rb +3 -2
- data/spec/lib/ruby_smb/smb2/tree_spec.rb +3 -3
- data.tar.gz.sig +0 -0
- metadata +71 -7
- metadata.gz.sig +0 -0
- data/lib/ruby_smb/smb1/create_actions.rb +0 -20
data/lib/ruby_smb/signing.rb
CHANGED
@@ -8,24 +8,35 @@ module RubySMB
|
|
8
8
|
|
9
9
|
# Take an SMB1 packet and sign it.
|
10
10
|
#
|
11
|
-
# @param
|
11
|
+
# @param [RubySMB::GenericPacket] packet The packet to sign.
|
12
12
|
# @return [RubySMB::GenericPacket] the signed packet
|
13
13
|
def smb1_sign(packet)
|
14
14
|
# Pack the Sequence counter into a int64le
|
15
|
-
packed_sequence_counter = [sequence_counter].pack('Q<')
|
15
|
+
packed_sequence_counter = [@sequence_counter].pack('Q<')
|
16
16
|
packet.smb_header.security_features = packed_sequence_counter
|
17
|
-
signature = OpenSSL::Digest::MD5.digest(session_key + packet.to_binary_s)[0, 8]
|
17
|
+
signature = OpenSSL::Digest::MD5.digest(@session_key + packet.to_binary_s)[0, 8]
|
18
18
|
packet.smb_header.security_features = signature
|
19
19
|
@sequence_counter += 1
|
20
20
|
|
21
21
|
packet
|
22
22
|
end
|
23
23
|
|
24
|
-
# Take an SMB2 packet and sign it.
|
24
|
+
# Take an SMB2 packet and sign it. This version is an instance method that
|
25
|
+
# accesses the necessary values from the object instance.
|
25
26
|
#
|
26
|
-
# @param
|
27
|
+
# @param [RubySMB::GenericPacket] packet The packet to sign.
|
27
28
|
# @return [RubySMB::GenericPacket] the signed packet
|
28
29
|
def smb2_sign(packet)
|
30
|
+
Signing::smb2_sign(packet, @session_key)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Take an SMB2 packet and sign it. This version is a module function that
|
34
|
+
# requires the necessary values to be explicitly passed to it.
|
35
|
+
#
|
36
|
+
# @param [RubySMB::GenericPacket] packet The packet to sign.
|
37
|
+
# @param [String] session_key The key to use for signing.
|
38
|
+
# @return [RubySMB::GenericPacket] the signed packet
|
39
|
+
def self.smb2_sign(packet, session_key)
|
29
40
|
packet.smb2_header.flags.signed = 1
|
30
41
|
packet.smb2_header.signature = "\x00" * 16
|
31
42
|
hmac = OpenSSL::HMAC.digest(OpenSSL::Digest.new('SHA256'), session_key, packet.to_binary_s)
|
@@ -34,18 +45,33 @@ module RubySMB
|
|
34
45
|
packet
|
35
46
|
end
|
36
47
|
|
37
|
-
# Take an SMB3 packet and sign it.
|
48
|
+
# Take an SMB3 packet and sign it. This version is an instance method that
|
49
|
+
# accesses the necessary values from the object instance.
|
38
50
|
#
|
39
|
-
# @param
|
51
|
+
# @param [RubySMB::GenericPacket] packet The packet to sign.
|
40
52
|
# @return [RubySMB::GenericPacket] the signed packet
|
41
53
|
def smb3_sign(packet)
|
42
|
-
|
54
|
+
Signing::smb3_sign(packet, @session_key, @dialect, @preauth_integrity_hash_value)
|
55
|
+
end
|
56
|
+
|
57
|
+
# Take an SMB3 packet and sign it. This version is a module function that
|
58
|
+
# requires the necessary values to be explicitly passed to it.
|
59
|
+
#
|
60
|
+
# @param [RubySMB::GenericPacket] packet The packet to sign.
|
61
|
+
# @param [String] session_key The key to use for signing.
|
62
|
+
# @param [String] dialect The SMB3 dialect to sign for.
|
63
|
+
# @param [String] preauth_integrity_hash The preauth integrity hash as
|
64
|
+
# required by the 3.1.1 dialect.
|
65
|
+
# @return [RubySMB::GenericPacket] the signed packet
|
66
|
+
def self.smb3_sign(packet, session_key, dialect, preauth_integrity_hash=nil)
|
67
|
+
case dialect
|
43
68
|
when '0x0300', '0x0302'
|
44
|
-
signing_key = Crypto::KDF.counter_mode(
|
69
|
+
signing_key = Crypto::KDF.counter_mode(session_key, "SMB2AESCMAC\x00", "SmbSign\x00")
|
45
70
|
when '0x0311'
|
46
|
-
|
71
|
+
raise ArgumentError.new('the preauth integrity hash is required for the specified dialect') if preauth_integrity_hash.nil?
|
72
|
+
signing_key = Crypto::KDF.counter_mode(session_key, "SMBSigningKey\x00", preauth_integrity_hash)
|
47
73
|
else
|
48
|
-
raise Error::SigningError.new("Dialect #{
|
74
|
+
raise Error::SigningError.new("Dialect #{dialect.inspect} is incompatible with SMBv3 signing")
|
49
75
|
end
|
50
76
|
|
51
77
|
packet.smb2_header.flags.signed = 1
|
data/lib/ruby_smb/smb1/tree.rb
CHANGED
@@ -59,8 +59,8 @@ module RubySMB
|
|
59
59
|
# Make sure we don't modify the caller's hash options
|
60
60
|
opts = opts.dup
|
61
61
|
opts[:filename] = opts[:filename].dup
|
62
|
-
opts[:filename].prepend('\\') unless opts[:filename].start_with?('\\')
|
63
|
-
|
62
|
+
opts[:filename].prepend('\\') unless opts[:filename].start_with?('\\'.encode(opts[:filename].encoding))
|
63
|
+
_open(**opts)
|
64
64
|
end
|
65
65
|
|
66
66
|
# Open a file on the remote share.
|
@@ -80,83 +80,12 @@ module RubySMB
|
|
80
80
|
# @return [RubySMB::SMB1::File] handle to the created file
|
81
81
|
# @raise [RubySMB::Error::InvalidPacket] if the response command is not SMB_COM_NT_CREATE_ANDX
|
82
82
|
# @raise [RubySMB::Error::UnexpectedStatusCode] if the response NTStatus is not STATUS_SUCCESS
|
83
|
-
def open_file(
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
if flags
|
91
|
-
nt_create_andx_request.parameter_block.flags = flags
|
92
|
-
else
|
93
|
-
nt_create_andx_request.parameter_block.flags.request_extended_response = 1
|
94
|
-
end
|
95
|
-
|
96
|
-
if options
|
97
|
-
nt_create_andx_request.parameter_block.create_options = options
|
98
|
-
else
|
99
|
-
nt_create_andx_request.parameter_block.create_options.directory_file = 0
|
100
|
-
nt_create_andx_request.parameter_block.create_options.non_directory_file = 1
|
101
|
-
end
|
102
|
-
|
103
|
-
if read
|
104
|
-
nt_create_andx_request.parameter_block.share_access.share_read = 1
|
105
|
-
nt_create_andx_request.parameter_block.desired_access.read_data = 1
|
106
|
-
nt_create_andx_request.parameter_block.desired_access.read_ea = 1
|
107
|
-
nt_create_andx_request.parameter_block.desired_access.read_attr = 1
|
108
|
-
nt_create_andx_request.parameter_block.desired_access.read_control = 1
|
109
|
-
end
|
110
|
-
|
111
|
-
if write
|
112
|
-
nt_create_andx_request.parameter_block.share_access.share_write = 1
|
113
|
-
nt_create_andx_request.parameter_block.desired_access.write_data = 1
|
114
|
-
nt_create_andx_request.parameter_block.desired_access.append_data = 1
|
115
|
-
nt_create_andx_request.parameter_block.desired_access.write_ea = 1
|
116
|
-
nt_create_andx_request.parameter_block.desired_access.write_attr = 1
|
117
|
-
end
|
118
|
-
|
119
|
-
if delete
|
120
|
-
nt_create_andx_request.parameter_block.share_access.share_delete = 1
|
121
|
-
nt_create_andx_request.parameter_block.desired_access.delete_access = 1
|
122
|
-
end
|
123
|
-
|
124
|
-
nt_create_andx_request.parameter_block.impersonation_level = impersonation
|
125
|
-
nt_create_andx_request.parameter_block.create_disposition = disposition
|
126
|
-
|
127
|
-
unicode_enabled = nt_create_andx_request.smb_header.flags2.unicode == 1
|
128
|
-
nt_create_andx_request.data_block.file_name = add_null_termination(str: filename, unicode: unicode_enabled)
|
129
|
-
|
130
|
-
raw_response = @client.send_recv(nt_create_andx_request)
|
131
|
-
response = RubySMB::SMB1::Packet::NtCreateAndxResponse.read(raw_response)
|
132
|
-
unless response.valid?
|
133
|
-
if response.is_a?(RubySMB::SMB1::Packet::EmptyPacket) &&
|
134
|
-
response.smb_header.protocol == RubySMB::SMB1::SMB_PROTOCOL_ID &&
|
135
|
-
response.smb_header.command == response.original_command
|
136
|
-
raise RubySMB::Error::InvalidPacket.new(
|
137
|
-
'The response seems to be an SMB1 NtCreateAndxResponse but an '\
|
138
|
-
'error occurs while parsing it. It is probably missing the '\
|
139
|
-
'required extended information.'
|
140
|
-
)
|
141
|
-
end
|
142
|
-
raise RubySMB::Error::InvalidPacket.new(
|
143
|
-
expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
|
144
|
-
expected_cmd: RubySMB::SMB1::Packet::NtCreateAndxResponse::COMMAND,
|
145
|
-
packet: response
|
146
|
-
)
|
147
|
-
end
|
148
|
-
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
149
|
-
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
150
|
-
end
|
151
|
-
|
152
|
-
case response.parameter_block.resource_type
|
153
|
-
when RubySMB::SMB1::ResourceType::BYTE_MODE_PIPE, RubySMB::SMB1::ResourceType::MESSAGE_MODE_PIPE
|
154
|
-
RubySMB::SMB1::Pipe.new(name: filename, tree: self, response: response)
|
155
|
-
when RubySMB::SMB1::ResourceType::DISK
|
156
|
-
RubySMB::SMB1::File.new(name: filename, tree: self, response: response)
|
157
|
-
else
|
158
|
-
raise RubySMB::Error::RubySMBError
|
159
|
-
end
|
83
|
+
def open_file(opts)
|
84
|
+
# Make sure we don't modify the caller's hash options
|
85
|
+
opts = opts.dup
|
86
|
+
opts[:filename] = opts[:filename].dup
|
87
|
+
opts[:filename] = opts[:filename][1..-1] if opts[:filename].start_with?('\\'.encode(opts[:filename].encoding))
|
88
|
+
_open(**opts)
|
160
89
|
end
|
161
90
|
|
162
91
|
# List `directory` on the remote share.
|
@@ -264,6 +193,85 @@ module RubySMB
|
|
264
193
|
|
265
194
|
private
|
266
195
|
|
196
|
+
def _open(filename:, flags: nil, options: nil, disposition: RubySMB::Dispositions::FILE_OPEN,
|
197
|
+
impersonation: RubySMB::ImpersonationLevels::SEC_IMPERSONATE, read: true, write: false, delete: false)
|
198
|
+
nt_create_andx_request = RubySMB::SMB1::Packet::NtCreateAndxRequest.new
|
199
|
+
nt_create_andx_request = set_header_fields(nt_create_andx_request)
|
200
|
+
|
201
|
+
nt_create_andx_request.parameter_block.ext_file_attributes.normal = 1
|
202
|
+
|
203
|
+
if flags
|
204
|
+
nt_create_andx_request.parameter_block.flags = flags
|
205
|
+
else
|
206
|
+
nt_create_andx_request.parameter_block.flags.request_extended_response = 1
|
207
|
+
end
|
208
|
+
|
209
|
+
if options
|
210
|
+
nt_create_andx_request.parameter_block.create_options = options
|
211
|
+
else
|
212
|
+
nt_create_andx_request.parameter_block.create_options.directory_file = 0
|
213
|
+
nt_create_andx_request.parameter_block.create_options.non_directory_file = 1
|
214
|
+
end
|
215
|
+
|
216
|
+
if read
|
217
|
+
nt_create_andx_request.parameter_block.share_access.share_read = 1
|
218
|
+
nt_create_andx_request.parameter_block.desired_access.read_data = 1
|
219
|
+
nt_create_andx_request.parameter_block.desired_access.read_ea = 1
|
220
|
+
nt_create_andx_request.parameter_block.desired_access.read_attr = 1
|
221
|
+
nt_create_andx_request.parameter_block.desired_access.read_control = 1
|
222
|
+
end
|
223
|
+
|
224
|
+
if write
|
225
|
+
nt_create_andx_request.parameter_block.share_access.share_write = 1
|
226
|
+
nt_create_andx_request.parameter_block.desired_access.write_data = 1
|
227
|
+
nt_create_andx_request.parameter_block.desired_access.append_data = 1
|
228
|
+
nt_create_andx_request.parameter_block.desired_access.write_ea = 1
|
229
|
+
nt_create_andx_request.parameter_block.desired_access.write_attr = 1
|
230
|
+
end
|
231
|
+
|
232
|
+
if delete
|
233
|
+
nt_create_andx_request.parameter_block.share_access.share_delete = 1
|
234
|
+
nt_create_andx_request.parameter_block.desired_access.delete_access = 1
|
235
|
+
end
|
236
|
+
|
237
|
+
nt_create_andx_request.parameter_block.impersonation_level = impersonation
|
238
|
+
nt_create_andx_request.parameter_block.create_disposition = disposition
|
239
|
+
|
240
|
+
unicode_enabled = nt_create_andx_request.smb_header.flags2.unicode == 1
|
241
|
+
nt_create_andx_request.data_block.file_name = add_null_termination(str: filename, unicode: unicode_enabled)
|
242
|
+
|
243
|
+
raw_response = @client.send_recv(nt_create_andx_request)
|
244
|
+
response = RubySMB::SMB1::Packet::NtCreateAndxResponse.read(raw_response)
|
245
|
+
unless response.valid?
|
246
|
+
if response.is_a?(RubySMB::SMB1::Packet::EmptyPacket) &&
|
247
|
+
response.smb_header.protocol == RubySMB::SMB1::SMB_PROTOCOL_ID &&
|
248
|
+
response.smb_header.command == response.original_command
|
249
|
+
raise RubySMB::Error::InvalidPacket.new(
|
250
|
+
'The response seems to be an SMB1 NtCreateAndxResponse but an '\
|
251
|
+
'error occurs while parsing it. It is probably missing the '\
|
252
|
+
'required extended information.'
|
253
|
+
)
|
254
|
+
end
|
255
|
+
raise RubySMB::Error::InvalidPacket.new(
|
256
|
+
expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
|
257
|
+
expected_cmd: RubySMB::SMB1::Packet::NtCreateAndxResponse::COMMAND,
|
258
|
+
packet: response
|
259
|
+
)
|
260
|
+
end
|
261
|
+
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
262
|
+
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
263
|
+
end
|
264
|
+
|
265
|
+
case response.parameter_block.resource_type
|
266
|
+
when RubySMB::SMB1::ResourceType::BYTE_MODE_PIPE, RubySMB::SMB1::ResourceType::MESSAGE_MODE_PIPE
|
267
|
+
RubySMB::SMB1::Pipe.new(name: filename, tree: self, response: response)
|
268
|
+
when RubySMB::SMB1::ResourceType::DISK
|
269
|
+
RubySMB::SMB1::File.new(name: filename, tree: self, response: response)
|
270
|
+
else
|
271
|
+
raise RubySMB::Error::RubySMBError
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
267
275
|
# Sets ParameterBlock options for FIND_FIRST2 and
|
268
276
|
# FIND_NEXT2 requests. In particular we need to do this
|
269
277
|
# to tell the server to ignore the Trans2DataBlock as we are
|
data/lib/ruby_smb/smb1.rb
CHANGED
@@ -5,7 +5,8 @@ module RubySMB
|
|
5
5
|
# [2.2.1.2 SMB2 Packet Header - SYNC](https://msdn.microsoft.com/en-us/library/cc246529.aspx)
|
6
6
|
class Smb2HeaderFlags < BinData::Record
|
7
7
|
endian :little
|
8
|
-
|
8
|
+
bit1 :reserved3, label: 'Reserved', initial_value: 0
|
9
|
+
bit3 :priority, label: 'Priority'
|
9
10
|
bit1 :signed, label: 'Packet Signed'
|
10
11
|
bit1 :related_operations, label: 'Chained Request'
|
11
12
|
bit1 :async_command, label: 'ASYNC Command', initial_value: 0
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'ruby_smb/dcerpc/uuid'
|
2
|
+
|
3
|
+
module RubySMB
|
4
|
+
module SMB2
|
5
|
+
module CreateContext
|
6
|
+
# [2.2.13.2.3 SMB2_CREATE_DURABLE_HANDLE_REQUEST](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/9999d870-b664-4e51-a187-1c3c16a1ae1c)
|
7
|
+
class CreateDurableHandleRequest < BinData::Record
|
8
|
+
NAME = CREATE_DURABLE_HANDLE
|
9
|
+
|
10
|
+
endian :little
|
11
|
+
string :reserved, label: 'Reserved', length: 16
|
12
|
+
end
|
13
|
+
|
14
|
+
# [2.2.13.2.11 SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/5e361a29-81a7-4774-861d-f290ea53a00e)
|
15
|
+
class CreateDurableHandleV2Request < BinData::Record
|
16
|
+
NAME = CREATE_DURABLE_HANDLE_V2
|
17
|
+
|
18
|
+
endian :little
|
19
|
+
uint32 :timeout, label: 'Timeout'
|
20
|
+
struct :flags, label: 'Flags' do
|
21
|
+
bit6 :reserved
|
22
|
+
bit1 :persistent, label: 'Persistent Handle'
|
23
|
+
bit1 :reserved1
|
24
|
+
skip length: 3
|
25
|
+
end
|
26
|
+
string :reserved, length: 8
|
27
|
+
uuid :create_guid, label: 'Create GUID'
|
28
|
+
end
|
29
|
+
|
30
|
+
# [2.2.13.2.5 SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQUEST](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/5ea40835-5d40-4e85-977d-13cd745d3af8)
|
31
|
+
class CreateQueryMaximalAccessRequest < BinData::Record
|
32
|
+
NAME = CREATE_QUERY_MAXIMAL_ACCESS
|
33
|
+
|
34
|
+
default_parameter length: 0
|
35
|
+
|
36
|
+
endian :little
|
37
|
+
file_time :timestamp, label: 'Timestamp', onlyif: -> { length != 0 }
|
38
|
+
end
|
39
|
+
|
40
|
+
# [2.2.13.2.9 SMB2_CREATE_QUERY_ON_DISK_ID](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/6eb9162a-3278-4513-988a-6b52bed30fc3)
|
41
|
+
class CreateQueryOnDiskIdRequest < BinData::Record
|
42
|
+
NAME = CREATE_QUERY_ON_DISK_ID
|
43
|
+
|
44
|
+
endian :little
|
45
|
+
end
|
46
|
+
|
47
|
+
class CreateContextRequest < CreateContext
|
48
|
+
delayed_io :data, read_abs_offset: -> { abs_offset + data_offset } do
|
49
|
+
choice :data, selection: -> { name.snapshot } do
|
50
|
+
create_durable_handle_request CREATE_DURABLE_HANDLE, length: :data_length
|
51
|
+
create_durable_handle_v2_request CREATE_DURABLE_HANDLE_V2, length: :data_length
|
52
|
+
create_query_maximal_access_request CREATE_QUERY_MAXIMAL_ACCESS, length: :data_length
|
53
|
+
create_query_on_disk_id_request CREATE_QUERY_ON_DISK_ID, length: :data_length
|
54
|
+
string :default, read_length: :data_length
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
class CreateContextArrayRequest < CreateContextArray
|
60
|
+
default_parameters type: :create_context_request
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module RubySMB
|
2
|
+
module SMB2
|
3
|
+
module CreateContext
|
4
|
+
# [2.2.14.2.3 SMB2_CREATE_DURABLE_HANDLE_RESPONSE](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/a3a11598-f228-47da-82bb-9418b9397041)
|
5
|
+
class CreateDurableHandleResponse < BinData::Record
|
6
|
+
NAME = CREATE_DURABLE_HANDLE
|
7
|
+
|
8
|
+
endian :little
|
9
|
+
string :reserved, label: 'Reserved', length: 8
|
10
|
+
end
|
11
|
+
|
12
|
+
# [2.2.14.2.12 SMB2_CREATE_DURABLE_HANDLE_RESPONSE_V2](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/48c1049f-25a4-4f23-9a57-11ddd72ce985)
|
13
|
+
class CreateDurableHandleV2Response < BinData::Record
|
14
|
+
NAME = CREATE_DURABLE_HANDLE_V2
|
15
|
+
|
16
|
+
endian :little
|
17
|
+
uint32 :timeout, label: 'Timeout'
|
18
|
+
struct :flags, label: 'Flags' do
|
19
|
+
bit6 :reserved
|
20
|
+
bit1 :persistent, label: 'Persistent Handle'
|
21
|
+
bit1 :reserved1
|
22
|
+
skip length: 3
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# [2.2.14.2.5 SMB2_CREATE_QUERY_MAXIMAL_ACCESS_RESPONSE](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/0fe6be15-3a76-4032-9a44-56f846ac6244)
|
27
|
+
class CreateQueryMaximalAccessResponse < BinData::Record
|
28
|
+
NAME = CREATE_QUERY_MAXIMAL_ACCESS
|
29
|
+
|
30
|
+
endian :little
|
31
|
+
nt_status :query_status, label: 'Query Status'
|
32
|
+
file_access_mask :maximal_access, label: 'Maximal Access'
|
33
|
+
end
|
34
|
+
|
35
|
+
# [2.2.14.2.9 SMB2_CREATE_QUERY_ON_DISK_ID](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/5c977939-1d8f-4774-9111-21e9195f3aca)
|
36
|
+
class CreateQueryOnDiskIdResponse < BinData::Record
|
37
|
+
NAME = CREATE_QUERY_ON_DISK_ID
|
38
|
+
|
39
|
+
endian :little
|
40
|
+
uint64 :disk_file_id, label: 'Disk File Id', initial_value: 0xffffffffffffffff
|
41
|
+
uint64 :volume_id, label: 'Volume Id'
|
42
|
+
string :reserved, label: 'Reserved', length: 16
|
43
|
+
end
|
44
|
+
|
45
|
+
class CreateContextResponse < CreateContext
|
46
|
+
delayed_io :data, read_abs_offset: -> { abs_offset + data_offset } do
|
47
|
+
choice :data, selection: -> { name.snapshot } do
|
48
|
+
create_durable_handle_response CREATE_DURABLE_HANDLE, length: :data_length
|
49
|
+
create_durable_handle_v2_response CREATE_DURABLE_HANDLE_V2, length: :data_length
|
50
|
+
create_query_maximal_access_response CREATE_QUERY_MAXIMAL_ACCESS, length: :data_length
|
51
|
+
create_query_on_disk_id_response CREATE_QUERY_ON_DISK_ID, length: :data_length
|
52
|
+
string :default, read_length: :data_length
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
class CreateContextArrayResponse < CreateContextArray
|
58
|
+
default_parameters type: :create_context_response
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -1,29 +1,81 @@
|
|
1
1
|
module RubySMB
|
2
2
|
module SMB2
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
3
|
+
module CreateContext
|
4
|
+
# Create name constants. Requests and responses have a shared name but some have different structures. Names are
|
5
|
+
# normalized to remove the request/response portion.
|
6
|
+
# [2.2.13.2 SMB2_CREATE_CONTEXT Request Values](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/75364667-3a93-4e2c-b771-592d8d5e876d)
|
7
|
+
CREATE_EA_BUFFER = 'ExtA'.freeze
|
8
|
+
CREATE_SD_BUFFER = 'SecD'.freeze
|
9
|
+
CREATE_DURABLE_HANDLE = 'DHnQ'.freeze
|
10
|
+
CREATE_DURABLE_HANDLE_RECONNECT = 'DHnC'.freeze
|
11
|
+
CREATE_ALLOCATION_SIZE = 'AISi'.freeze
|
12
|
+
CREATE_QUERY_MAXIMAL_ACCESS = 'MxAc'.freeze
|
13
|
+
CREATE_TIMEWARP_TOKEN = 'TWrp'.freeze
|
14
|
+
CREATE_QUERY_ON_DISK_ID = 'QFid'.freeze
|
15
|
+
CREATE_LEASE = 'RqLs'.freeze
|
16
|
+
CREATE_LEASE_V2 = 'RqLs'.freeze
|
17
|
+
CREATE_DURABLE_HANDLE_V2 = 'DH2Q'.freeze
|
18
|
+
CREATE_DURABLE_HANDLE_RECONNECT_v2 = 'DH2C'.freeze
|
19
|
+
CREATE_APP_INSTANCE_ID = "\x45\xBC\xA6\x6A\xEF\xA7\xF7\x4A\x90\x08\xFA\x46\x2E\x14\x4D\x74".b.freeze
|
20
|
+
CREATE_APP_INSTANCE_VERSION = "\xB9\x82\xD0\xB7\x3B\x56\x07\x4F\xA0\x7B\x52\x4A\x81\x16\xA0\x10".b.freeze
|
21
|
+
SVHDX_OPEN_DEVICE_CONTEXT = "\x9C\xCB\xCF\x9E\x04\xC1\xE6\x43\x98\x0E\x15\x8D\xA1\xF6\xEC\x83".b.freeze
|
22
|
+
|
23
|
+
# An SMB2_CREATE_CONTEXT struct as defined in
|
24
|
+
# [2.2.13.2 SMB2_CREATE_CONTEXT Request Values](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/75364667-3a93-4e2c-b771-592d8d5e876d?redirectedfrom=MSDN)
|
25
|
+
class CreateContext < BinData::Record
|
26
|
+
unregister_self
|
27
|
+
|
28
|
+
endian :little
|
29
|
+
uint32 :next_offset, label: 'Offset to next Context'
|
30
|
+
uint16 :name_offset, label: 'Offset to Name/Tag', initial_value: -> { buffer.rel_offset }
|
31
|
+
uint16 :name_length, label: 'Length of Name/Tag', initial_value: -> { name.num_bytes }
|
32
|
+
uint16 :reserved, label: 'Reserved Space'
|
33
|
+
uint16 :data_offset, label: 'Offset to data', initial_value: -> { calc_data_offset }
|
34
|
+
uint32 :data_length, label: 'Length of data', initial_value: -> { data.num_bytes }
|
35
|
+
string :buffer, label: 'Buffer', initial_value: -> { build_buffer }, read_length: -> { calc_buffer_size }
|
36
|
+
|
37
|
+
delayed_io :name, read_abs_offset: -> { abs_offset + name_offset } do
|
38
|
+
string :name, label: 'Name', read_length: :name_length
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def build_buffer
|
44
|
+
align = 8
|
45
|
+
buf = name.dup.tap { |obj| obj.abs_offset = 0 }.to_binary_s { |obj| obj.write_now! }
|
46
|
+
buf << "\x00".b * ((align - buf.length % align) % align)
|
47
|
+
buf << data.dup.tap { |obj| obj.abs_offset = 0 }.to_binary_s { |obj| obj.write_now! }
|
48
|
+
buf << "\x00".b * ((align - buf.length % align) % align)
|
49
|
+
end
|
50
|
+
|
51
|
+
def calc_buffer_size
|
52
|
+
align = 8
|
53
|
+
size = 0
|
54
|
+
size += name_length + ((align - name_length % align) % align)
|
55
|
+
size += data_length + ((align - data_length % align) % align)
|
56
|
+
size
|
57
|
+
end
|
58
|
+
|
59
|
+
def calc_data_offset
|
60
|
+
if data.num_bytes == 0
|
61
|
+
0
|
62
|
+
else
|
63
|
+
align = 8
|
64
|
+
buffer.rel_offset + name_length + ((align - name_length % align) % align)
|
65
|
+
end
|
25
66
|
end
|
26
67
|
end
|
68
|
+
|
69
|
+
class CreateContextArray < BinData::Array
|
70
|
+
unregister_self
|
71
|
+
|
72
|
+
default_parameters read_until: -> { element&.next_offset == 0 }
|
73
|
+
endian :little
|
74
|
+
end
|
27
75
|
end
|
28
76
|
end
|
29
77
|
end
|
78
|
+
|
79
|
+
require 'ruby_smb/smb2/bit_field'
|
80
|
+
require 'ruby_smb/smb2/create_context/request'
|
81
|
+
require 'ruby_smb/smb2/create_context/response'
|
@@ -4,9 +4,8 @@ module RubySMB
|
|
4
4
|
# An SMB2 Create Request Packet as defined in
|
5
5
|
# [2.2.13 SMB2 CREATE Request](https://msdn.microsoft.com/en-us/library/cc246502.aspx)
|
6
6
|
class CreateRequest < RubySMB::GenericPacket
|
7
|
-
COMMAND = RubySMB::SMB2::Commands::CREATE
|
8
|
-
|
9
7
|
require 'ruby_smb/smb1/bit_field/create_options'
|
8
|
+
COMMAND = RubySMB::SMB2::Commands::CREATE
|
10
9
|
|
11
10
|
endian :little
|
12
11
|
smb2_header :smb2_header
|
@@ -35,17 +34,51 @@ module RubySMB
|
|
35
34
|
bit8 :reserved4, label: 'Reserved Space'
|
36
35
|
end
|
37
36
|
|
38
|
-
uint32
|
39
|
-
create_options
|
40
|
-
uint16
|
41
|
-
uint16
|
42
|
-
uint32
|
43
|
-
uint32
|
44
|
-
|
45
|
-
|
37
|
+
uint32 :create_disposition, label: 'Create Disposition'
|
38
|
+
create_options :create_options
|
39
|
+
uint16 :name_offset, label: 'Name Offset', initial_value: -> { calc_name_offset }
|
40
|
+
uint16 :name_length, label: 'Name Length', initial_value: -> { name.num_bytes }
|
41
|
+
uint32 :contexts_offset, label: 'Create Contexts Offset', initial_value: -> { calc_contexts_offset }
|
42
|
+
uint32 :contexts_length, label: 'Create Contexts Length'
|
43
|
+
count_bytes_remaining :bytes_remaining
|
44
|
+
string :buffer, label: 'Buffer', initial_value: -> { build_buffer }, read_length: :bytes_remaining
|
45
|
+
|
46
|
+
delayed_io :name, label: 'File Name', read_abs_offset: :name_offset do
|
47
|
+
string16 read_length: :name_length
|
48
|
+
end
|
49
|
+
|
50
|
+
delayed_io :contexts, label: 'Context Array', read_abs_offset: :contexts_offset, onlyif: -> { contexts_offset != 0 } do
|
51
|
+
buffer length: :contexts_length do
|
52
|
+
create_context_array_request :contexts
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def build_buffer
|
59
|
+
align = 8
|
60
|
+
buf = name.dup.tap { |obj| obj.abs_offset = 0 }.to_binary_s { |obj| obj.write_now! }
|
61
|
+
buf << "\x00".b * ((align - buf.length % align) % align)
|
62
|
+
buf << contexts.map(&:to_binary_s).join
|
63
|
+
buf << "\x00".b * ((align - buf.length % align) % align)
|
64
|
+
end
|
46
65
|
|
47
|
-
|
66
|
+
def calc_contexts_offset
|
67
|
+
if contexts.num_bytes == 0
|
68
|
+
0
|
69
|
+
else
|
70
|
+
align = 8
|
71
|
+
buffer.rel_offset + name_length + ((align - name_length % align) % align)
|
72
|
+
end
|
73
|
+
end
|
48
74
|
|
75
|
+
def calc_name_offset
|
76
|
+
if name.num_bytes == 0
|
77
|
+
0
|
78
|
+
else
|
79
|
+
buffer.rel_offset
|
80
|
+
end
|
81
|
+
end
|
49
82
|
end
|
50
83
|
end
|
51
84
|
end
|
@@ -21,15 +21,29 @@ module RubySMB
|
|
21
21
|
file_attributes :file_attributes, label: 'File Attributes'
|
22
22
|
uint32 :reserved, label: 'Reserved Space'
|
23
23
|
smb2_fileid :file_id, label: 'File ID'
|
24
|
-
uint32 :
|
25
|
-
uint32 :
|
24
|
+
uint32 :contexts_offset, label: 'Create Contexts Offset'
|
25
|
+
uint32 :contexts_length, label: 'Create Contexts Length'
|
26
|
+
count_bytes_remaining :bytes_remaining
|
27
|
+
string :buffer, label: 'Buffer', initial_value: -> { build_buffer }, read_length: :bytes_remaining
|
26
28
|
|
27
|
-
|
29
|
+
delayed_io :contexts, label: 'Context Array', read_abs_offset: -> { contexts_offset }, onlyif: -> { contexts_offset != 0 } do
|
30
|
+
buffer length: :contexts_length do
|
31
|
+
create_context_array_response :contexts
|
32
|
+
end
|
33
|
+
end
|
28
34
|
|
29
35
|
def initialize_instance
|
30
36
|
super
|
31
37
|
smb2_header.flags.reply = 1
|
32
38
|
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def build_buffer
|
43
|
+
align = 8
|
44
|
+
buf = contexts.map(&:to_binary_s).join
|
45
|
+
buf << "\x00".b * ((align - buf.length % align) % align)
|
46
|
+
end
|
33
47
|
end
|
34
48
|
end
|
35
49
|
end
|
@@ -25,7 +25,7 @@ module RubySMB
|
|
25
25
|
uint16 :name_offset, label: 'File Name Offset', initial_value: -> { name.abs_offset }
|
26
26
|
uint16 :name_length, label: 'File Name Length', initial_value: -> { name.do_num_bytes }
|
27
27
|
uint32 :output_length, label: 'Output Buffer Length'
|
28
|
-
string16 :name, label: 'Name/Search Pattern'
|
28
|
+
string16 :name, label: 'Name/Search Pattern', read_length: :name_length
|
29
29
|
|
30
30
|
end
|
31
31
|
end
|