ruby_smb 1.0.5 → 1.1.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.tar.gz.sig +0 -0
- data/.travis.yml +4 -1
- data/README.md +35 -47
- data/examples/enum_registry_key.rb +28 -0
- data/examples/enum_registry_values.rb +30 -0
- data/examples/pipes.rb +2 -1
- data/examples/read_registry_key_value.rb +32 -0
- data/lib/ruby_smb.rb +0 -1
- data/lib/ruby_smb/client.rb +2 -0
- data/lib/ruby_smb/client/winreg.rb +46 -0
- data/lib/ruby_smb/dcerpc.rb +38 -0
- data/lib/ruby_smb/dcerpc/bind.rb +2 -2
- data/lib/ruby_smb/dcerpc/bind_ack.rb +2 -2
- data/lib/ruby_smb/dcerpc/error.rb +3 -0
- data/lib/ruby_smb/dcerpc/ndr.rb +95 -16
- data/lib/ruby_smb/dcerpc/pdu_header.rb +1 -1
- data/lib/ruby_smb/dcerpc/request.rb +28 -9
- data/lib/ruby_smb/dcerpc/rrp_unicode_string.rb +35 -0
- data/lib/ruby_smb/dcerpc/srvsvc.rb +10 -0
- data/lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all.rb +9 -0
- data/lib/ruby_smb/dcerpc/winreg.rb +340 -0
- data/lib/ruby_smb/dcerpc/winreg/close_key_request.rb +24 -0
- data/lib/ruby_smb/dcerpc/winreg/close_key_response.rb +27 -0
- data/lib/ruby_smb/dcerpc/winreg/enum_key_request.rb +45 -0
- data/lib/ruby_smb/dcerpc/winreg/enum_key_response.rb +42 -0
- data/lib/ruby_smb/dcerpc/winreg/enum_value_request.rb +39 -0
- data/lib/ruby_smb/dcerpc/winreg/enum_value_response.rb +36 -0
- data/lib/ruby_smb/dcerpc/winreg/open_key_request.rb +34 -0
- data/lib/ruby_smb/dcerpc/winreg/open_key_response.rb +25 -0
- data/lib/ruby_smb/dcerpc/winreg/open_root_key_request.rb +43 -0
- data/lib/ruby_smb/dcerpc/winreg/open_root_key_response.rb +35 -0
- data/lib/ruby_smb/dcerpc/winreg/query_info_key_request.rb +27 -0
- data/lib/ruby_smb/dcerpc/winreg/query_info_key_response.rb +40 -0
- data/lib/ruby_smb/dcerpc/winreg/query_value_request.rb +39 -0
- data/lib/ruby_smb/dcerpc/winreg/query_value_response.rb +57 -0
- data/lib/ruby_smb/dcerpc/winreg/regsam.rb +40 -0
- data/lib/ruby_smb/smb1/file.rb +2 -0
- data/lib/ruby_smb/smb1/pipe.rb +78 -2
- data/lib/ruby_smb/smb2/packet/error_packet.rb +2 -4
- data/lib/ruby_smb/smb2/pipe.rb +89 -2
- data/lib/ruby_smb/version.rb +1 -1
- data/ruby_smb.gemspec +3 -3
- data/spec/lib/ruby_smb/client_spec.rb +148 -0
- data/spec/lib/ruby_smb/dcerpc/bind_ack_spec.rb +2 -2
- data/spec/lib/ruby_smb/dcerpc/bind_spec.rb +2 -2
- data/spec/lib/ruby_smb/dcerpc/ndr_spec.rb +410 -0
- data/spec/lib/ruby_smb/dcerpc/request_spec.rb +50 -7
- data/spec/lib/ruby_smb/dcerpc/rrp_unicode_string_spec.rb +98 -0
- data/spec/lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all_spec.rb +13 -0
- data/spec/lib/ruby_smb/dcerpc/srvsvc_spec.rb +60 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/close_key_request_spec.rb +28 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/close_key_response_spec.rb +36 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_request_spec.rb +108 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_response_spec.rb +97 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_request_spec.rb +94 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_response_spec.rb +82 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/open_key_request_spec.rb +74 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/open_key_response_spec.rb +35 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_request_spec.rb +90 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_response_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/query_info_key_request_spec.rb +39 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/query_info_key_response_spec.rb +113 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/query_value_request_spec.rb +88 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/query_value_response_spec.rb +150 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/regsam_spec.rb +32 -0
- data/spec/lib/ruby_smb/dcerpc/winreg_spec.rb +710 -0
- data/spec/lib/ruby_smb/dcerpc_spec.rb +81 -0
- data/spec/lib/ruby_smb/smb1/file_spec.rb +9 -1
- data/spec/lib/ruby_smb/smb1/pipe_spec.rb +210 -148
- data/spec/lib/ruby_smb/smb2/packet/error_packet_spec.rb +3 -24
- data/spec/lib/ruby_smb/smb2/pipe_spec.rb +256 -145
- metadata +66 -9
- metadata.gz.sig +0 -0
- data/lib/ruby_smb/smb1/dcerpc.rb +0 -72
- data/lib/ruby_smb/smb2/dcerpc.rb +0 -75
@@ -35,17 +35,6 @@ RSpec.describe RubySMB::SMB2::Packet::ErrorPacket do
|
|
35
35
|
it 'should be a 32-bit unsigned integer' do
|
36
36
|
expect(packet.byte_count).to be_a BinData::Uint32le
|
37
37
|
end
|
38
|
-
|
39
|
-
it 'should be the number of bytes in #error_data' do
|
40
|
-
str = 'testing'
|
41
|
-
packet.error_data = str
|
42
|
-
expect(packet.byte_count).to eq str.size
|
43
|
-
end
|
44
|
-
|
45
|
-
it 'should be 0 when #error_data is 1-byte long' do
|
46
|
-
packet.error_data = "\x00"
|
47
|
-
expect(packet.byte_count).to eq 0
|
48
|
-
end
|
49
38
|
end
|
50
39
|
|
51
40
|
describe '#error_data' do
|
@@ -53,20 +42,10 @@ RSpec.describe RubySMB::SMB2::Packet::ErrorPacket do
|
|
53
42
|
expect(packet.error_data).to be_a BinData::String
|
54
43
|
end
|
55
44
|
|
56
|
-
it 'should
|
57
|
-
expect(packet.error_data).to eq "\x00"
|
58
|
-
end
|
59
|
-
|
60
|
-
it 'should read 1 byte when #byte_count is 0' do
|
61
|
-
packet.error_data = 'test'
|
62
|
-
packet.byte_count = 0
|
63
|
-
expect(described_class.read(packet.to_binary_s).error_data.size).to eq 1
|
64
|
-
end
|
65
|
-
|
66
|
-
it 'should read #byte_count bytes when #byte_count is not 0' do
|
45
|
+
it 'should read #byte_count bytes' do
|
67
46
|
packet.error_data = 'test'
|
68
|
-
packet.byte_count =
|
69
|
-
expect(described_class.read(packet.to_binary_s).error_data.size).to eq
|
47
|
+
packet.byte_count = 3
|
48
|
+
expect(described_class.read(packet.to_binary_s).error_data.size).to eq 3
|
70
49
|
end
|
71
50
|
end
|
72
51
|
|
@@ -27,14 +27,14 @@ RSpec.describe RubySMB::SMB2::Pipe do
|
|
27
27
|
last_write: time
|
28
28
|
)
|
29
29
|
}
|
30
|
-
|
31
30
|
let(:ioctl_response) {
|
32
31
|
packet = RubySMB::SMB2::Packet::IoctlResponse.new
|
33
32
|
packet.buffer = "\x03\x00\x00\x00" + "\x10\x20\x30\x40" + "\x00\x00\x00\x00" + "\x00\x00\x00\x00"
|
34
33
|
packet
|
35
34
|
}
|
35
|
+
let(:filename) { 'msf-pipe' }
|
36
36
|
|
37
|
-
subject(:pipe) { described_class.new(name:
|
37
|
+
subject(:pipe) { described_class.new(name: filename, response: create_response, tree: tree) }
|
38
38
|
|
39
39
|
describe '#peek' do
|
40
40
|
let(:request) { RubySMB::SMB2::Packet::IoctlRequest.new }
|
@@ -127,206 +127,317 @@ RSpec.describe RubySMB::SMB2::Pipe do
|
|
127
127
|
end
|
128
128
|
end
|
129
129
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
allow(pipe).to receive(:bind)
|
137
|
-
allow(pipe).to receive(:request).and_return(dcerpc_response)
|
138
|
-
allow(RubySMB::Dcerpc::Srvsvc::NetShareEnumAll).to receive(:parse_response).and_return([])
|
130
|
+
describe '#initialize' do
|
131
|
+
context 'when name is not provided' do
|
132
|
+
it 'raises an ArgumentError' do
|
133
|
+
expect {
|
134
|
+
described_class.new(tree: tree, response: create_response, name: nil)
|
135
|
+
}.to raise_error(ArgumentError)
|
139
136
|
end
|
137
|
+
end
|
140
138
|
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
139
|
+
it 'calls the superclass with the expected arguments' do
|
140
|
+
expect(pipe.tree).to eq(tree)
|
141
|
+
expect(pipe.name).to eq(filename)
|
142
|
+
expect(pipe.attributes).to eq(create_response.file_attributes)
|
143
|
+
expect(pipe.guid).to eq(create_response.file_id)
|
144
|
+
expect(pipe.last_access).to eq(create_response.last_access.to_datetime)
|
145
|
+
expect(pipe.last_change).to eq(create_response.last_change.to_datetime)
|
146
|
+
expect(pipe.last_write).to eq(create_response.last_write.to_datetime)
|
147
|
+
expect(pipe.size).to eq(create_response.end_of_file)
|
148
|
+
expect(pipe.size_on_disk).to eq(create_response.allocation_size)
|
149
|
+
end
|
145
150
|
|
146
|
-
|
147
|
-
|
148
|
-
pipe.
|
151
|
+
context 'with \'srvsvc\' filename' do
|
152
|
+
it 'extends Srvsvc class' do
|
153
|
+
pipe = described_class.new(tree: tree, response: create_response, name: 'srvsvc')
|
154
|
+
expect(pipe.respond_to?(:net_share_enum_all)).to be true
|
149
155
|
end
|
156
|
+
end
|
150
157
|
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
expect(RubySMB::Dcerpc::Srvsvc::NetShareEnumAll).to receive(:parse_response).with(stub)
|
156
|
-
pipe.net_share_enum_all(host)
|
158
|
+
context 'with \'winreg\' filename' do
|
159
|
+
it 'extends Winreg class' do
|
160
|
+
pipe = described_class.new(tree: tree, response: create_response, name: 'winreg')
|
161
|
+
expect(pipe.respond_to?(:has_registry_key?)).to be true
|
157
162
|
end
|
163
|
+
end
|
164
|
+
end
|
158
165
|
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
166
|
+
describe '#dcerpc_request' do
|
167
|
+
let(:options) { { host: '1.2.3.4' } }
|
168
|
+
let(:stub_packet ) { RubySMB::Dcerpc::Winreg::OpenKeyRequest.new }
|
169
|
+
let(:dcerpc_request) { double('DCERPC Request') }
|
170
|
+
let(:request_stub) { double('Request stub') }
|
171
|
+
before :example do
|
172
|
+
allow(RubySMB::Dcerpc::Request).to receive(:new).and_return(dcerpc_request)
|
173
|
+
allow(dcerpc_request).to receive(:stub).and_return(request_stub)
|
174
|
+
allow(request_stub).to receive(:read)
|
175
|
+
allow(pipe).to receive(:ioctl_send_recv)
|
176
|
+
end
|
177
|
+
|
178
|
+
it 'creates a Request packet with the expected arguments' do
|
179
|
+
pipe.dcerpc_request(stub_packet, options)
|
180
|
+
expect(options).to eq( { host: '1.2.3.4', endpoint: 'Winreg' })
|
181
|
+
expect(RubySMB::Dcerpc::Request).to have_received(:new).with({ opnum: stub_packet.opnum }, options)
|
182
|
+
end
|
183
|
+
|
184
|
+
it 'sets DCERPC request stub to the stub packet passed as argument' do
|
185
|
+
pipe.dcerpc_request(stub_packet, options)
|
186
|
+
expect(request_stub).to have_received(:read).with(stub_packet.to_binary_s)
|
187
|
+
end
|
188
|
+
|
189
|
+
it 'calls #ioctl_send_recv with the expected arguments' do
|
190
|
+
pipe.dcerpc_request(stub_packet, options)
|
191
|
+
expect(pipe).to have_received(:ioctl_send_recv).with(dcerpc_request, options)
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
describe '#ioctl_send_recv' do
|
196
|
+
let(:ioctl_request_packet) { double('IoctlRequest') }
|
197
|
+
let(:flags) { double('Flags') }
|
198
|
+
let(:dcerpc_request) { double('DCERPC Request') }
|
199
|
+
let(:binary_dcerpc_request) { double('Binary DCERPC Request') }
|
200
|
+
let(:options) { { host: '1.2.3.4' } }
|
201
|
+
let(:ioctl_raw_response) { double('IOCTL raw response') }
|
202
|
+
let(:ioctl_response) { double('IOCTL response') }
|
203
|
+
let(:raw_data) { double('Raw data') }
|
204
|
+
let(:dcerpc_response) { double('DCERPC Response') }
|
205
|
+
let(:result) { 'Result' }
|
206
|
+
before :example do
|
207
|
+
allow(RubySMB::SMB2::Packet::IoctlRequest).to receive(:new).and_return(ioctl_request_packet)
|
208
|
+
allow(pipe).to receive(:set_header_fields).and_return(ioctl_request_packet)
|
209
|
+
allow(ioctl_request_packet).to receive_messages(
|
210
|
+
:ctl_code= => nil,
|
211
|
+
:flags => flags,
|
212
|
+
:buffer= => nil
|
213
|
+
)
|
214
|
+
allow(flags).to receive(:is_fsctl=)
|
215
|
+
allow(dcerpc_request).to receive(:to_binary_s).and_return(binary_dcerpc_request)
|
216
|
+
allow(client).to receive(:send_recv).and_return(ioctl_raw_response)
|
217
|
+
allow(RubySMB::SMB2::Packet::IoctlResponse).to receive(:read).and_return(ioctl_response)
|
218
|
+
allow(ioctl_response).to receive_messages(
|
219
|
+
:valid? => true,
|
220
|
+
:status_code => WindowsError::NTStatus::STATUS_SUCCESS,
|
221
|
+
:output_data => raw_data
|
222
|
+
)
|
223
|
+
allow(RubySMB::Dcerpc::Response).to receive(:read).and_return(dcerpc_response)
|
224
|
+
allow(dcerpc_response).to receive_message_chain(:pdu_header, :ptype => RubySMB::Dcerpc::PTypes::RESPONSE)
|
225
|
+
allow(dcerpc_response).to receive(:stub).and_return(result)
|
226
|
+
end
|
227
|
+
|
228
|
+
it 'creates an IoctlRequest packet' do
|
229
|
+
pipe.ioctl_send_recv(dcerpc_request, options)
|
230
|
+
expect(RubySMB::SMB2::Packet::IoctlRequest).to have_received(:new).with(options)
|
231
|
+
end
|
232
|
+
|
233
|
+
it 'calls #set_header_fields' do
|
234
|
+
pipe.ioctl_send_recv(dcerpc_request, options)
|
235
|
+
expect(pipe).to have_received(:set_header_fields).with(ioctl_request_packet)
|
236
|
+
end
|
237
|
+
|
238
|
+
it 'sets the expected properties on the request packet' do
|
239
|
+
pipe.ioctl_send_recv(dcerpc_request, options)
|
240
|
+
expect(ioctl_request_packet).to have_received(:ctl_code=).with(0x11C017)
|
241
|
+
expect(flags).to have_received(:is_fsctl=).with(0x1)
|
242
|
+
expect(ioctl_request_packet).to have_received(:buffer=).with(binary_dcerpc_request)
|
175
243
|
end
|
176
244
|
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
245
|
+
it 'sends the expected request' do
|
246
|
+
pipe.ioctl_send_recv(dcerpc_request, options)
|
247
|
+
expect(client).to have_received(:send_recv).with(ioctl_request_packet)
|
248
|
+
end
|
249
|
+
|
250
|
+
it 'creates an IoctlResponse packet from the response' do
|
251
|
+
pipe.ioctl_send_recv(dcerpc_request, options)
|
252
|
+
expect(RubySMB::SMB2::Packet::IoctlResponse).to have_received(:read).with(ioctl_raw_response)
|
253
|
+
end
|
181
254
|
|
255
|
+
context 'when the response is not an IoctlResponse packet' do
|
256
|
+
it 'raises an InvalidPacket exception' do
|
257
|
+
allow(ioctl_response).to receive_message_chain(:smb2_header, :protocol)
|
258
|
+
allow(ioctl_response).to receive_message_chain(:smb2_header, :command)
|
259
|
+
allow(ioctl_response).to receive(:valid?).and_return(false)
|
260
|
+
expect { pipe.ioctl_send_recv(dcerpc_request, options) }.to raise_error(RubySMB::Error::InvalidPacket)
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
context 'when the response status code is STATUS_PENDING' do
|
265
|
+
let(:ioctl_raw_response2) { double('IOCTL raw response #2') }
|
266
|
+
let(:ioctl_response2) { double('IOCTL response #2') }
|
182
267
|
before :example do
|
183
|
-
allow(
|
184
|
-
allow(pipe).to receive(:
|
185
|
-
allow(
|
186
|
-
|
187
|
-
|
188
|
-
|
268
|
+
allow(ioctl_response).to receive(:status_code).and_return(WindowsError::NTStatus::STATUS_PENDING)
|
269
|
+
allow(pipe).to receive(:sleep)
|
270
|
+
allow(dispatcher).to receive(:recv_packet).and_return(ioctl_raw_response2)
|
271
|
+
allow(RubySMB::SMB2::Packet::IoctlResponse).to receive(:read).with(ioctl_raw_response2).and_return(ioctl_response2)
|
272
|
+
allow(ioctl_response2).to receive_messages(
|
273
|
+
:valid? => true,
|
274
|
+
:output_data => raw_data,
|
275
|
+
:status_code => WindowsError::NTStatus::STATUS_SUCCESS
|
276
|
+
)
|
277
|
+
end
|
278
|
+
|
279
|
+
it 'waits 1 second' do
|
280
|
+
pipe.ioctl_send_recv(dcerpc_request, options)
|
281
|
+
expect(pipe).to have_received(:sleep).with(1)
|
189
282
|
end
|
190
283
|
|
191
|
-
it '
|
192
|
-
|
193
|
-
|
284
|
+
it 'calls dispatcher #recv_packet' do
|
285
|
+
pipe.ioctl_send_recv(dcerpc_request, options)
|
286
|
+
expect(dispatcher).to have_received(:recv_packet)
|
194
287
|
end
|
195
288
|
|
196
|
-
it '
|
197
|
-
|
198
|
-
|
289
|
+
it 'creates an IoctlResponse packet from the response' do
|
290
|
+
pipe.ioctl_send_recv(dcerpc_request, options)
|
291
|
+
expect(RubySMB::SMB2::Packet::IoctlResponse).to have_received(:read).with(ioctl_raw_response2)
|
199
292
|
end
|
200
293
|
|
201
|
-
|
202
|
-
|
203
|
-
|
294
|
+
context 'when the response is not an IoctlResponse packet' do
|
295
|
+
it 'raises an InvalidPacket exception' do
|
296
|
+
allow(ioctl_response2).to receive_message_chain(:smb2_header, :protocol)
|
297
|
+
allow(ioctl_response2).to receive_message_chain(:smb2_header, :command)
|
298
|
+
allow(ioctl_response2).to receive(:valid?).and_return(false)
|
299
|
+
expect { pipe.ioctl_send_recv(dcerpc_request, options) }.to raise_error(RubySMB::Error::InvalidPacket)
|
300
|
+
end
|
204
301
|
end
|
302
|
+
end
|
205
303
|
|
206
|
-
|
207
|
-
|
208
|
-
allow(
|
209
|
-
expect(
|
210
|
-
pipe.bind(options)
|
304
|
+
context 'when the response status code is not STATUS_SUCCESS or STATUS_BUFFER_OVERFLOW' do
|
305
|
+
it 'raises an UnexpectedStatusCode exception' do
|
306
|
+
allow(ioctl_response).to receive(:status_code).and_return(WindowsError::NTStatus::STATUS_INVALID_HANDLE)
|
307
|
+
expect { pipe.ioctl_send_recv(dcerpc_request, options) }.to raise_error(RubySMB::Error::UnexpectedStatusCode)
|
211
308
|
end
|
309
|
+
end
|
212
310
|
|
213
|
-
|
214
|
-
|
215
|
-
expect { pipe.
|
311
|
+
context 'when the response status code is STATUS_SUCCESS' do
|
312
|
+
it 'does not raise any exception' do
|
313
|
+
expect { pipe.ioctl_send_recv(dcerpc_request, options)}.not_to raise_error
|
216
314
|
end
|
217
315
|
|
218
|
-
it '
|
219
|
-
|
220
|
-
|
221
|
-
expect { pipe.bind(options) }.to raise_error(RubySMB::Dcerpc::Error::BindError)
|
316
|
+
it 'creates a DCERPC Response packet from the response' do
|
317
|
+
pipe.ioctl_send_recv(dcerpc_request, options)
|
318
|
+
expect(RubySMB::Dcerpc::Response).to have_received(:read).with(raw_data)
|
222
319
|
end
|
223
320
|
|
224
|
-
|
225
|
-
|
226
|
-
|
321
|
+
context 'when an IOError occurs while parsing the DCERPC response' do
|
322
|
+
it 'raises an InvalidPacket exception' do
|
323
|
+
allow(RubySMB::Dcerpc::Response).to receive(:read).and_raise(IOError)
|
324
|
+
expect { pipe.ioctl_send_recv(dcerpc_request, options) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
|
325
|
+
end
|
227
326
|
end
|
228
327
|
|
229
|
-
|
230
|
-
|
231
|
-
|
328
|
+
context 'when the response is not a DCERPC Response packet' do
|
329
|
+
it 'raises an InvalidPacket exception' do
|
330
|
+
allow(dcerpc_response).to receive_message_chain(:pdu_header, :ptype => RubySMB::Dcerpc::PTypes::FAULT)
|
331
|
+
expect { pipe.ioctl_send_recv(dcerpc_request, options) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
|
332
|
+
end
|
232
333
|
end
|
233
334
|
|
234
|
-
it 'returns the expected
|
235
|
-
expect(pipe.
|
335
|
+
it 'returns the expected stub data' do
|
336
|
+
expect(pipe.ioctl_send_recv(dcerpc_request, options)).to eq(result)
|
236
337
|
end
|
237
338
|
end
|
238
339
|
|
239
|
-
|
240
|
-
let(:
|
241
|
-
let(:
|
242
|
-
let(:req_packet) { RubySMB::Dcerpc::Request.new({ :opnum => opnum }, options) }
|
243
|
-
let(:ioctl_response) { RubySMB::SMB2::Packet::IoctlResponse.new }
|
244
|
-
let(:res_packet) { RubySMB::Dcerpc::Response.new }
|
245
|
-
|
340
|
+
context 'when the response status code is STATUS_BUFFER_OVERFLOW' do
|
341
|
+
let(:data_count) { 100 }
|
342
|
+
let(:added_raw_data) { double('Added raw data') }
|
246
343
|
before :example do
|
247
|
-
allow(
|
248
|
-
allow(
|
249
|
-
allow(
|
344
|
+
allow(ioctl_response).to receive(:status_code).and_return(WindowsError::NTStatus::STATUS_BUFFER_OVERFLOW)
|
345
|
+
allow(ioctl_response).to receive(:output_count).and_return(data_count)
|
346
|
+
allow(pipe).to receive(:read).and_return(added_raw_data)
|
347
|
+
allow(raw_data).to receive(:<<)
|
348
|
+
allow(dcerpc_response).to receive_message_chain(:pdu_header, :pfc_flags, :first_frag => 1)
|
349
|
+
allow(dcerpc_response).to receive_message_chain(:pdu_header, :pfc_flags, :last_frag => 1)
|
250
350
|
end
|
251
351
|
|
252
|
-
it '
|
253
|
-
expect(
|
254
|
-
pipe.request(opnum, options)
|
352
|
+
it 'does not raise any exception' do
|
353
|
+
expect { pipe.ioctl_send_recv(dcerpc_request, options) }.not_to raise_error
|
255
354
|
end
|
256
355
|
|
257
|
-
it '
|
258
|
-
|
259
|
-
pipe.
|
356
|
+
it 'reads the expected number of bytes and concatenate it the first response raw data' do
|
357
|
+
pipe.ioctl_send_recv(dcerpc_request, options)
|
358
|
+
expect(pipe).to have_received(:read).with(bytes: tree.client.max_buffer_size - data_count)
|
359
|
+
expect(raw_data).to have_received(:<<).with(added_raw_data)
|
260
360
|
end
|
261
361
|
|
262
|
-
it 'creates a DCERPC Response packet from the
|
263
|
-
|
264
|
-
|
362
|
+
it 'creates a DCERPC Response packet from the updated raw data' do
|
363
|
+
pipe.ioctl_send_recv(dcerpc_request, options)
|
364
|
+
expect(RubySMB::Dcerpc::Response).to have_received(:read).with(raw_data)
|
265
365
|
end
|
266
366
|
|
267
|
-
|
268
|
-
|
269
|
-
|
367
|
+
context 'when an IOError occurs while parsing the DCERPC response' do
|
368
|
+
it 'raises an InvalidPacket exception' do
|
369
|
+
allow(RubySMB::Dcerpc::Response).to receive(:read).and_raise(IOError)
|
370
|
+
expect { pipe.ioctl_send_recv(dcerpc_request, options) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
|
371
|
+
end
|
270
372
|
end
|
271
373
|
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
374
|
+
context 'when the response is not a DCERPC Response packet' do
|
375
|
+
it 'raises an InvalidPacket exception' do
|
376
|
+
allow(dcerpc_response).to receive_message_chain(:pdu_header, :ptype => RubySMB::Dcerpc::PTypes::FAULT)
|
377
|
+
expect { pipe.ioctl_send_recv(dcerpc_request, options) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
|
378
|
+
end
|
276
379
|
end
|
277
380
|
|
278
|
-
|
279
|
-
|
381
|
+
context 'when the response is not the first fragment' do
|
382
|
+
it 'raises an InvalidPacket exception' do
|
383
|
+
allow(dcerpc_response).to receive_message_chain(:pdu_header, :pfc_flags, :first_frag => 0)
|
384
|
+
expect { pipe.ioctl_send_recv(dcerpc_request, options) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
|
385
|
+
end
|
280
386
|
end
|
281
|
-
end
|
282
387
|
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
388
|
+
context 'when the response is the last fragment' do
|
389
|
+
it 'only reads the pipe once' do
|
390
|
+
pipe.ioctl_send_recv(dcerpc_request, options)
|
391
|
+
expect(RubySMB::Dcerpc::Response).to have_received(:read).once
|
392
|
+
end
|
288
393
|
|
289
|
-
|
290
|
-
|
394
|
+
it 'returns the expected stub data' do
|
395
|
+
expect(pipe.ioctl_send_recv(dcerpc_request, options)).to eq(result)
|
396
|
+
end
|
291
397
|
end
|
292
398
|
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
399
|
+
context 'when the response is not the last fragment' do
|
400
|
+
let(:raw_data2) { double('Raw data #2') }
|
401
|
+
let(:dcerpc_response2) { double('DCERPC Response #2') }
|
402
|
+
let(:result2) { 'Result #2' }
|
403
|
+
before :example do
|
404
|
+
allow(dcerpc_response).to receive_message_chain(:pdu_header, :pfc_flags, :last_frag => 0)
|
405
|
+
allow(pipe).to receive(:read).with(bytes: tree.client.max_buffer_size).and_return(raw_data2)
|
406
|
+
allow(RubySMB::Dcerpc::Response).to receive(:read).with(raw_data2).and_return(dcerpc_response2)
|
407
|
+
allow(dcerpc_response2).to receive_message_chain(:pdu_header, :ptype => RubySMB::Dcerpc::PTypes::RESPONSE)
|
408
|
+
allow(dcerpc_response2).to receive_message_chain(:pdu_header, :pfc_flags, :last_frag => 1)
|
409
|
+
allow(dcerpc_response2).to receive(:stub).and_return(result2)
|
410
|
+
end
|
297
411
|
|
298
|
-
|
299
|
-
|
300
|
-
expect(
|
301
|
-
expect(req.flags.is_fsctl).to eq(0x00000001)
|
302
|
-
expect(req.buffer).to eq(action.to_binary_s)
|
303
|
-
ioctl_response.to_binary_s
|
412
|
+
it 'reads the expected number of bytes' do
|
413
|
+
pipe.ioctl_send_recv(dcerpc_request, options)
|
414
|
+
expect(pipe).to have_received(:read).with(bytes: tree.client.max_buffer_size)
|
304
415
|
end
|
305
|
-
pipe.ioctl_send_recv(action, options)
|
306
|
-
end
|
307
416
|
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
417
|
+
it 'creates a DCERPC Response packet from the new raw data' do
|
418
|
+
pipe.ioctl_send_recv(dcerpc_request, options)
|
419
|
+
expect(RubySMB::Dcerpc::Response).to have_received(:read).with(raw_data2)
|
420
|
+
end
|
312
421
|
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
422
|
+
context 'when an IOError occurs while parsing the new DCERPC response' do
|
423
|
+
it 'raises an InvalidPacket exception' do
|
424
|
+
allow(RubySMB::Dcerpc::Response).to receive(:read).with(raw_data2).and_raise(IOError)
|
425
|
+
expect { pipe.ioctl_send_recv(dcerpc_request, options) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
|
426
|
+
end
|
427
|
+
end
|
318
428
|
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
429
|
+
context 'when the new response is not a DCERPC Response packet' do
|
430
|
+
it 'raises an InvalidPacket exception' do
|
431
|
+
allow(dcerpc_response2).to receive_message_chain(:pdu_header, :ptype => RubySMB::Dcerpc::PTypes::FAULT)
|
432
|
+
expect { pipe.ioctl_send_recv(dcerpc_request, options) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
|
433
|
+
end
|
434
|
+
end
|
325
435
|
|
326
|
-
|
327
|
-
|
436
|
+
it 'returns the expected stub data' do
|
437
|
+
expect(pipe.ioctl_send_recv(dcerpc_request, options)).to eq(result)
|
438
|
+
end
|
328
439
|
end
|
329
440
|
end
|
330
441
|
end
|
331
|
-
end
|
332
442
|
|
443
|
+
end
|