ruby_smb 2.0.1 → 2.0.6
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 +2 -1
- 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 +5 -4
- data/examples/enum_registry_values.rb +5 -4
- data/examples/list_directory.rb +8 -6
- data/examples/negotiate_with_netbios_service.rb +9 -5
- data/examples/net_share_enum_all.rb +6 -4
- data/examples/pipes.rb +11 -12
- data/examples/query_service_status.rb +64 -0
- data/examples/read_file.rb +8 -6
- data/examples/read_registry_key_value.rb +6 -5
- 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/client.rb +81 -48
- data/lib/ruby_smb/client/authentication.rb +5 -10
- data/lib/ruby_smb/client/echo.rb +2 -4
- data/lib/ruby_smb/client/negotiation.rb +21 -14
- data/lib/ruby_smb/client/tree_connect.rb +2 -4
- data/lib/ruby_smb/client/utils.rb +16 -10
- data/lib/ruby_smb/client/winreg.rb +1 -1
- data/lib/ruby_smb/dcerpc.rb +4 -0
- data/lib/ruby_smb/dcerpc/error.rb +3 -0
- data/lib/ruby_smb/dcerpc/ndr.rb +306 -44
- data/lib/ruby_smb/dcerpc/netlogon.rb +101 -0
- data/lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_request.rb +28 -0
- data/lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_response.rb +26 -0
- data/lib/ruby_smb/dcerpc/netlogon/netr_server_password_set2_request.rb +27 -0
- data/lib/ruby_smb/dcerpc/netlogon/netr_server_password_set2_response.rb +23 -0
- data/lib/ruby_smb/dcerpc/netlogon/netr_server_req_challenge_request.rb +25 -0
- data/lib/ruby_smb/dcerpc/netlogon/netr_server_req_challenge_response.rb +24 -0
- data/lib/ruby_smb/dcerpc/request.rb +19 -0
- data/lib/ruby_smb/dcerpc/rpc_security_attributes.rb +34 -0
- data/lib/ruby_smb/dcerpc/rrp_unicode_string.rb +9 -6
- 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 +98 -17
- 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 +1 -1
- data/lib/ruby_smb/dcerpc/winreg/enum_value_request.rb +1 -1
- data/lib/ruby_smb/dcerpc/winreg/enum_value_response.rb +1 -1
- data/lib/ruby_smb/dcerpc/winreg/open_root_key_request.rb +4 -4
- data/lib/ruby_smb/dcerpc/winreg/query_info_key_request.rb +1 -1
- data/lib/ruby_smb/dcerpc/winreg/query_value_request.rb +7 -6
- data/lib/ruby_smb/dcerpc/winreg/query_value_response.rb +10 -10
- 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 +1 -1
- data/lib/ruby_smb/error.rb +21 -5
- data/lib/ruby_smb/field/stringz16.rb +17 -1
- data/lib/ruby_smb/generic_packet.rb +11 -1
- data/lib/ruby_smb/nbss/session_header.rb +4 -4
- data/lib/ruby_smb/smb1/file.rb +10 -25
- data/lib/ruby_smb/smb1/packet/trans2/find_first2_response.rb +0 -1
- data/lib/ruby_smb/smb1/packet/trans2/find_next2_response.rb +0 -1
- data/lib/ruby_smb/smb1/packet/trans2/open2_response.rb +1 -2
- data/lib/ruby_smb/smb1/packet/trans2/set_file_information_response.rb +1 -13
- data/lib/ruby_smb/smb1/pipe.rb +8 -6
- data/lib/ruby_smb/smb1/tree.rb +13 -9
- data/lib/ruby_smb/smb2/file.rb +33 -33
- data/lib/ruby_smb/smb2/pipe.rb +9 -6
- data/lib/ruby_smb/smb2/tree.rb +21 -11
- data/lib/ruby_smb/version.rb +1 -1
- data/spec/lib/ruby_smb/client_spec.rb +195 -101
- data/spec/lib/ruby_smb/dcerpc/ndr_spec.rb +1396 -77
- data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_request_spec.rb +69 -0
- data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_response_spec.rb +53 -0
- data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_password_set2_request_spec.rb +69 -0
- data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_password_set2_response_spec.rb +37 -0
- data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_req_challenge_request_spec.rb +45 -0
- data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_req_challenge_response_spec.rb +37 -0
- data/spec/lib/ruby_smb/dcerpc/rpc_security_attributes_spec.rb +161 -0
- data/spec/lib/ruby_smb/dcerpc/rrp_unicode_string_spec.rb +49 -12
- 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/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 +0 -4
- data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_request_spec.rb +2 -2
- data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_response_spec.rb +2 -2
- data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_request_spec.rb +9 -4
- data/spec/lib/ruby_smb/dcerpc/winreg/query_info_key_request_spec.rb +0 -4
- data/spec/lib/ruby_smb/dcerpc/winreg/query_value_request_spec.rb +17 -17
- data/spec/lib/ruby_smb/dcerpc/winreg/query_value_response_spec.rb +11 -23
- 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 +227 -41
- data/spec/lib/ruby_smb/dispatcher/socket_spec.rb +10 -10
- data/spec/lib/ruby_smb/error_spec.rb +34 -5
- data/spec/lib/ruby_smb/field/stringz16_spec.rb +12 -0
- data/spec/lib/ruby_smb/generic_packet_spec.rb +7 -0
- data/spec/lib/ruby_smb/nbss/session_header_spec.rb +4 -11
- data/spec/lib/ruby_smb/smb1/file_spec.rb +2 -4
- data/spec/lib/ruby_smb/smb1/packet/trans2/find_first2_response_spec.rb +0 -1
- data/spec/lib/ruby_smb/smb1/packet/trans2/find_next2_response_spec.rb +0 -1
- data/spec/lib/ruby_smb/smb1/packet/trans2/open2_response_spec.rb +0 -5
- data/spec/lib/ruby_smb/smb1/packet/trans2/set_file_information_response_spec.rb +0 -6
- data/spec/lib/ruby_smb/smb1/pipe_spec.rb +30 -5
- data/spec/lib/ruby_smb/smb1/tree_spec.rb +22 -0
- data/spec/lib/ruby_smb/smb2/file_spec.rb +61 -9
- data/spec/lib/ruby_smb/smb2/pipe_spec.rb +9 -5
- data/spec/lib/ruby_smb/smb2/tree_spec.rb +58 -1
- metadata +91 -2
- metadata.gz.sig +0 -0
@@ -9,16 +9,45 @@ RSpec.describe RubySMB::Error::InvalidPacket do
|
|
9
9
|
end
|
10
10
|
|
11
11
|
context 'with a Hash' do
|
12
|
-
|
13
|
-
|
12
|
+
let(:ex) do
|
13
|
+
described_class.new(
|
14
14
|
expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
|
15
15
|
expected_cmd: RubySMB::SMB1::Packet::NegotiateResponseExtended::COMMAND,
|
16
16
|
expected_custom: "extended_security=1",
|
17
|
-
|
18
|
-
received_cmd: RubySMB::SMB2::Packet::NegotiateResponse::COMMAND,
|
17
|
+
packet: packet,
|
19
18
|
received_custom: "extended_security=0"
|
20
19
|
)
|
21
|
-
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'with an SMB2 packet' do
|
23
|
+
let(:packet) { RubySMB::SMB2::Packet::NegotiateResponse.new }
|
24
|
+
|
25
|
+
it 'outputs the expected error message' do
|
26
|
+
expect(ex.to_s).to eq('Expecting SMB1 protocol with command=114 (extended_security=1), got SMB2 protocol with command=0 (extended_security=0), Status: (0x00000000) STATUS_SUCCESS: The operation completed successfully.')
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'with an SMB1 packet' do
|
31
|
+
let(:packet) { RubySMB::SMB1::Packet::ReadAndxRequest.new }
|
32
|
+
|
33
|
+
it 'outputs the expected error message' do
|
34
|
+
expect(ex.to_s).to eq('Expecting SMB1 protocol with command=114 (extended_security=1), got SMB1 protocol with command=46 (extended_security=0), Status: (0x00000000) STATUS_SUCCESS: The operation completed successfully.')
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context 'without packet' do
|
39
|
+
let(:ex) do
|
40
|
+
described_class.new(
|
41
|
+
expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
|
42
|
+
expected_cmd: RubySMB::SMB1::Packet::NegotiateResponseExtended::COMMAND,
|
43
|
+
expected_custom: "extended_security=1",
|
44
|
+
received_custom: "extended_security=0"
|
45
|
+
)
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'outputs the expected error message' do
|
49
|
+
expect(ex.to_s).to eq('Expecting SMB1 protocol with command=114 (extended_security=1), got ??? protocol with command=??? (extended_security=0)')
|
50
|
+
end
|
22
51
|
end
|
23
52
|
end
|
24
53
|
|
@@ -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
|
@@ -88,6 +88,13 @@ RSpec.describe RubySMB::GenericPacket do
|
|
88
88
|
packet = RubySMB::SMB2::Packet::NegotiateResponse.read(smb2_error_packet.to_binary_s)
|
89
89
|
expect(packet.original_command).to eq RubySMB::SMB2::Packet::NegotiateResponse::COMMAND
|
90
90
|
end
|
91
|
+
|
92
|
+
context 'when the server returns an SMB1 error packet' do
|
93
|
+
let(:smb1_error_packet) { RubySMB::SMB1::Packet::EmptyPacket.new }
|
94
|
+
it 'returns the empty packet instead of the asked for class' do
|
95
|
+
expect(RubySMB::SMB2::Packet::NegotiateResponse.read(smb1_error_packet.to_binary_s)).to be_a RubySMB::SMB1::Packet::EmptyPacket
|
96
|
+
end
|
97
|
+
end
|
91
98
|
end
|
92
99
|
end
|
93
100
|
|
@@ -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
|
@@ -473,7 +473,7 @@ RSpec.describe RubySMB::SMB1::File do
|
|
473
473
|
end
|
474
474
|
|
475
475
|
it 'sets the File Information #rename_pending field of the packet' do
|
476
|
-
expect(file.rename_packet(filename).data_block.trans2_data.info_level_struct.file_name).to eq filename
|
476
|
+
expect(file.rename_packet(filename).data_block.trans2_data.info_level_struct.file_name).to eq filename
|
477
477
|
end
|
478
478
|
|
479
479
|
it 'sets the Trans2 ParameterBlock fields' do
|
@@ -521,9 +521,7 @@ RSpec.describe RubySMB::SMB1::File do
|
|
521
521
|
|
522
522
|
it 'raises an InvalidPacket exception if the response is not valid' do
|
523
523
|
allow(response).to receive(:valid?).and_return(false)
|
524
|
-
|
525
|
-
allow(response).to receive(:smb_header).and_return(smb_header)
|
526
|
-
allow(smb_header).to receive_messages(:protocol => nil, :command => nil)
|
524
|
+
allow(response).to receive(:packet_smb_version)
|
527
525
|
expect { file.close }.to raise_error(RubySMB::Error::InvalidPacket)
|
528
526
|
end
|
529
527
|
|
@@ -32,7 +32,6 @@ RSpec.describe RubySMB::SMB1::Packet::Trans2::FindFirst2Response do
|
|
32
32
|
describe '#data_block' do
|
33
33
|
subject(:data_block) { packet.data_block }
|
34
34
|
|
35
|
-
it { is_expected.to respond_to :name }
|
36
35
|
it { is_expected.to respond_to :trans2_parameters }
|
37
36
|
it { is_expected.to respond_to :trans2_data }
|
38
37
|
|
@@ -32,7 +32,6 @@ RSpec.describe RubySMB::SMB1::Packet::Trans2::FindNext2Response do
|
|
32
32
|
describe '#data_block' do
|
33
33
|
subject(:data_block) { packet.data_block }
|
34
34
|
|
35
|
-
it { is_expected.to respond_to :name }
|
36
35
|
it { is_expected.to respond_to :trans2_parameters }
|
37
36
|
it { is_expected.to respond_to :trans2_data }
|
38
37
|
|
@@ -35,16 +35,11 @@ RSpec.describe RubySMB::SMB1::Packet::Trans2::Open2Response do
|
|
35
35
|
end
|
36
36
|
|
37
37
|
it { is_expected.to respond_to :trans2_parameters }
|
38
|
-
it { is_expected.to respond_to :trans2_data }
|
39
38
|
|
40
39
|
it 'should keep #trans2_parameters 4-byte aligned' do
|
41
40
|
expect(data_block.trans2_parameters.abs_offset % 4).to eq 0
|
42
41
|
end
|
43
42
|
|
44
|
-
it 'should keep #trans2_data 4-byte aligned' do
|
45
|
-
expect(data_block.trans2_data.abs_offset % 4).to eq 0
|
46
|
-
end
|
47
|
-
|
48
43
|
describe '#trans2_parameters' do
|
49
44
|
subject(:parameters) { data_block.trans2_parameters }
|
50
45
|
|
@@ -28,18 +28,12 @@ RSpec.describe RubySMB::SMB1::Packet::Trans2::SetFileInformationResponse do
|
|
28
28
|
describe '#data_block' do
|
29
29
|
subject(:data_block) { packet.data_block }
|
30
30
|
|
31
|
-
it { is_expected.to respond_to :name }
|
32
31
|
it { is_expected.to respond_to :trans2_parameters }
|
33
|
-
it { is_expected.to respond_to :trans2_data }
|
34
32
|
|
35
33
|
it 'should keep #trans2_parameters 4-byte aligned' do
|
36
34
|
expect(data_block.trans2_parameters.abs_offset % 4).to eq 0
|
37
35
|
end
|
38
36
|
|
39
|
-
it 'should keep #trans2_data 4-byte aligned' do
|
40
|
-
expect(data_block.trans2_data.abs_offset % 4).to eq 0
|
41
|
-
end
|
42
|
-
|
43
37
|
describe '#trans2_parameters' do
|
44
38
|
subject(:parameters) { data_block.trans2_parameters }
|
45
39
|
|
@@ -80,9 +80,7 @@ RSpec.describe RubySMB::SMB1::Pipe do
|
|
80
80
|
|
81
81
|
it 'raises an InvalidPacket exception if the response is not valid' do
|
82
82
|
allow(response).to receive(:valid?).and_return(false)
|
83
|
-
|
84
|
-
allow(response).to receive(:smb_header).and_return(smb_header)
|
85
|
-
allow(smb_header).to receive_messages(:protocol => nil, :command => nil)
|
83
|
+
allow(response).to receive(:packet_smb_version)
|
86
84
|
expect { pipe.peek }.to raise_error(RubySMB::Error::InvalidPacket)
|
87
85
|
end
|
88
86
|
|
@@ -149,12 +147,40 @@ RSpec.describe RubySMB::SMB1::Pipe do
|
|
149
147
|
end
|
150
148
|
end
|
151
149
|
|
150
|
+
context 'with \'\\srvsvc\' filename' do
|
151
|
+
it 'extends Srvsvc class' do
|
152
|
+
pipe = described_class.new(tree: tree, response: nt_create_andx_response, name: '\\srvsvc')
|
153
|
+
expect(pipe.respond_to?(:net_share_enum_all)).to be true
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
152
157
|
context 'with \'winreg\' filename' do
|
153
158
|
it 'extends Winreg class' do
|
154
159
|
pipe = described_class.new(tree: tree, response: nt_create_andx_response, name: 'winreg')
|
155
160
|
expect(pipe.respond_to?(:has_registry_key?)).to be true
|
156
161
|
end
|
157
162
|
end
|
163
|
+
|
164
|
+
context 'with \'\\winreg\' filename' do
|
165
|
+
it 'extends Winreg class' do
|
166
|
+
pipe = described_class.new(tree: tree, response: nt_create_andx_response, name: '\\winreg')
|
167
|
+
expect(pipe.respond_to?(:has_registry_key?)).to be true
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
context 'with \'svcctl\' filename' do
|
172
|
+
it 'extends svcctl class' do
|
173
|
+
pipe = described_class.new(tree: tree, response: nt_create_andx_response, name: 'svcctl')
|
174
|
+
expect(pipe.respond_to?(:query_service_config)).to be true
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
context 'with \'\\svcctl\' filename' do
|
179
|
+
it 'extends svcctl class' do
|
180
|
+
pipe = described_class.new(tree: tree, response: nt_create_andx_response, name: '\\svcctl')
|
181
|
+
expect(pipe.respond_to?(:query_service_config)).to be true
|
182
|
+
end
|
183
|
+
end
|
158
184
|
end
|
159
185
|
|
160
186
|
describe '#dcerpc_request' do
|
@@ -238,8 +264,7 @@ RSpec.describe RubySMB::SMB1::Pipe do
|
|
238
264
|
|
239
265
|
context 'when the response is not a Trans packet' do
|
240
266
|
it 'raises an InvalidPacket exception' do
|
241
|
-
allow(trans_nmpipe_response).to
|
242
|
-
allow(trans_nmpipe_response).to receive_message_chain(:smb_header, :command)
|
267
|
+
allow(trans_nmpipe_response).to receive(:packet_smb_version)
|
243
268
|
allow(trans_nmpipe_response).to receive(:valid?).and_return(false)
|
244
269
|
expect { pipe.dcerpc_request(stub_packet, options) }.to raise_error(RubySMB::Error::InvalidPacket)
|
245
270
|
end
|
@@ -492,4 +492,26 @@ RSpec.describe RubySMB::SMB1::Tree do
|
|
492
492
|
end
|
493
493
|
end
|
494
494
|
|
495
|
+
describe '#open_pipe' do
|
496
|
+
let(:opts) { { filename: 'test', write: true } }
|
497
|
+
before :example do
|
498
|
+
allow(tree).to receive(:open_file)
|
499
|
+
end
|
500
|
+
|
501
|
+
it 'calls #open_file with the provided options' do
|
502
|
+
opts[:filename] ='\\test'
|
503
|
+
expect(tree).to receive(:open_file).with(opts)
|
504
|
+
tree.open_pipe(opts)
|
505
|
+
end
|
506
|
+
|
507
|
+
it 'prepends the filename with \\ if needed' do
|
508
|
+
expect(tree).to receive(:open_file).with( { filename: '\\test', write: true } )
|
509
|
+
tree.open_pipe(opts)
|
510
|
+
end
|
511
|
+
|
512
|
+
it 'does not modify the original option hash' do
|
513
|
+
tree.open_pipe(opts)
|
514
|
+
expect(opts).to eq( { filename: 'test', write: true } )
|
515
|
+
end
|
516
|
+
end
|
495
517
|
end
|
@@ -107,6 +107,10 @@ RSpec.describe RubySMB::SMB2::File do
|
|
107
107
|
it 'sets the offset of the packet' do
|
108
108
|
expect(file.read_packet(offset: 55).offset).to eq 55
|
109
109
|
end
|
110
|
+
|
111
|
+
it 'sets the credit_charge of the packet' do
|
112
|
+
expect(file.read_packet(credit_charge: 3).smb2_header.credit_charge).to eq 3
|
113
|
+
end
|
110
114
|
end
|
111
115
|
|
112
116
|
describe '#read' do
|
@@ -125,7 +129,7 @@ RSpec.describe RubySMB::SMB2::File do
|
|
125
129
|
end
|
126
130
|
|
127
131
|
it 'uses a single packet to read the entire file' do
|
128
|
-
expect(file).to receive(:read_packet).with(read_length: 108, offset: 0).and_return(small_read)
|
132
|
+
expect(file).to receive(:read_packet).with(read_length: 108, offset: 0, credit_charge: 0).and_return(small_read)
|
129
133
|
expect(client).to receive(:send_recv).with(small_read, encrypt: false).and_return 'fake data'
|
130
134
|
expect(RubySMB::SMB2::Packet::ReadResponse).to receive(:read).with('fake data').and_return(small_response)
|
131
135
|
expect(file.read).to eq 'fake data'
|
@@ -161,14 +165,15 @@ RSpec.describe RubySMB::SMB2::File do
|
|
161
165
|
}
|
162
166
|
|
163
167
|
before :example do
|
168
|
+
client.server_supports_multi_credit = 1
|
164
169
|
allow(file).to receive(:read_packet)
|
165
170
|
allow(client).to receive(:send_recv)
|
166
171
|
allow(RubySMB::SMB2::Packet::ReadResponse).to receive(:read).and_return(big_response)
|
167
172
|
end
|
168
173
|
|
169
|
-
it 'uses
|
170
|
-
expect(file).to receive(:read_packet).once.with(read_length: described_class::MAX_PACKET_SIZE, offset: 0).and_return(big_read)
|
171
|
-
expect(file).to receive(:read_packet).once.with(read_length: described_class::MAX_PACKET_SIZE, offset: described_class::MAX_PACKET_SIZE).and_return(big_read)
|
174
|
+
it 'uses multiple packets to read the file in chunks' do
|
175
|
+
expect(file).to receive(:read_packet).once.with(read_length: described_class::MAX_PACKET_SIZE, offset: 0, credit_charge: 1).and_return(big_read)
|
176
|
+
expect(file).to receive(:read_packet).once.with(read_length: described_class::MAX_PACKET_SIZE, offset: described_class::MAX_PACKET_SIZE, credit_charge: 1).and_return(big_read)
|
172
177
|
expect(client).to receive(:send_recv).twice.and_return 'fake data'
|
173
178
|
expect(RubySMB::SMB2::Packet::ReadResponse).to receive(:read).twice.with('fake data').and_return(big_response)
|
174
179
|
file.read(bytes: (described_class::MAX_PACKET_SIZE * 2))
|
@@ -184,7 +189,7 @@ RSpec.describe RubySMB::SMB2::File do
|
|
184
189
|
|
185
190
|
context 'when the second response is not valid' do
|
186
191
|
it 'raise an InvalidPacket exception' do
|
187
|
-
allow(file).to receive(:read_packet).with(read_length: described_class::MAX_PACKET_SIZE, offset: described_class::MAX_PACKET_SIZE) do
|
192
|
+
allow(file).to receive(:read_packet).with(read_length: described_class::MAX_PACKET_SIZE, offset: described_class::MAX_PACKET_SIZE, credit_charge: 1) do
|
188
193
|
big_response.smb2_header.command = RubySMB::SMB2::Commands::LOGOFF
|
189
194
|
end
|
190
195
|
expect { file.read(bytes: (described_class::MAX_PACKET_SIZE * 2)) }.to raise_error(RubySMB::Error::InvalidPacket)
|
@@ -193,12 +198,31 @@ RSpec.describe RubySMB::SMB2::File do
|
|
193
198
|
|
194
199
|
context 'when the second response status code is not STATUS_SUCCESS' do
|
195
200
|
it 'raise an UnexpectedStatusCode exception' do
|
196
|
-
allow(file).to receive(:read_packet).with(read_length: described_class::MAX_PACKET_SIZE, offset: described_class::MAX_PACKET_SIZE) do
|
201
|
+
allow(file).to receive(:read_packet).with(read_length: described_class::MAX_PACKET_SIZE, offset: described_class::MAX_PACKET_SIZE, credit_charge: 1) do
|
197
202
|
big_response.smb2_header.nt_status = WindowsError::NTStatus::STATUS_INVALID_HANDLE.value
|
198
203
|
end
|
199
204
|
expect { file.read(bytes: (described_class::MAX_PACKET_SIZE * 2)) }.to raise_error(RubySMB::Error::UnexpectedStatusCode)
|
200
205
|
end
|
201
206
|
end
|
207
|
+
|
208
|
+
context 'when the server does not support multi credits' do
|
209
|
+
it 'reads 65536 bytes at a time with no credit charge' do
|
210
|
+
client.server_supports_multi_credit = false
|
211
|
+
expect(file).to receive(:read_packet).once.with(read_length: 65536, offset: 0, credit_charge: 0).and_return(big_read)
|
212
|
+
expect(file).to receive(:read_packet).once.with(read_length: 65536, offset: 65536, credit_charge: 0).and_return(big_read)
|
213
|
+
file.read(bytes: (described_class::MAX_PACKET_SIZE * 4))
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
context 'when the server supports multi credits' do
|
218
|
+
it 'reads a number of bytes equal to #server_max_read_size, with the expected credit charge' do
|
219
|
+
credit_charge = (90000 - 1) / 65536 + 1
|
220
|
+
client.server_max_read_size = 90000
|
221
|
+
expect(file).to receive(:read_packet).once.with(read_length: 90000, offset: 0, credit_charge: credit_charge).and_return(big_read)
|
222
|
+
expect(file).to receive(:read_packet).once.with(read_length: (described_class::MAX_PACKET_SIZE * 4 - 90000), offset: 90000, credit_charge: credit_charge).and_return(big_read)
|
223
|
+
file.read(bytes: (described_class::MAX_PACKET_SIZE * 4))
|
224
|
+
end
|
225
|
+
end
|
202
226
|
end
|
203
227
|
end
|
204
228
|
|
@@ -222,6 +246,10 @@ RSpec.describe RubySMB::SMB2::File do
|
|
222
246
|
it 'sets the buffer on the packet' do
|
223
247
|
expect(file.write_packet(data:'hello').buffer).to eq 'hello'
|
224
248
|
end
|
249
|
+
|
250
|
+
it 'sets the credit_charge on the packet header' do
|
251
|
+
expect(file.write_packet(credit_charge: 5).smb2_header.credit_charge).to eq 5
|
252
|
+
end
|
225
253
|
end
|
226
254
|
|
227
255
|
describe '#write' do
|
@@ -242,6 +270,11 @@ RSpec.describe RubySMB::SMB2::File do
|
|
242
270
|
end
|
243
271
|
|
244
272
|
context 'for a large write' do
|
273
|
+
before :example do
|
274
|
+
allow(client).to receive(:send_recv).and_return(write_response.to_binary_s)
|
275
|
+
client.server_supports_multi_credit = 1
|
276
|
+
end
|
277
|
+
|
245
278
|
it 'sends multiple packets' do
|
246
279
|
expect(client).to receive(:send_recv).twice.and_return(write_response.to_binary_s)
|
247
280
|
file.write(data: SecureRandom.random_bytes(described_class::MAX_PACKET_SIZE + 1))
|
@@ -254,6 +287,27 @@ RSpec.describe RubySMB::SMB2::File do
|
|
254
287
|
expect(client).to receive(:send_recv).twice.with(write_request, encrypt: true).and_return(write_response.to_binary_s)
|
255
288
|
file.write(data: SecureRandom.random_bytes(described_class::MAX_PACKET_SIZE + 1))
|
256
289
|
end
|
290
|
+
|
291
|
+
context 'when the server does not support multi credits' do
|
292
|
+
it 'writes 65536 bytes at a time with no credit charge' do
|
293
|
+
client.server_supports_multi_credit = false
|
294
|
+
data = SecureRandom.random_bytes(65536 * 2)
|
295
|
+
expect(file).to receive(:write_packet).once.with(data: data[0, 65536], offset: 0, credit_charge: 0)
|
296
|
+
expect(file).to receive(:write_packet).once.with(data: data[65536, (data.size - 65536)], offset: 65536, credit_charge: 0)
|
297
|
+
file.write(data: data)
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
context 'when the server supports multi credits' do
|
302
|
+
it 'reads a number of bytes equal to #server_max_write_size, with the expected credit charge' do
|
303
|
+
data = SecureRandom.random_bytes(90000 * 2)
|
304
|
+
credit_charge = (90000 - 1) / 65536 + 1
|
305
|
+
client.server_max_write_size = 90000
|
306
|
+
expect(file).to receive(:write_packet).once.with(data: data[0, 90000], offset: 0, credit_charge: credit_charge)
|
307
|
+
expect(file).to receive(:write_packet).once.with(data: data[90000, (data.size - 90000)], offset: 90000, credit_charge: credit_charge)
|
308
|
+
file.write(data: data)
|
309
|
+
end
|
310
|
+
end
|
257
311
|
end
|
258
312
|
|
259
313
|
it 'raises an InvalidPacket exception if the response is not valid' do
|
@@ -405,9 +459,7 @@ RSpec.describe RubySMB::SMB2::File do
|
|
405
459
|
|
406
460
|
it 'raises an InvalidPacket exception if the response is not valid' do
|
407
461
|
allow(response).to receive(:valid?).and_return(false)
|
408
|
-
|
409
|
-
allow(response).to receive(:smb2_header).and_return(smb2_header)
|
410
|
-
allow(smb2_header).to receive_messages(:protocol => nil, :command => nil)
|
462
|
+
allow(response).to receive(:packet_smb_version)
|
411
463
|
expect { file.close }.to raise_error(RubySMB::Error::InvalidPacket)
|
412
464
|
end
|
413
465
|
|
@@ -86,9 +86,7 @@ RSpec.describe RubySMB::SMB2::Pipe do
|
|
86
86
|
|
87
87
|
it 'raises an InvalidPacket exception if the response is not valid' do
|
88
88
|
allow(response).to receive(:valid?).and_return(false)
|
89
|
-
|
90
|
-
allow(response).to receive(:smb2_header).and_return(smb2_header)
|
91
|
-
allow(smb2_header).to receive_messages(:protocol => nil, :command => nil)
|
89
|
+
allow(response).to receive(:packet_smb_version)
|
92
90
|
expect { pipe.peek }.to raise_error(RubySMB::Error::InvalidPacket)
|
93
91
|
end
|
94
92
|
|
@@ -161,6 +159,13 @@ RSpec.describe RubySMB::SMB2::Pipe do
|
|
161
159
|
expect(pipe.respond_to?(:has_registry_key?)).to be true
|
162
160
|
end
|
163
161
|
end
|
162
|
+
|
163
|
+
context 'with \'svcctl\' filename' do
|
164
|
+
it 'extends svcctl class' do
|
165
|
+
pipe = described_class.new(tree: tree, response: create_response, name: 'svcctl')
|
166
|
+
expect(pipe.respond_to?(:query_service_config)).to be true
|
167
|
+
end
|
168
|
+
end
|
164
169
|
end
|
165
170
|
|
166
171
|
describe '#dcerpc_request' do
|
@@ -254,8 +259,7 @@ RSpec.describe RubySMB::SMB2::Pipe do
|
|
254
259
|
|
255
260
|
context 'when the response is not an IoctlResponse packet' do
|
256
261
|
it 'raises an InvalidPacket exception' do
|
257
|
-
allow(ioctl_response).to
|
258
|
-
allow(ioctl_response).to receive_message_chain(:smb2_header, :command)
|
262
|
+
allow(ioctl_response).to receive(:packet_smb_version)
|
259
263
|
allow(ioctl_response).to receive(:valid?).and_return(false)
|
260
264
|
expect { pipe.ioctl_send_recv(dcerpc_request, options) }.to raise_error(RubySMB::Error::InvalidPacket)
|
261
265
|
end
|