ruby_smb 2.0.13 → 3.0.3
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/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 +11 -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/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 +3 -2
- 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
|