ruby_smb 1.0.5 → 2.0.3
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 +5 -5
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/.travis.yml +3 -2
- data/Gemfile +6 -2
- data/README.md +35 -47
- data/examples/anonymous_auth.rb +3 -3
- data/examples/append_file.rb +10 -8
- data/examples/authenticate.rb +9 -5
- data/examples/delete_file.rb +8 -6
- data/examples/enum_registry_key.rb +29 -0
- data/examples/enum_registry_values.rb +31 -0
- data/examples/list_directory.rb +8 -6
- data/examples/negotiate.rb +51 -8
- data/examples/negotiate_with_netbios_service.rb +9 -5
- data/examples/net_share_enum_all.rb +6 -4
- data/examples/pipes.rb +13 -13
- data/examples/query_service_status.rb +64 -0
- data/examples/read_file.rb +8 -6
- data/examples/read_file_encryption.rb +56 -0
- data/examples/read_registry_key_value.rb +33 -0
- data/examples/rename_file.rb +9 -7
- data/examples/tree_connect.rb +7 -5
- data/examples/write_file.rb +9 -7
- data/lib/ruby_smb.rb +4 -1
- data/lib/ruby_smb/client.rb +239 -21
- data/lib/ruby_smb/client/authentication.rb +27 -8
- data/lib/ruby_smb/client/encryption.rb +62 -0
- data/lib/ruby_smb/client/negotiation.rb +154 -12
- data/lib/ruby_smb/client/signing.rb +19 -0
- data/lib/ruby_smb/client/tree_connect.rb +4 -4
- data/lib/ruby_smb/client/utils.rb +8 -7
- data/lib/ruby_smb/client/winreg.rb +46 -0
- data/lib/ruby_smb/crypto.rb +30 -0
- data/lib/ruby_smb/dcerpc.rb +40 -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 +6 -0
- data/lib/ruby_smb/dcerpc/ndr.rb +260 -16
- data/lib/ruby_smb/dcerpc/pdu_header.rb +1 -1
- data/lib/ruby_smb/dcerpc/request.rb +41 -9
- data/lib/ruby_smb/dcerpc/rpc_security_attributes.rb +34 -0
- data/lib/ruby_smb/dcerpc/rrp_unicode_string.rb +38 -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/svcctl.rb +479 -0
- data/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_request.rb +48 -0
- data/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_response.rb +26 -0
- data/lib/ruby_smb/dcerpc/svcctl/close_service_handle_request.rb +25 -0
- data/lib/ruby_smb/dcerpc/svcctl/close_service_handle_response.rb +26 -0
- data/lib/ruby_smb/dcerpc/svcctl/control_service_request.rb +26 -0
- data/lib/ruby_smb/dcerpc/svcctl/control_service_response.rb +26 -0
- data/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_request.rb +35 -0
- data/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_response.rb +23 -0
- data/lib/ruby_smb/dcerpc/svcctl/open_service_w_request.rb +31 -0
- data/lib/ruby_smb/dcerpc/svcctl/open_service_w_response.rb +23 -0
- data/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_request.rb +25 -0
- data/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_response.rb +44 -0
- data/lib/ruby_smb/dcerpc/svcctl/query_service_status_request.rb +23 -0
- data/lib/ruby_smb/dcerpc/svcctl/query_service_status_response.rb +27 -0
- data/lib/ruby_smb/dcerpc/svcctl/service_status.rb +25 -0
- data/lib/ruby_smb/dcerpc/svcctl/start_service_w_request.rb +27 -0
- data/lib/ruby_smb/dcerpc/svcctl/start_service_w_response.rb +25 -0
- data/lib/ruby_smb/dcerpc/winreg.rb +421 -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/create_key_request.rb +73 -0
- data/lib/ruby_smb/dcerpc/winreg/create_key_response.rb +36 -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 +40 -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/dcerpc/winreg/save_key_request.rb +37 -0
- data/lib/ruby_smb/dcerpc/winreg/save_key_response.rb +23 -0
- data/lib/ruby_smb/dispatcher/base.rb +1 -1
- data/lib/ruby_smb/dispatcher/socket.rb +5 -4
- data/lib/ruby_smb/error.rb +28 -1
- data/lib/ruby_smb/field/stringz16.rb +17 -1
- data/lib/ruby_smb/nbss/session_header.rb +4 -4
- data/lib/ruby_smb/smb1/commands.rb +1 -1
- data/lib/ruby_smb/smb1/file.rb +8 -14
- data/lib/ruby_smb/smb1/packet/session_setup_legacy_request.rb +1 -1
- data/lib/ruby_smb/smb1/packet/session_setup_legacy_response.rb +2 -2
- data/lib/ruby_smb/smb1/packet/session_setup_request.rb +1 -1
- data/lib/ruby_smb/smb1/packet/session_setup_response.rb +2 -2
- data/lib/ruby_smb/smb1/packet/write_andx_request.rb +1 -1
- data/lib/ruby_smb/smb1/pipe.rb +81 -3
- data/lib/ruby_smb/smb1/tree.rb +12 -3
- data/lib/ruby_smb/smb2/bit_field/session_flags.rb +2 -1
- data/lib/ruby_smb/smb2/bit_field/share_flags.rb +6 -4
- data/lib/ruby_smb/smb2/file.rb +51 -61
- data/lib/ruby_smb/smb2/negotiate_context.rb +108 -0
- data/lib/ruby_smb/smb2/packet.rb +2 -0
- data/lib/ruby_smb/smb2/packet/compression_transform_header.rb +41 -0
- data/lib/ruby_smb/smb2/packet/error_packet.rb +2 -4
- data/lib/ruby_smb/smb2/packet/negotiate_request.rb +51 -14
- data/lib/ruby_smb/smb2/packet/negotiate_response.rb +50 -4
- data/lib/ruby_smb/smb2/packet/transform_header.rb +84 -0
- data/lib/ruby_smb/smb2/packet/tree_connect_request.rb +92 -6
- data/lib/ruby_smb/smb2/packet/tree_connect_response.rb +8 -26
- data/lib/ruby_smb/smb2/pipe.rb +80 -3
- data/lib/ruby_smb/smb2/smb2_header.rb +1 -1
- data/lib/ruby_smb/smb2/tree.rb +32 -20
- data/lib/ruby_smb/version.rb +1 -1
- data/ruby_smb.gemspec +5 -3
- data/spec/lib/ruby_smb/client_spec.rb +1583 -102
- data/spec/lib/ruby_smb/crypto_spec.rb +25 -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 +1729 -0
- data/spec/lib/ruby_smb/dcerpc/request_spec.rb +50 -7
- data/spec/lib/ruby_smb/dcerpc/rpc_security_attributes_spec.rb +161 -0
- data/spec/lib/ruby_smb/dcerpc/rrp_unicode_string_spec.rb +135 -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/svcctl/change_service_config_w_request_spec.rb +191 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_response_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/close_service_handle_request_spec.rb +30 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/close_service_handle_response_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/control_service_request_spec.rb +39 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/control_service_response_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_request_spec.rb +78 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_response_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/open_service_w_request_spec.rb +59 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/open_service_w_response_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_request_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_response_spec.rb +152 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_status_request_spec.rb +30 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_status_response_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/service_status_spec.rb +72 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/start_service_w_request_spec.rb +46 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/start_service_w_response_spec.rb +30 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl_spec.rb +512 -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/create_key_request_spec.rb +110 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/create_key_response_spec.rb +44 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_request_spec.rb +104 -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 +95 -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 +35 -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 +138 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/regsam_spec.rb +32 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/save_key_request_spec.rb +57 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/save_key_response_spec.rb +22 -0
- data/spec/lib/ruby_smb/dcerpc/winreg_spec.rb +884 -0
- data/spec/lib/ruby_smb/dcerpc_spec.rb +81 -0
- data/spec/lib/ruby_smb/dispatcher/socket_spec.rb +12 -12
- data/spec/lib/ruby_smb/error_spec.rb +59 -0
- data/spec/lib/ruby_smb/field/stringz16_spec.rb +12 -0
- data/spec/lib/ruby_smb/nbss/session_header_spec.rb +4 -11
- data/spec/lib/ruby_smb/smb1/file_spec.rb +9 -1
- data/spec/lib/ruby_smb/smb1/packet/session_setup_legacy_request_spec.rb +2 -2
- data/spec/lib/ruby_smb/smb1/packet/session_setup_legacy_response_spec.rb +2 -2
- data/spec/lib/ruby_smb/smb1/packet/session_setup_request_spec.rb +2 -2
- data/spec/lib/ruby_smb/smb1/packet/session_setup_response_spec.rb +1 -1
- data/spec/lib/ruby_smb/smb1/pipe_spec.rb +216 -147
- data/spec/lib/ruby_smb/smb2/bit_field/session_flags_spec.rb +9 -0
- data/spec/lib/ruby_smb/smb2/bit_field/share_flags_spec.rb +27 -0
- data/spec/lib/ruby_smb/smb2/file_spec.rb +146 -68
- data/spec/lib/ruby_smb/smb2/negotiate_context_spec.rb +332 -0
- data/spec/lib/ruby_smb/smb2/packet/compression_transform_header_spec.rb +108 -0
- data/spec/lib/ruby_smb/smb2/packet/error_packet_spec.rb +3 -24
- data/spec/lib/ruby_smb/smb2/packet/negotiate_request_spec.rb +138 -3
- data/spec/lib/ruby_smb/smb2/packet/negotiate_response_spec.rb +120 -2
- data/spec/lib/ruby_smb/smb2/packet/transform_header_spec.rb +220 -0
- data/spec/lib/ruby_smb/smb2/packet/tree_connect_request_spec.rb +339 -9
- data/spec/lib/ruby_smb/smb2/packet/tree_connect_response_spec.rb +3 -30
- data/spec/lib/ruby_smb/smb2/pipe_spec.rb +226 -148
- data/spec/lib/ruby_smb/smb2/smb2_header_spec.rb +2 -2
- data/spec/lib/ruby_smb/smb2/tree_spec.rb +88 -9
- metadata +257 -81
- metadata.gz.sig +0 -0
- data/lib/ruby_smb/smb1/dcerpc.rb +0 -72
- data/lib/ruby_smb/smb2/dcerpc.rb +0 -75
@@ -0,0 +1,81 @@
|
|
1
|
+
RSpec.describe RubySMB::Dcerpc do
|
2
|
+
let(:tree) { double('Tree') }
|
3
|
+
let(:pipe) do
|
4
|
+
RubySMB::SMB1::Pipe.new(
|
5
|
+
tree: tree,
|
6
|
+
response: RubySMB::SMB1::Packet::NtCreateAndxResponse.new,
|
7
|
+
name: 'winreg'
|
8
|
+
)
|
9
|
+
end
|
10
|
+
|
11
|
+
describe '#bind' do
|
12
|
+
let(:options) { { endpoint: RubySMB::Dcerpc::Winreg } }
|
13
|
+
let(:bind_packet) { RubySMB::Dcerpc::Bind.new(options) }
|
14
|
+
let(:bind_ack_packet) { RubySMB::Dcerpc::BindAck.new }
|
15
|
+
let(:client) { double('Client') }
|
16
|
+
|
17
|
+
before :example do
|
18
|
+
allow(RubySMB::Dcerpc::Bind).to receive(:new).and_return(bind_packet)
|
19
|
+
allow(pipe).to receive(:write)
|
20
|
+
allow(pipe).to receive(:read)
|
21
|
+
bind_ack_packet.p_result_list.n_results = 1
|
22
|
+
bind_ack_packet.p_result_list.p_results[0].result = RubySMB::Dcerpc::BindAck::ACCEPTANCE
|
23
|
+
allow(RubySMB::Dcerpc::BindAck).to receive(:read).and_return(bind_ack_packet)
|
24
|
+
allow(tree).to receive(:client).and_return(client)
|
25
|
+
allow(client).to receive(:max_buffer_size=)
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'creates a Bind packet' do
|
29
|
+
pipe.bind(options)
|
30
|
+
expect(RubySMB::Dcerpc::Bind).to have_received(:new).with(options)
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'writes to the named pipe' do
|
34
|
+
pipe.bind(options)
|
35
|
+
expect(pipe).to have_received(:write).with(data: bind_packet.to_binary_s)
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'reads the socket' do
|
39
|
+
pipe.bind(options)
|
40
|
+
expect(pipe).to have_received(:read)
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'creates a BindAck packet from the response' do
|
44
|
+
raw_response = RubySMB::Dcerpc::BindAck.new.to_binary_s
|
45
|
+
allow(pipe).to receive(:read).and_return(raw_response)
|
46
|
+
pipe.bind(options)
|
47
|
+
expect(RubySMB::Dcerpc::BindAck).to have_received(:read).with(raw_response)
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'raises the expected exception when an invalid packet is received' do
|
51
|
+
allow(RubySMB::Dcerpc::BindAck).to receive(:read).and_raise(IOError)
|
52
|
+
expect { pipe.bind(options) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'raises the expected exception when it is not a BindAck packet' do
|
56
|
+
response = RubySMB::Dcerpc::Bind.new
|
57
|
+
allow(RubySMB::Dcerpc::BindAck).to receive(:read).and_return(response)
|
58
|
+
expect { pipe.bind(options) }.to raise_error(RubySMB::Dcerpc::Error::BindError)
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'raises an exception when no result is returned' do
|
62
|
+
bind_ack_packet.p_result_list.n_results = 0
|
63
|
+
expect { pipe.bind(options) }.to raise_error(RubySMB::Dcerpc::Error::BindError)
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'raises an exception when result is not ACCEPTANCE' do
|
67
|
+
bind_ack_packet.p_result_list.p_results[0].result = RubySMB::Dcerpc::BindAck::USER_REJECTION
|
68
|
+
expect { pipe.bind(options) }.to raise_error(RubySMB::Dcerpc::Error::BindError)
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'sets the Tree #client.max_buffer_size property to the DCERPC response #max_xmit_frag property value' do
|
72
|
+
bind_ack_packet.max_xmit_frag = 64
|
73
|
+
pipe.bind(options)
|
74
|
+
expect(client).to have_received(:max_buffer_size=).with(64)
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'returns the expected BindAck packet' do
|
78
|
+
expect(pipe.bind(options)).to eq(bind_ack_packet)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -51,9 +51,9 @@ RSpec.describe RubySMB::Dispatcher::Socket do
|
|
51
51
|
let(:session_header) { RubySMB::Nbss::SessionHeader.new }
|
52
52
|
|
53
53
|
context 'when reading from the socket results in a nil value' do
|
54
|
-
it 'should raise Error::
|
54
|
+
it 'should raise Error::CommunicationError' do
|
55
55
|
smb_socket.tcp_socket = blank_socket
|
56
|
-
expect { smb_socket.recv_packet }.to raise_error(::RubySMB::Error::
|
56
|
+
expect { smb_socket.recv_packet }.to raise_error(::RubySMB::Error::CommunicationError)
|
57
57
|
end
|
58
58
|
end
|
59
59
|
|
@@ -102,26 +102,26 @@ RSpec.describe RubySMB::Dispatcher::Socket do
|
|
102
102
|
end
|
103
103
|
|
104
104
|
it 'reads the number of bytes specified in the nbss header' do
|
105
|
-
|
106
|
-
session_header.
|
105
|
+
stream_protocol_length = 10
|
106
|
+
session_header.stream_protocol_length = stream_protocol_length
|
107
107
|
allow(RubySMB::Nbss::SessionHeader).to receive(:read).and_return(session_header)
|
108
108
|
expect(response_socket).to receive(:read).with(4).and_return(session_header)
|
109
|
-
expect(response_socket).to receive(:read).with(
|
109
|
+
expect(response_socket).to receive(:read).with(stream_protocol_length).and_return('A' * stream_protocol_length)
|
110
110
|
smb_socket.recv_packet
|
111
111
|
end
|
112
112
|
|
113
113
|
context 'when the socket does not return everything the first time' do
|
114
114
|
it 'calls #read several times until everything is returned' do
|
115
|
-
|
115
|
+
stream_protocol_length = 67
|
116
116
|
returned_length = 10
|
117
|
-
session_header.
|
117
|
+
session_header.stream_protocol_length = stream_protocol_length
|
118
118
|
allow(RubySMB::Nbss::SessionHeader).to receive(:read).and_return(session_header)
|
119
119
|
|
120
120
|
expect(response_socket).to receive(:read).with(4).and_return(session_header)
|
121
121
|
loop do
|
122
|
-
expect(response_socket).to receive(:read).with(
|
123
|
-
|
124
|
-
break if
|
122
|
+
expect(response_socket).to receive(:read).with(stream_protocol_length).and_return('A' * returned_length).once
|
123
|
+
stream_protocol_length -= returned_length
|
124
|
+
break if stream_protocol_length <= 0
|
125
125
|
end
|
126
126
|
smb_socket.recv_packet
|
127
127
|
end
|
@@ -134,7 +134,7 @@ RSpec.describe RubySMB::Dispatcher::Socket do
|
|
134
134
|
|
135
135
|
context 'when the SMB packet is empty' do
|
136
136
|
it 'returns the nbss header only' do
|
137
|
-
session_header.
|
137
|
+
session_header.stream_protocol_length = 0
|
138
138
|
allow(RubySMB::Nbss::SessionHeader).to receive(:read).and_return(session_header)
|
139
139
|
expect(smb_socket.recv_packet(full_response: true)).to eq(session_header.to_binary_s)
|
140
140
|
end
|
@@ -148,7 +148,7 @@ RSpec.describe RubySMB::Dispatcher::Socket do
|
|
148
148
|
|
149
149
|
context 'when the SMB packet is empty' do
|
150
150
|
it 'returns an empty string' do
|
151
|
-
session_header.
|
151
|
+
session_header.stream_protocol_length = 0
|
152
152
|
allow(RubySMB::Nbss::SessionHeader).to receive(:read).and_return(session_header)
|
153
153
|
expect(smb_socket.recv_packet(full_response: false)).to eq('')
|
154
154
|
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe RubySMB::Error::InvalidPacket do
|
4
|
+
context 'with a String' do
|
5
|
+
it 'outputs the expected error message' do
|
6
|
+
ex = described_class.new('My exception')
|
7
|
+
expect(ex.to_s).to eq('My exception')
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
context 'with a Hash' do
|
12
|
+
it 'outputs the expected error message' do
|
13
|
+
ex = described_class.new(
|
14
|
+
expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
|
15
|
+
expected_cmd: RubySMB::SMB1::Packet::NegotiateResponseExtended::COMMAND,
|
16
|
+
expected_custom: "extended_security=1",
|
17
|
+
received_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
|
18
|
+
received_cmd: RubySMB::SMB2::Packet::NegotiateResponse::COMMAND,
|
19
|
+
received_custom: "extended_security=0"
|
20
|
+
)
|
21
|
+
expect(ex.to_s).to eq('Expecting SMB1 protocol with command=114 (extended_security=1), got SMB2 protocol with command=0 (extended_security=0)')
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'with an unsupported type' do
|
26
|
+
it 'raises the expected exception' do
|
27
|
+
expect { described_class.new(['wrong']) }.to raise_error(
|
28
|
+
ArgumentError,
|
29
|
+
'InvalidPacket expects a String or a Hash, got a Array'
|
30
|
+
)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
RSpec.describe RubySMB::Error::UnexpectedStatusCode do
|
37
|
+
context 'with a WindowsError::ErrorCode' do
|
38
|
+
it 'outputs the expected error message' do
|
39
|
+
ex = described_class.new(WindowsError::NTStatus::STATUS_BUFFER_OVERFLOW)
|
40
|
+
expect(ex.to_s).to eq('The server responded with an unexpected status code: STATUS_BUFFER_OVERFLOW')
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'with an Integer' do
|
45
|
+
it 'outputs the expected error message' do
|
46
|
+
ex = described_class.new(0x80000005)
|
47
|
+
expect(ex.to_s).to eq('The server responded with an unexpected status code: STATUS_BUFFER_OVERFLOW')
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context 'with an unsupported type' do
|
52
|
+
it 'raises the expected exception' do
|
53
|
+
expect { described_class.new(['wrong']) }.to raise_error(
|
54
|
+
ArgumentError,
|
55
|
+
'Status code must be a WindowsError::ErrorCode or an Integer, got Array'
|
56
|
+
)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -44,5 +44,17 @@ RSpec.describe RubySMB::Field::Stringz16 do
|
|
44
44
|
io = StringIO.new("A\x00B\x00C\x00D\x00")
|
45
45
|
expect { stringz16.read(io) }.to raise_error(EOFError)
|
46
46
|
end
|
47
|
+
|
48
|
+
it 'trims the string to #max_length and makes sure it ends with a null terminator' do
|
49
|
+
io = StringIO.new("A\x00B\x00C\x00D\x00")
|
50
|
+
str = described_class.new(max_length: 6)
|
51
|
+
expect(str.read(io).to_binary_s).to eq("A\x00B\x00\x00\x00".b)
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'raises an exception when #max_length is not a multiple of two' do
|
55
|
+
io = StringIO.new("A\x00B\x00C\x00D\x00")
|
56
|
+
str = described_class.new(max_length: 5)
|
57
|
+
expect { str.read(io) }.to raise_error(ArgumentError)
|
58
|
+
end
|
47
59
|
end
|
48
60
|
end
|
@@ -2,8 +2,7 @@ RSpec.describe RubySMB::Nbss::SessionHeader do
|
|
2
2
|
subject(:session_header) { described_class.new }
|
3
3
|
|
4
4
|
it { is_expected.to respond_to :session_packet_type }
|
5
|
-
it { is_expected.to respond_to :
|
6
|
-
it { is_expected.to respond_to :packet_length }
|
5
|
+
it { is_expected.to respond_to :stream_protocol_length }
|
7
6
|
|
8
7
|
it 'is big endian' do
|
9
8
|
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :big
|
@@ -15,15 +14,9 @@ RSpec.describe RubySMB::Nbss::SessionHeader do
|
|
15
14
|
end
|
16
15
|
end
|
17
16
|
|
18
|
-
describe '#
|
19
|
-
it 'is a
|
20
|
-
expect(session_header.
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
describe '#packet_length' do
|
25
|
-
it 'is a 17-bit Unsigned Integer' do
|
26
|
-
expect(session_header.packet_length).to be_a BinData::Bit17
|
17
|
+
describe '#stream_protocol_length' do
|
18
|
+
it 'is a 24-bit Unsigned Integer' do
|
19
|
+
expect(session_header.stream_protocol_length).to be_a BinData::Uint24be
|
27
20
|
end
|
28
21
|
end
|
29
22
|
end
|
@@ -110,10 +110,18 @@ RSpec.describe RubySMB::SMB1::File do
|
|
110
110
|
file.read_packet
|
111
111
|
end
|
112
112
|
|
113
|
-
it 'sets the
|
113
|
+
it 'sets the #max_count_of_bytes_to_return of the packet' do
|
114
114
|
expect(file.read_packet(read_length: 55).parameter_block.max_count_of_bytes_to_return).to eq 55
|
115
115
|
end
|
116
116
|
|
117
|
+
it 'sets the #min_count_of_bytes_to_return of the packet' do
|
118
|
+
expect(file.read_packet(read_length: 55).parameter_block.min_count_of_bytes_to_return).to eq 55
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'sets the #remaining of the packet' do
|
122
|
+
expect(file.read_packet(read_length: 55).parameter_block.remaining).to eq 55
|
123
|
+
end
|
124
|
+
|
117
125
|
it 'sets the offset of the packet' do
|
118
126
|
expect(file.read_packet(offset: 55).parameter_block.offset).to eq 55
|
119
127
|
end
|
@@ -10,8 +10,8 @@ RSpec.describe RubySMB::SMB1::Packet::SessionSetupLegacyRequest do
|
|
10
10
|
expect(header).to be_a RubySMB::SMB1::SMBHeader
|
11
11
|
end
|
12
12
|
|
13
|
-
it 'should have the command set to
|
14
|
-
expect(header.command).to eq RubySMB::SMB1::Commands::
|
13
|
+
it 'should have the command set to SMB_COM_SESSION_SETUP_ANDX' do
|
14
|
+
expect(header.command).to eq RubySMB::SMB1::Commands::SMB_COM_SESSION_SETUP_ANDX
|
15
15
|
end
|
16
16
|
|
17
17
|
it 'should not have the response flag set' do
|
@@ -10,8 +10,8 @@ RSpec.describe RubySMB::SMB1::Packet::SessionSetupLegacyResponse do
|
|
10
10
|
expect(header).to be_a RubySMB::SMB1::SMBHeader
|
11
11
|
end
|
12
12
|
|
13
|
-
it 'should have the command set to
|
14
|
-
expect(header.command).to eq RubySMB::SMB1::Commands::
|
13
|
+
it 'should have the command set to SMB_COM_SESSION_SETUP_ANDX' do
|
14
|
+
expect(header.command).to eq RubySMB::SMB1::Commands::SMB_COM_SESSION_SETUP_ANDX
|
15
15
|
end
|
16
16
|
|
17
17
|
it 'should have the response flag set' do
|
@@ -10,8 +10,8 @@ RSpec.describe RubySMB::SMB1::Packet::SessionSetupRequest do
|
|
10
10
|
expect(header).to be_a RubySMB::SMB1::SMBHeader
|
11
11
|
end
|
12
12
|
|
13
|
-
it 'should have the command set to
|
14
|
-
expect(header.command).to eq RubySMB::SMB1::Commands::
|
13
|
+
it 'should have the command set to SMB_COM_SESSION_SETUP_ANDX' do
|
14
|
+
expect(header.command).to eq RubySMB::SMB1::Commands::SMB_COM_SESSION_SETUP_ANDX
|
15
15
|
end
|
16
16
|
|
17
17
|
it 'should not have the response flag set' do
|
@@ -11,7 +11,7 @@ RSpec.describe RubySMB::SMB1::Packet::SessionSetupResponse do
|
|
11
11
|
end
|
12
12
|
|
13
13
|
it 'should have the command set to SMB_COM_NEGOTIATE' do
|
14
|
-
expect(header.command).to eq RubySMB::SMB1::Commands::
|
14
|
+
expect(header.command).to eq RubySMB::SMB1::Commands::SMB_COM_SESSION_SETUP_ANDX
|
15
15
|
end
|
16
16
|
|
17
17
|
it 'should have the response flag set' do
|
@@ -1,15 +1,12 @@
|
|
1
1
|
RSpec.describe RubySMB::SMB1::Pipe do
|
2
2
|
|
3
|
+
it { expect(described_class).to be < RubySMB::SMB1::File }
|
4
|
+
|
3
5
|
let(:peek_nmpipe_response) {
|
4
6
|
packet = RubySMB::SMB1::Packet::Trans::PeekNmpipeResponse.new
|
5
7
|
packet.data_block.trans_parameters.read("\x10\x20\x00\x00\x03\x00")
|
6
8
|
packet
|
7
9
|
}
|
8
|
-
|
9
|
-
describe RubySMB::SMB1::Pipe do
|
10
|
-
it { expect(described_class).to be < RubySMB::SMB1::File }
|
11
|
-
end
|
12
|
-
|
13
10
|
let(:dispatcher) { RubySMB::Dispatcher::Socket.new(double('socket')) }
|
14
11
|
let(:client) { RubySMB::Client.new(dispatcher, username: 'msfadmin', password: 'msfadmin') }
|
15
12
|
let(:connect_response) {
|
@@ -124,201 +121,273 @@ RSpec.describe RubySMB::SMB1::Pipe do
|
|
124
121
|
end
|
125
122
|
end
|
126
123
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
allow(pipe).to receive(:bind)
|
134
|
-
allow(pipe).to receive(:request).and_return(dcerpc_response)
|
135
|
-
allow(RubySMB::Dcerpc::Srvsvc::NetShareEnumAll).to receive(:parse_response).and_return([])
|
124
|
+
describe '#initialize' do
|
125
|
+
context 'when name is not provided' do
|
126
|
+
it 'raises an ArgumentError' do
|
127
|
+
expect {
|
128
|
+
described_class.new(tree: tree, response: nt_create_andx_response, name: nil)
|
129
|
+
}.to raise_error(ArgumentError)
|
136
130
|
end
|
131
|
+
end
|
137
132
|
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
133
|
+
it 'calls the superclass with the expected arguments' do
|
134
|
+
expect(pipe.tree).to eq(tree)
|
135
|
+
expect(pipe.name).to eq(filename)
|
136
|
+
expect(pipe.attributes).to eq(nt_create_andx_response.parameter_block.ext_file_attributes)
|
137
|
+
expect(pipe.fid).to eq(nt_create_andx_response.parameter_block.fid)
|
138
|
+
expect(pipe.last_access).to eq(nt_create_andx_response.parameter_block.last_access_time.to_datetime)
|
139
|
+
expect(pipe.last_change).to eq(nt_create_andx_response.parameter_block.last_change_time.to_datetime)
|
140
|
+
expect(pipe.last_write).to eq(nt_create_andx_response.parameter_block.last_write_time.to_datetime)
|
141
|
+
expect(pipe.size).to eq(nt_create_andx_response.parameter_block.end_of_file)
|
142
|
+
expect(pipe.size_on_disk).to eq(nt_create_andx_response.parameter_block.allocation_size)
|
143
|
+
end
|
142
144
|
|
143
|
-
|
144
|
-
|
145
|
-
pipe.
|
145
|
+
context 'with \'srvsvc\' filename' do
|
146
|
+
it 'extends Srvsvc class' do
|
147
|
+
pipe = described_class.new(tree: tree, response: nt_create_andx_response, name: 'srvsvc')
|
148
|
+
expect(pipe.respond_to?(:net_share_enum_all)).to be true
|
146
149
|
end
|
150
|
+
end
|
147
151
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
expect(RubySMB::Dcerpc::Srvsvc::NetShareEnumAll).to receive(:parse_response).with(stub)
|
153
|
-
pipe.net_share_enum_all(host)
|
152
|
+
context 'with \'winreg\' filename' do
|
153
|
+
it 'extends Winreg class' do
|
154
|
+
pipe = described_class.new(tree: tree, response: nt_create_andx_response, name: 'winreg')
|
155
|
+
expect(pipe.respond_to?(:has_registry_key?)).to be true
|
154
156
|
end
|
157
|
+
end
|
155
158
|
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
["IPC$", "IPC", "Remote IPC"],
|
161
|
-
["ADMIN$", "DISK", "Remote Admin"]
|
162
|
-
]
|
163
|
-
output = [
|
164
|
-
{:name=>"C$", :type=>"DISK", :comment=>"Default share"},
|
165
|
-
{:name=>"Shared", :type=>"DISK", :comment=>""},
|
166
|
-
{:name=>"IPC$", :type=>"IPC", :comment=>"Remote IPC"},
|
167
|
-
{:name=>"ADMIN$", :type=>"DISK", :comment=>"Remote Admin"},
|
168
|
-
]
|
169
|
-
allow(RubySMB::Dcerpc::Srvsvc::NetShareEnumAll).to receive(:parse_response).and_return(shares)
|
170
|
-
expect(pipe.net_share_enum_all(host)).to eq(output)
|
159
|
+
context 'with \'svcctl\' filename' do
|
160
|
+
it 'extends svcctl class' do
|
161
|
+
pipe = described_class.new(tree: tree, response: nt_create_andx_response, name: 'svcctl')
|
162
|
+
expect(pipe.respond_to?(:query_service_config)).to be true
|
171
163
|
end
|
172
164
|
end
|
165
|
+
end
|
173
166
|
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
167
|
+
describe '#dcerpc_request' do
|
168
|
+
let(:options) { { host: '1.2.3.4' } }
|
169
|
+
let(:stub_packet ) { RubySMB::Dcerpc::Winreg::OpenKeyRequest.new }
|
170
|
+
let(:dcerpc_request) { double('DCERPC Request') }
|
171
|
+
let(:request_stub) { double('Request stub') }
|
172
|
+
let(:binary_dcerpc_request) { double('Binary DCERPC Request') }
|
173
|
+
let(:trans_nmpipe_request) { double('TransactNmpipeRequest') }
|
174
|
+
let(:trans_data) { double('Trans data') }
|
175
|
+
let(:trans_nmpipe_raw_response) { double('Trans nmpipe raw response') }
|
176
|
+
let(:trans_nmpipe_response) { double('TransactNmpipeResponse') }
|
177
|
+
let(:raw_data) { double('Raw data') }
|
178
|
+
let(:dcerpc_response) { double('DCERPC Response') }
|
179
|
+
let(:result) { 'Result' }
|
178
180
|
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
181
|
+
before :example do
|
182
|
+
allow(RubySMB::Dcerpc::Request).to receive(:new).and_return(dcerpc_request)
|
183
|
+
allow(dcerpc_request).to receive_messages(
|
184
|
+
:stub => request_stub,
|
185
|
+
:to_binary_s => binary_dcerpc_request
|
186
|
+
)
|
187
|
+
allow(request_stub).to receive(:read)
|
188
|
+
allow(RubySMB::SMB1::Packet::Trans::TransactNmpipeRequest).to receive(:new).and_return(trans_nmpipe_request)
|
189
|
+
allow(tree).to receive(:set_header_fields)
|
190
|
+
allow(trans_nmpipe_request).to receive_message_chain(:data_block, :trans_data => trans_data)
|
191
|
+
allow(trans_nmpipe_request).to receive(:set_fid)
|
192
|
+
allow(trans_data).to receive(:write_data=)
|
193
|
+
allow(client).to receive(:send_recv).and_return(trans_nmpipe_raw_response)
|
194
|
+
allow(RubySMB::SMB1::Packet::Trans::TransactNmpipeResponse).to receive(:read).and_return(trans_nmpipe_response)
|
195
|
+
allow(trans_nmpipe_response).to receive_messages(
|
196
|
+
:valid? => true,
|
197
|
+
:status_code => WindowsError::NTStatus::STATUS_SUCCESS
|
198
|
+
)
|
199
|
+
allow(trans_nmpipe_response).to receive_message_chain(:data_block, :trans_data, :read_data, :to_binary_s => raw_data)
|
200
|
+
allow(RubySMB::Dcerpc::Response).to receive(:read).and_return(dcerpc_response)
|
201
|
+
allow(dcerpc_response).to receive_message_chain(:pdu_header, :ptype => RubySMB::Dcerpc::PTypes::RESPONSE)
|
202
|
+
allow(dcerpc_response).to receive(:stub).and_return(result)
|
203
|
+
end
|
187
204
|
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
205
|
+
it 'creates a Request packet with the expected arguments' do
|
206
|
+
pipe.dcerpc_request(stub_packet, options)
|
207
|
+
expect(options).to eq( { host: '1.2.3.4', endpoint: 'Winreg' })
|
208
|
+
expect(RubySMB::Dcerpc::Request).to have_received(:new).with({ opnum: stub_packet.opnum }, options)
|
209
|
+
end
|
192
210
|
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
211
|
+
it 'sets DCERPC request stub to the stub packet passed as argument' do
|
212
|
+
pipe.dcerpc_request(stub_packet, options)
|
213
|
+
expect(request_stub).to have_received(:read).with(stub_packet.to_binary_s)
|
214
|
+
end
|
215
|
+
|
216
|
+
it 'creates a Trans TransactNmpipeRequest packet' do
|
217
|
+
pipe.dcerpc_request(stub_packet, options)
|
218
|
+
expect(RubySMB::SMB1::Packet::Trans::TransactNmpipeRequest).to have_received(:new).with(options)
|
219
|
+
end
|
220
|
+
|
221
|
+
it 'calls Tree #set_header_fields' do
|
222
|
+
pipe.dcerpc_request(stub_packet, options)
|
223
|
+
expect(tree).to have_received(:set_header_fields).with(trans_nmpipe_request)
|
224
|
+
end
|
225
|
+
|
226
|
+
it 'calls TransactNmpipeRequest #set_fid' do
|
227
|
+
pipe.dcerpc_request(stub_packet, options)
|
228
|
+
expect(trans_nmpipe_request).to have_received(:set_fid).with(pipe.fid)
|
229
|
+
end
|
230
|
+
|
231
|
+
it 'sets the expected #write_data request property' do
|
232
|
+
pipe.dcerpc_request(stub_packet, options)
|
233
|
+
expect(trans_data).to have_received(:write_data=).with(binary_dcerpc_request)
|
234
|
+
end
|
197
235
|
|
198
|
-
|
199
|
-
|
200
|
-
|
236
|
+
it 'sends the expected request' do
|
237
|
+
pipe.dcerpc_request(stub_packet, options)
|
238
|
+
expect(client).to have_received(:send_recv).with(trans_nmpipe_request)
|
239
|
+
end
|
240
|
+
|
241
|
+
it 'creates a Trans TransactNmpipeResponse packet from the response' do
|
242
|
+
pipe.dcerpc_request(stub_packet, options)
|
243
|
+
expect(RubySMB::SMB1::Packet::Trans::TransactNmpipeResponse).to have_received(:read).with(trans_nmpipe_raw_response)
|
244
|
+
end
|
245
|
+
|
246
|
+
context 'when the response is not a Trans packet' do
|
247
|
+
it 'raises an InvalidPacket exception' do
|
248
|
+
allow(trans_nmpipe_response).to receive_message_chain(:smb_header, :protocol)
|
249
|
+
allow(trans_nmpipe_response).to receive_message_chain(:smb_header, :command)
|
250
|
+
allow(trans_nmpipe_response).to receive(:valid?).and_return(false)
|
251
|
+
expect { pipe.dcerpc_request(stub_packet, options) }.to raise_error(RubySMB::Error::InvalidPacket)
|
201
252
|
end
|
253
|
+
end
|
202
254
|
|
203
|
-
|
204
|
-
|
205
|
-
allow(
|
206
|
-
expect(
|
207
|
-
pipe.bind(options)
|
255
|
+
context 'when the response status code is not STATUS_SUCCESS or STATUS_BUFFER_OVERFLOW' do
|
256
|
+
it 'raises an UnexpectedStatusCode exception' do
|
257
|
+
allow(trans_nmpipe_response).to receive(:status_code).and_return(WindowsError::NTStatus::STATUS_INVALID_HANDLE)
|
258
|
+
expect { pipe.dcerpc_request(stub_packet, options) }.to raise_error(RubySMB::Error::UnexpectedStatusCode)
|
208
259
|
end
|
260
|
+
end
|
209
261
|
|
210
|
-
|
211
|
-
|
212
|
-
expect { pipe.
|
262
|
+
context 'when the response status code is STATUS_SUCCESS' do
|
263
|
+
it 'does not raise any exception' do
|
264
|
+
expect { pipe.dcerpc_request(stub_packet, options) }.not_to raise_error
|
213
265
|
end
|
214
266
|
|
215
|
-
it '
|
216
|
-
|
217
|
-
|
218
|
-
expect { pipe.bind(options) }.to raise_error(RubySMB::Dcerpc::Error::BindError)
|
267
|
+
it 'creates a DCERPC Response packet from the response' do
|
268
|
+
pipe.dcerpc_request(stub_packet, options)
|
269
|
+
expect(RubySMB::Dcerpc::Response).to have_received(:read).with(raw_data)
|
219
270
|
end
|
220
271
|
|
221
|
-
|
222
|
-
|
223
|
-
|
272
|
+
context 'when an IOError occurs while parsing the DCERPC response' do
|
273
|
+
it 'raises an InvalidPacket exception' do
|
274
|
+
allow(RubySMB::Dcerpc::Response).to receive(:read).and_raise(IOError)
|
275
|
+
expect { pipe.dcerpc_request(stub_packet, options) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
|
276
|
+
end
|
224
277
|
end
|
225
278
|
|
226
|
-
|
227
|
-
|
228
|
-
|
279
|
+
context 'when the response is not a DCERPC Response packet' do
|
280
|
+
it 'raises an InvalidPacket exception' do
|
281
|
+
allow(dcerpc_response).to receive_message_chain(:pdu_header, :ptype => RubySMB::Dcerpc::PTypes::FAULT)
|
282
|
+
expect { pipe.dcerpc_request(stub_packet, options) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
|
283
|
+
end
|
229
284
|
end
|
230
285
|
|
231
|
-
it 'returns the expected
|
232
|
-
expect(pipe.
|
286
|
+
it 'returns the expected stub data' do
|
287
|
+
expect(pipe.dcerpc_request(stub_packet, options)).to eq(result)
|
233
288
|
end
|
234
289
|
end
|
235
290
|
|
236
|
-
|
237
|
-
let(:
|
238
|
-
let(:
|
239
|
-
let(:req_packet) { RubySMB::Dcerpc::Request.new({ :opnum => opnum }, options) }
|
240
|
-
let(:nmpipe_packet) { RubySMB::SMB1::Packet::Trans::TransactNmpipeRequest.new(options) }
|
241
|
-
let(:nmpipe_response) { RubySMB::SMB1::Packet::Trans::TransactNmpipeResponse.new }
|
242
|
-
let(:res_packet) { RubySMB::Dcerpc::Response.new }
|
243
|
-
|
291
|
+
context 'when the response status code is STATUS_BUFFER_OVERFLOW' do
|
292
|
+
let(:data_count) { 100 }
|
293
|
+
let(:added_raw_data) { double('Added raw data') }
|
244
294
|
before :example do
|
245
|
-
allow(
|
246
|
-
allow(
|
247
|
-
allow(
|
248
|
-
allow(
|
249
|
-
allow(
|
295
|
+
allow(trans_nmpipe_response).to receive(:status_code).and_return(WindowsError::NTStatus::STATUS_BUFFER_OVERFLOW)
|
296
|
+
allow(trans_nmpipe_response).to receive_message_chain(:parameter_block, :data_count => data_count)
|
297
|
+
allow(pipe).to receive(:read).and_return(added_raw_data)
|
298
|
+
allow(raw_data).to receive(:<<)
|
299
|
+
allow(dcerpc_response).to receive_message_chain(:pdu_header, :pfc_flags, :first_frag => 1)
|
300
|
+
allow(dcerpc_response).to receive_message_chain(:pdu_header, :pfc_flags, :last_frag => 1)
|
250
301
|
end
|
251
302
|
|
252
|
-
it '
|
253
|
-
expect(
|
254
|
-
pipe.request(opnum, options)
|
303
|
+
it 'does not raise any exception' do
|
304
|
+
expect { pipe.dcerpc_request(stub_packet, options) }.not_to raise_error
|
255
305
|
end
|
256
306
|
|
257
|
-
it '
|
258
|
-
|
259
|
-
pipe.
|
307
|
+
it 'reads the expected number of bytes and concatenate it the first response raw data' do
|
308
|
+
pipe.dcerpc_request(stub_packet, options)
|
309
|
+
expect(pipe).to have_received(:read).with(bytes: tree.client.max_buffer_size - data_count)
|
310
|
+
expect(raw_data).to have_received(:<<).with(added_raw_data)
|
260
311
|
end
|
261
312
|
|
262
|
-
it '
|
263
|
-
|
264
|
-
|
313
|
+
it 'creates a DCERPC Response packet from the updated raw data' do
|
314
|
+
pipe.dcerpc_request(stub_packet, options)
|
315
|
+
expect(RubySMB::Dcerpc::Response).to have_received(:read).with(raw_data)
|
265
316
|
end
|
266
317
|
|
267
|
-
|
268
|
-
|
269
|
-
|
318
|
+
context 'when an IOError occurs while parsing the DCERPC response' do
|
319
|
+
it 'raises an InvalidPacket exception' do
|
320
|
+
allow(RubySMB::Dcerpc::Response).to receive(:read).and_raise(IOError)
|
321
|
+
expect { pipe.dcerpc_request(stub_packet, options) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
|
322
|
+
end
|
270
323
|
end
|
271
324
|
|
272
|
-
|
273
|
-
|
274
|
-
|
325
|
+
context 'when the response is not a DCERPC Response packet' do
|
326
|
+
it 'raises an InvalidPacket exception' do
|
327
|
+
allow(dcerpc_response).to receive_message_chain(:pdu_header, :ptype => RubySMB::Dcerpc::PTypes::FAULT)
|
328
|
+
expect { pipe.dcerpc_request(stub_packet, options) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
|
275
329
|
end
|
276
|
-
pipe.request(opnum, options)
|
277
330
|
end
|
278
331
|
|
279
|
-
|
280
|
-
|
281
|
-
|
332
|
+
context 'when the response is not the first fragment' do
|
333
|
+
it 'raises an InvalidPacket exception' do
|
334
|
+
allow(dcerpc_response).to receive_message_chain(:pdu_header, :pfc_flags, :first_frag => 0)
|
335
|
+
expect { pipe.dcerpc_request(stub_packet, options) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
|
336
|
+
end
|
282
337
|
end
|
283
338
|
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
end
|
339
|
+
context 'when the response is the last fragment' do
|
340
|
+
it 'only reads the pipe once' do
|
341
|
+
pipe.dcerpc_request(stub_packet, options)
|
342
|
+
expect(RubySMB::Dcerpc::Response).to have_received(:read).once
|
343
|
+
end
|
290
344
|
|
291
|
-
|
292
|
-
|
293
|
-
|
345
|
+
it 'returns the expected stub data' do
|
346
|
+
expect(pipe.dcerpc_request(stub_packet, options)).to eq(result)
|
347
|
+
end
|
294
348
|
end
|
295
349
|
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
350
|
+
context 'when the response is not the last fragment' do
|
351
|
+
let(:raw_data2) { double('Raw data #2') }
|
352
|
+
let(:dcerpc_response2) { double('DCERPC Response #2') }
|
353
|
+
let(:result2) { 'Result #2' }
|
354
|
+
before :example do
|
355
|
+
allow(dcerpc_response).to receive_message_chain(:pdu_header, :pfc_flags, :last_frag => 0)
|
356
|
+
allow(pipe).to receive(:read).with(bytes: tree.client.max_buffer_size).and_return(raw_data2)
|
357
|
+
allow(RubySMB::Dcerpc::Response).to receive(:read).with(raw_data2).and_return(dcerpc_response2)
|
358
|
+
allow(dcerpc_response2).to receive_message_chain(:pdu_header, :ptype => RubySMB::Dcerpc::PTypes::RESPONSE)
|
359
|
+
allow(dcerpc_response2).to receive_message_chain(:pdu_header, :pfc_flags, :last_frag => 1)
|
360
|
+
allow(dcerpc_response2).to receive(:stub).and_return(result2)
|
361
|
+
end
|
300
362
|
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
end
|
363
|
+
it 'reads the expected number of bytes' do
|
364
|
+
pipe.dcerpc_request(stub_packet, options)
|
365
|
+
expect(pipe).to have_received(:read).with(bytes: tree.client.max_buffer_size)
|
366
|
+
end
|
306
367
|
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
368
|
+
it 'creates a DCERPC Response packet from the new raw data' do
|
369
|
+
pipe.dcerpc_request(stub_packet, options)
|
370
|
+
expect(RubySMB::Dcerpc::Response).to have_received(:read).with(raw_data2)
|
371
|
+
end
|
311
372
|
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
373
|
+
context 'when an IOError occurs while parsing the new DCERPC response' do
|
374
|
+
it 'raises an InvalidPacket exception' do
|
375
|
+
allow(RubySMB::Dcerpc::Response).to receive(:read).with(raw_data2).and_raise(IOError)
|
376
|
+
expect { pipe.dcerpc_request(stub_packet, options) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
|
377
|
+
end
|
378
|
+
end
|
317
379
|
|
318
|
-
|
319
|
-
|
380
|
+
context 'when the new response is not a DCERPC Response packet' do
|
381
|
+
it 'raises an InvalidPacket exception' do
|
382
|
+
allow(dcerpc_response2).to receive_message_chain(:pdu_header, :ptype => RubySMB::Dcerpc::PTypes::FAULT)
|
383
|
+
expect { pipe.dcerpc_request(stub_packet, options) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
|
384
|
+
end
|
385
|
+
end
|
386
|
+
|
387
|
+
it 'returns the expected stub data' do
|
388
|
+
expect(pipe.dcerpc_request(stub_packet, options)).to eq(result)
|
389
|
+
end
|
320
390
|
end
|
321
391
|
end
|
322
392
|
end
|
323
|
-
|
324
393
|
end
|