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,88 @@
|
|
1
|
+
RSpec.describe RubySMB::Dcerpc::Winreg::RpcHkey do
|
2
|
+
it 'is NdrContextHandle subclass' do
|
3
|
+
expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrContextHandle
|
4
|
+
end
|
5
|
+
end
|
6
|
+
|
7
|
+
RSpec.describe RubySMB::Dcerpc::Winreg::QueryValueRequest do
|
8
|
+
subject(:packet) { described_class.new }
|
9
|
+
|
10
|
+
it { is_expected.to respond_to :hkey }
|
11
|
+
it { is_expected.to respond_to :lp_value_name }
|
12
|
+
it { is_expected.to respond_to :pad1 }
|
13
|
+
it { is_expected.to respond_to :lp_type }
|
14
|
+
it { is_expected.to respond_to :lp_data }
|
15
|
+
it { is_expected.to respond_to :pad2 }
|
16
|
+
it { is_expected.to respond_to :lpcb_data }
|
17
|
+
it { is_expected.to respond_to :lpcb_len }
|
18
|
+
it { is_expected.to respond_to :opnum }
|
19
|
+
|
20
|
+
it 'is little endian' do
|
21
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '#hkey' do
|
25
|
+
it 'is a RpcHkey structure' do
|
26
|
+
expect(packet.hkey).to be_a RubySMB::Dcerpc::Winreg::RpcHkey
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe '#lp_value_name' do
|
31
|
+
it 'is a RrpUnicodeString structure' do
|
32
|
+
expect(packet.lp_value_name).to be_a RubySMB::Dcerpc::RrpUnicodeString
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe '#pad1' do
|
37
|
+
it 'is a string' do
|
38
|
+
expect(packet.pad1).to be_a BinData::String
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'should keep #lp_type 4-byte aligned' do
|
42
|
+
packet.lp_value_name = 'test'
|
43
|
+
expect(packet.lp_type.abs_offset % 4).to eq 0
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe '#lp_type' do
|
48
|
+
it 'is a NdrLpDword structure' do
|
49
|
+
expect(packet.lp_type).to be_a RubySMB::Dcerpc::Ndr::NdrLpDword
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe '#lp_data' do
|
54
|
+
it 'is a NdrLpByteArray structure' do
|
55
|
+
expect(packet.lp_data).to be_a RubySMB::Dcerpc::Ndr::NdrLpByteArray
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe '#lpcb_data' do
|
60
|
+
it 'is a NdrLpDword structure' do
|
61
|
+
expect(packet.lpcb_data).to be_a RubySMB::Dcerpc::Ndr::NdrLpDword
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe '#pad2' do
|
66
|
+
it 'is a string' do
|
67
|
+
expect(packet.pad2).to be_a BinData::String
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'should keep #lpcb_data 4-byte aligned' do
|
71
|
+
packet.lp_data = [1, 2]
|
72
|
+
expect(packet.lpcb_data.abs_offset % 4).to eq 0
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
describe '#lpcb_len' do
|
77
|
+
it 'is a NdrLpDword structure' do
|
78
|
+
expect(packet.lpcb_len).to be_a RubySMB::Dcerpc::Ndr::NdrLpDword
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe '#initialize_instance' do
|
83
|
+
it 'sets #opnum to REG_QUERY_VALUE constant' do
|
84
|
+
expect(packet.opnum).to eq(RubySMB::Dcerpc::Winreg::REG_QUERY_VALUE)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
@@ -0,0 +1,138 @@
|
|
1
|
+
RSpec.describe RubySMB::Dcerpc::Winreg::QueryValueResponse do
|
2
|
+
subject(:packet) { described_class.new }
|
3
|
+
|
4
|
+
it { is_expected.to respond_to :lp_type }
|
5
|
+
it { is_expected.to respond_to :lp_data }
|
6
|
+
it { is_expected.to respond_to :pad }
|
7
|
+
it { is_expected.to respond_to :lpcb_data }
|
8
|
+
it { is_expected.to respond_to :lpcb_len }
|
9
|
+
it { is_expected.to respond_to :error_status }
|
10
|
+
it { is_expected.to respond_to :opnum }
|
11
|
+
|
12
|
+
it 'is little endian' do
|
13
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '#lp_type' do
|
17
|
+
it 'is a NdrLpDword structure' do
|
18
|
+
expect(packet.lp_type).to be_a RubySMB::Dcerpc::Ndr::NdrLpDword
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#lp_data' do
|
23
|
+
it 'is a NdrLpByteArray structure' do
|
24
|
+
expect(packet.lp_data).to be_a RubySMB::Dcerpc::Ndr::NdrLpByteArray
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe '#pad' do
|
29
|
+
it 'is a string' do
|
30
|
+
expect(packet.pad).to be_a BinData::String
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should keep #lpcb_data 4-byte aligned' do
|
34
|
+
packet.lp_data = 'spec_test'.bytes
|
35
|
+
expect(packet.lpcb_data.abs_offset % 4).to eq 0
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe '#lpcb_data' do
|
40
|
+
it 'is a NdrLpDword structure' do
|
41
|
+
expect(packet.lpcb_data).to be_a RubySMB::Dcerpc::Ndr::NdrLpDword
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe '#lpcb_len' do
|
46
|
+
it 'is a NdrLpDword structure' do
|
47
|
+
expect(packet.lpcb_len).to be_a RubySMB::Dcerpc::Ndr::NdrLpDword
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe '#error_status' do
|
52
|
+
it 'is a 32-bit unsigned integer' do
|
53
|
+
expect(packet.error_status).to be_a BinData::Uint32le
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe '#initialize_instance' do
|
58
|
+
it 'sets #opnum to REG_QUERY_VALUE constant' do
|
59
|
+
expect(packet.opnum).to eq(RubySMB::Dcerpc::Winreg::REG_QUERY_VALUE)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe '#data' do
|
64
|
+
context 'when #lp_type is 1 (unicode null-terminated string)' do
|
65
|
+
it 'returns the expected value' do
|
66
|
+
str = 'spec test string'.encode('utf-16le')
|
67
|
+
packet.lp_type = 1
|
68
|
+
packet.lp_data = str.bytes
|
69
|
+
expect(packet.data).to eq(str)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context 'when #lp_type is 2 (unicode null-terminated string with unexpanded references to environment variables)' do
|
74
|
+
it 'returns the expected value' do
|
75
|
+
str = '/%PATH%/foo'.encode('utf-16le')
|
76
|
+
packet.lp_type = 2
|
77
|
+
packet.lp_data = str.bytes
|
78
|
+
expect(packet.data).to eq(str)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
context 'when #lp_type is 3 (binary data)' do
|
83
|
+
it 'returns the expected value' do
|
84
|
+
bytes = [0xFF, 0xEE, 0xDD, 0xCC].pack('C*')
|
85
|
+
packet.lp_type = 3
|
86
|
+
packet.lp_data = bytes.bytes
|
87
|
+
expect(packet.data).to eq(bytes)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
context 'when #lp_type is 4 (a 32-bit number in little-endian format)' do
|
92
|
+
it 'returns the expected value' do
|
93
|
+
number = 12345
|
94
|
+
packet.lp_type = 4
|
95
|
+
packet.lp_data = [number].pack('V').bytes
|
96
|
+
expect(packet.data).to eq(number)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
context 'when #lp_type is 5 (a 32-bit number in big-endian format)' do
|
101
|
+
it 'returns the expected value' do
|
102
|
+
number = 12345
|
103
|
+
packet.lp_type = 5
|
104
|
+
packet.lp_data = [number].pack('N').bytes
|
105
|
+
expect(packet.data).to eq(number)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
context 'when #lp_type is 7 (a sequence of unicode null-terminated strings, terminated by an empty string)' do
|
110
|
+
it 'returns the expected value' do
|
111
|
+
str_array = ['String1', 'String2', 'String3', 'LastString'].map {|v| v.encode('utf-16le')}
|
112
|
+
null_byte = "\0".encode('utf-16le')
|
113
|
+
str = (str_array + [null_byte]).join(null_byte)
|
114
|
+
packet.lp_type = 7
|
115
|
+
packet.lp_data = str.bytes
|
116
|
+
expect(packet.data).to eq(str_array)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
context 'when #lp_type is 11 (a 64-bit number in little-endian format)' do
|
121
|
+
it 'returns the expected value' do
|
122
|
+
number = 0x1234567812345678
|
123
|
+
packet.lp_type = 11
|
124
|
+
packet.lp_data = [number].pack('Q<').bytes
|
125
|
+
expect(packet.data).to eq(number)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
context 'when #lp_type is an unknown value' do
|
130
|
+
it 'returns an empty string' do
|
131
|
+
str = 'test'
|
132
|
+
packet.lp_type = 6
|
133
|
+
packet.lp_data = str.bytes
|
134
|
+
expect(packet.data).to eq('')
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
RSpec.describe RubySMB::Dcerpc::Winreg::Regsam do
|
2
|
+
subject(:packet) { described_class.new }
|
3
|
+
|
4
|
+
it { is_expected.to respond_to :reserved }
|
5
|
+
it { is_expected.to respond_to :key_create_link }
|
6
|
+
it { is_expected.to respond_to :key_notify }
|
7
|
+
it { is_expected.to respond_to :key_enumerate_sub_keys }
|
8
|
+
it { is_expected.to respond_to :key_create_sub_key }
|
9
|
+
it { is_expected.to respond_to :key_set_value }
|
10
|
+
it { is_expected.to respond_to :key_query_value }
|
11
|
+
it { is_expected.to respond_to :reserved2 }
|
12
|
+
it { is_expected.to respond_to :key_wow64_32key }
|
13
|
+
it { is_expected.to respond_to :key_wow64_64key }
|
14
|
+
it { is_expected.to respond_to :reserved3 }
|
15
|
+
it { is_expected.to respond_to :synchronize }
|
16
|
+
it { is_expected.to respond_to :write_owner }
|
17
|
+
it { is_expected.to respond_to :write_dac }
|
18
|
+
it { is_expected.to respond_to :read_control }
|
19
|
+
it { is_expected.to respond_to :delete_access }
|
20
|
+
it { is_expected.to respond_to :generic_read }
|
21
|
+
it { is_expected.to respond_to :generic_write }
|
22
|
+
it { is_expected.to respond_to :generic_execute }
|
23
|
+
it { is_expected.to respond_to :generic_all }
|
24
|
+
it { is_expected.to respond_to :reserved4 }
|
25
|
+
it { is_expected.to respond_to :maximum }
|
26
|
+
it { is_expected.to respond_to :system_security }
|
27
|
+
|
28
|
+
|
29
|
+
it 'is little endian' do
|
30
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
RSpec.describe RubySMB::Dcerpc::Winreg::RpcHkey do
|
2
|
+
subject(:packet) { described_class.new }
|
3
|
+
|
4
|
+
it 'is NdrContextHandle subclass' do
|
5
|
+
expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrContextHandle
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
RSpec.describe RubySMB::Dcerpc::Winreg::SaveKeyRequest do
|
10
|
+
subject(:packet) { described_class.new }
|
11
|
+
|
12
|
+
|
13
|
+
it 'is little endian' do
|
14
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
15
|
+
end
|
16
|
+
|
17
|
+
it { is_expected.to respond_to :hkey }
|
18
|
+
it { is_expected.to respond_to :lp_file }
|
19
|
+
it { is_expected.to respond_to :pad }
|
20
|
+
it { is_expected.to respond_to :lp_security_attributes }
|
21
|
+
|
22
|
+
describe '#hkey' do
|
23
|
+
it 'is a RpcHkey structure' do
|
24
|
+
expect(packet.hkey).to be_a RubySMB::Dcerpc::Winreg::RpcHkey
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe '#lp_file' do
|
29
|
+
it 'is a RrpUnicodeString structure' do
|
30
|
+
expect(packet.lp_file).to be_a RubySMB::Dcerpc::RrpUnicodeString
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe '#pad' do
|
35
|
+
it 'is a string' do
|
36
|
+
expect(packet.pad).to be_a BinData::String
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should keep #lp_security_attributes 4-byte aligned' do
|
40
|
+
packet.lp_file = "test"
|
41
|
+
expect(packet.lp_security_attributes.abs_offset % 4).to eq 0
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe '#lp_security_attributes' do
|
46
|
+
it 'is a PrpcSecurityAttributes structure' do
|
47
|
+
expect(packet.lp_security_attributes).to be_a RubySMB::Dcerpc::PrpcSecurityAttributes
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe '#initialize_instance' do
|
52
|
+
it 'sets #opnum to REG_SAVE_KEY constant' do
|
53
|
+
expect(packet.opnum).to eq(RubySMB::Dcerpc::Winreg::REG_SAVE_KEY)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
RSpec.describe RubySMB::Dcerpc::Winreg::SaveKeyResponse do
|
2
|
+
subject(:packet) { described_class.new }
|
3
|
+
|
4
|
+
it { is_expected.to respond_to :error_status }
|
5
|
+
|
6
|
+
it 'is little endian' do
|
7
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
8
|
+
end
|
9
|
+
|
10
|
+
describe '#error_status' do
|
11
|
+
it 'is a 32-bit unsigned integer' do
|
12
|
+
expect(packet.error_status).to be_a BinData::Uint32le
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '#initialize_instance' do
|
17
|
+
it 'sets #opnum to REG_CREATE_KEY constant' do
|
18
|
+
expect(packet.opnum).to eq(RubySMB::Dcerpc::Winreg::REG_CREATE_KEY)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
@@ -0,0 +1,884 @@
|
|
1
|
+
RSpec.describe RubySMB::Dcerpc::Winreg do
|
2
|
+
let(:winreg) do
|
3
|
+
RubySMB::SMB1::Pipe.new(
|
4
|
+
tree: double('Tree'),
|
5
|
+
response: RubySMB::SMB1::Packet::NtCreateAndxResponse.new,
|
6
|
+
name: 'winreg'
|
7
|
+
)
|
8
|
+
end
|
9
|
+
|
10
|
+
describe '#open_root_key' do
|
11
|
+
let(:root_key_request_packet) { double('Root Key Request Packet') }
|
12
|
+
let(:response) { double('Response') }
|
13
|
+
let(:root_key_response_packet) { double('Root Key Response Packet') }
|
14
|
+
let(:ph_key) { double('PHKEY') }
|
15
|
+
before :example do
|
16
|
+
allow(described_class::OpenRootKeyRequest).to receive(:new).and_return(root_key_request_packet)
|
17
|
+
allow(winreg).to receive(:dcerpc_request).and_return(response)
|
18
|
+
allow(described_class::OpenRootKeyResponse).to receive(:read).and_return(root_key_response_packet)
|
19
|
+
allow(root_key_response_packet).to receive_messages(
|
20
|
+
:error_status => WindowsError::Win32::ERROR_SUCCESS,
|
21
|
+
:ph_key => ph_key
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'when the root key is unknown' do
|
26
|
+
it 'raises an ArgumentError exception' do
|
27
|
+
expect { winreg.open_root_key('UNKNOWN') }.to raise_error(ArgumentError)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'create the expected OpenRootKeyRequest packet' do
|
32
|
+
winreg.open_root_key('HKLM')
|
33
|
+
expect(described_class::OpenRootKeyRequest).to have_received(:new).with(opnum: described_class::OPEN_HKLM)
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'sends the expected dcerpc request' do
|
37
|
+
winreg.open_root_key('HKLM')
|
38
|
+
expect(winreg).to have_received(:dcerpc_request).with(root_key_request_packet)
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'creates a OpenRootKeyResponse structure from the expected dcerpc response' do
|
42
|
+
winreg.open_root_key('HKLM')
|
43
|
+
expect(described_class::OpenRootKeyResponse).to have_received(:read).with(response)
|
44
|
+
end
|
45
|
+
|
46
|
+
context 'when an IOError occurs while parsing the response' do
|
47
|
+
it 'raises a RubySMB::Dcerpc::Error::InvalidPacket' do
|
48
|
+
allow(described_class::OpenRootKeyResponse).to receive(:read).and_raise(IOError)
|
49
|
+
expect { winreg.open_root_key('HKLM') }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
context 'when the response error status is not WindowsError::Win32::ERROR_SUCCESS' do
|
54
|
+
it 'raises a RubySMB::Dcerpc::Error::WinregError' do
|
55
|
+
allow(root_key_response_packet).to receive(:error_status).and_return(WindowsError::Win32::ERROR_INVALID_DATA)
|
56
|
+
expect { winreg.open_root_key('HKLM') }.to raise_error(RubySMB::Dcerpc::Error::WinregError)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'returns the expected handler' do
|
61
|
+
expect(winreg.open_root_key('HKLM')).to eq(ph_key)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe '#open_key' do
|
66
|
+
let(:handle) { double('Handle') }
|
67
|
+
let(:sub_key) { double('Sub-key') }
|
68
|
+
let(:openkey_request_packet) { double('OpenKey Request Packet') }
|
69
|
+
let(:regsam) { double('Regsam') }
|
70
|
+
let(:response) { double('Response') }
|
71
|
+
let(:open_key_response) { double('OpenKey Response') }
|
72
|
+
let(:phk_result) { double('Phk Result') }
|
73
|
+
before :example do
|
74
|
+
allow(described_class::OpenKeyRequest).to receive(:new).and_return(openkey_request_packet)
|
75
|
+
allow(openkey_request_packet).to receive(:sam_desired).and_return(regsam)
|
76
|
+
allow(regsam).to receive_messages(
|
77
|
+
:read_control= => nil,
|
78
|
+
:key_query_value= => nil,
|
79
|
+
:key_enumerate_sub_keys= => nil,
|
80
|
+
:key_notify= => nil,
|
81
|
+
)
|
82
|
+
allow(winreg).to receive(:dcerpc_request).and_return(response)
|
83
|
+
allow(described_class::OpenKeyResponse).to receive(:read).and_return(open_key_response)
|
84
|
+
allow(open_key_response).to receive_messages(
|
85
|
+
:error_status => WindowsError::Win32::ERROR_SUCCESS,
|
86
|
+
:phk_result => phk_result
|
87
|
+
)
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'create the expected OpenKeyRequest packet' do
|
91
|
+
winreg.open_key(handle, sub_key)
|
92
|
+
expect(described_class::OpenKeyRequest).to have_received(:new).with(hkey: handle, lp_sub_key: sub_key)
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'sets the expected user rights on the request packet' do
|
96
|
+
winreg.open_key(handle, sub_key)
|
97
|
+
expect(regsam).to have_received(:read_control=).with(1)
|
98
|
+
expect(regsam).to have_received(:key_query_value=).with(1)
|
99
|
+
expect(regsam).to have_received(:key_enumerate_sub_keys=).with(1)
|
100
|
+
expect(regsam).to have_received(:key_notify=).with(1)
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'sends the expected dcerpc request' do
|
104
|
+
winreg.open_key(handle, sub_key)
|
105
|
+
expect(winreg).to have_received(:dcerpc_request).with(openkey_request_packet)
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'creates a OpenKeyResponse structure from the expected dcerpc response' do
|
109
|
+
winreg.open_key(handle, sub_key)
|
110
|
+
expect(described_class::OpenKeyResponse).to have_received(:read).with(response)
|
111
|
+
end
|
112
|
+
|
113
|
+
context 'when an IOError occurs while parsing the response' do
|
114
|
+
it 'raises a RubySMB::Dcerpc::Error::InvalidPacket' do
|
115
|
+
allow(described_class::OpenKeyResponse).to receive(:read).and_raise(IOError)
|
116
|
+
expect { winreg.open_key(handle, sub_key) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
context 'when the response error status is not WindowsError::Win32::ERROR_SUCCESS' do
|
121
|
+
it 'raises a RubySMB::Dcerpc::Error::WinregError' do
|
122
|
+
allow(open_key_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_INVALID_DATA)
|
123
|
+
expect { winreg.open_key(handle, sub_key) }.to raise_error(RubySMB::Dcerpc::Error::WinregError)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
it 'returns the expected handler' do
|
128
|
+
expect(winreg.open_key(handle, sub_key)).to eq(phk_result)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
describe '#query_value' do
|
133
|
+
let(:handle) { double('Handle') }
|
134
|
+
let(:value_name) { double('Value Name') }
|
135
|
+
let(:query_value_request_packet) { double('Query Value Request Packet #1') }
|
136
|
+
let(:lp_data1) { double('LpData #1') }
|
137
|
+
let(:lp_data2) { double('LpData #2') }
|
138
|
+
let(:response1) { double('Response #1') }
|
139
|
+
let(:response2) { double('Response #2') }
|
140
|
+
let(:query_value_response1) { double('Query Value Response #1') }
|
141
|
+
let(:query_value_response2) { double('Query Value Response #2') }
|
142
|
+
let(:data) { double('Data') }
|
143
|
+
let(:lpcb_data) { double('LpcbData') }
|
144
|
+
let(:lpcb_data_referent) { double('LpcbData Referent') }
|
145
|
+
let(:lp_data2_referent) { double('LpData Referent') }
|
146
|
+
before :example do
|
147
|
+
allow(described_class::QueryValueRequest).to receive(:new).and_return(query_value_request_packet)
|
148
|
+
allow(query_value_request_packet).to receive_messages(
|
149
|
+
:lp_type= => nil,
|
150
|
+
:lpcb_data= => nil,
|
151
|
+
:lpcb_len= => nil,
|
152
|
+
:lp_data= => nil,
|
153
|
+
:lp_data => lp_data2,
|
154
|
+
)
|
155
|
+
allow(lp_data2).to receive(:referent).and_return(lp_data2_referent)
|
156
|
+
allow(lp_data2_referent).to receive(:max_count=)
|
157
|
+
first_request = true
|
158
|
+
allow(winreg).to receive(:dcerpc_request) do |arg|
|
159
|
+
if first_request
|
160
|
+
first_request = false
|
161
|
+
response1
|
162
|
+
else
|
163
|
+
response2
|
164
|
+
end
|
165
|
+
end
|
166
|
+
allow(described_class::QueryValueResponse).to receive(:read).with(response1).and_return(query_value_response1)
|
167
|
+
allow(described_class::QueryValueResponse).to receive(:read).with(response2).and_return(query_value_response2)
|
168
|
+
allow(query_value_response1).to receive(:error_status).and_return(WindowsError::Win32::ERROR_SUCCESS)
|
169
|
+
allow(query_value_response2).to receive_messages(
|
170
|
+
:error_status => WindowsError::Win32::ERROR_SUCCESS,
|
171
|
+
:data => data
|
172
|
+
)
|
173
|
+
allow(query_value_response1).to receive(:lpcb_data).and_return(lpcb_data)
|
174
|
+
allow(lpcb_data).to receive(:referent).and_return(lpcb_data_referent)
|
175
|
+
end
|
176
|
+
|
177
|
+
it 'create the expected QueryValueRequest packets' do
|
178
|
+
winreg.query_value(handle, value_name)
|
179
|
+
expect(described_class::QueryValueRequest).to have_received(:new).with(hkey: handle, lp_value_name: value_name)
|
180
|
+
end
|
181
|
+
|
182
|
+
it 'sets the expected fields on the request packet' do
|
183
|
+
winreg.query_value(handle, value_name)
|
184
|
+
expect(query_value_request_packet).to have_received(:lp_type=).with(0)
|
185
|
+
expect(query_value_request_packet).to have_received(:lpcb_data=).with(0)
|
186
|
+
expect(query_value_request_packet).to have_received(:lpcb_len=).with(0)
|
187
|
+
expect(query_value_request_packet).to have_received(:lpcb_data=).with(lpcb_data)
|
188
|
+
expect(query_value_request_packet).to have_received(:lp_data=).with([])
|
189
|
+
expect(lp_data2_referent).to have_received(:max_count=).with(lpcb_data_referent)
|
190
|
+
end
|
191
|
+
|
192
|
+
it 'sends the expected dcerpc requests' do
|
193
|
+
winreg.query_value(handle, value_name)
|
194
|
+
expect(winreg).to have_received(:dcerpc_request).with(query_value_request_packet).twice
|
195
|
+
end
|
196
|
+
|
197
|
+
context 'when receiving the first response' do
|
198
|
+
it 'creates a QueryValueResponse structure from the expected dcerpc response' do
|
199
|
+
winreg.query_value(handle, value_name)
|
200
|
+
expect(described_class::QueryValueResponse).to have_received(:read).with(response1)
|
201
|
+
end
|
202
|
+
|
203
|
+
context 'when an IOError occurs while parsing the response' do
|
204
|
+
it 'raises a RubySMB::Dcerpc::Error::InvalidPacket' do
|
205
|
+
allow(described_class::QueryValueResponse).to receive(:read).with(response1).and_raise(IOError)
|
206
|
+
expect { winreg.query_value(handle, value_name) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
context 'when the first response error status is not WindowsError::Win32::ERROR_SUCCESS' do
|
211
|
+
it 'raises a RubySMB::Dcerpc::Error::WinregError' do
|
212
|
+
allow(query_value_response1).to receive(:error_status).and_return(WindowsError::Win32::ERROR_INVALID_DATA)
|
213
|
+
expect { winreg.query_value(handle, value_name) }.to raise_error(RubySMB::Dcerpc::Error::WinregError)
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
context 'when receiving the second response' do
|
219
|
+
it 'creates a QueryValueResponse structure from the expected dcerpc response' do
|
220
|
+
winreg.query_value(handle, value_name)
|
221
|
+
expect(described_class::QueryValueResponse).to have_received(:read).with(response2)
|
222
|
+
end
|
223
|
+
|
224
|
+
context 'when an IOError occurs while parsing the response' do
|
225
|
+
it 'raises a RubySMB::Dcerpc::Error::InvalidPacket' do
|
226
|
+
allow(described_class::QueryValueResponse).to receive(:read).with(response2).and_raise(IOError)
|
227
|
+
expect { winreg.query_value(handle, value_name) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
context 'when the first response error status is not WindowsError::Win32::ERROR_SUCCESS' do
|
232
|
+
it 'raises a RubySMB::Dcerpc::Error::WinregError' do
|
233
|
+
allow(query_value_response2).to receive(:error_status).and_return(WindowsError::Win32::ERROR_INVALID_DATA)
|
234
|
+
expect { winreg.query_value(handle, value_name) }.to raise_error(RubySMB::Dcerpc::Error::WinregError)
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
it 'returns the expected response data' do
|
240
|
+
expect(winreg.query_value(handle, value_name)).to eq(data)
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
describe '#close_key' do
|
245
|
+
let(:handle) { double('Handle') }
|
246
|
+
let(:close_key_request_packet) { double('CloseKey Request Packet') }
|
247
|
+
let(:response) { double('Response') }
|
248
|
+
let(:close_key_response) { double('CloseKey Response') }
|
249
|
+
before :example do
|
250
|
+
allow(described_class::CloseKeyRequest).to receive(:new).and_return(close_key_request_packet)
|
251
|
+
allow(winreg).to receive(:dcerpc_request).and_return(response)
|
252
|
+
allow(described_class::CloseKeyResponse).to receive(:read).and_return(close_key_response)
|
253
|
+
allow(close_key_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_SUCCESS)
|
254
|
+
end
|
255
|
+
|
256
|
+
it 'create the expected CloseKeyRequest packet' do
|
257
|
+
winreg.close_key(handle)
|
258
|
+
expect(described_class::CloseKeyRequest).to have_received(:new).with(hkey: handle)
|
259
|
+
end
|
260
|
+
|
261
|
+
it 'sends the expected dcerpc request' do
|
262
|
+
winreg.close_key(handle)
|
263
|
+
expect(winreg).to have_received(:dcerpc_request).with(close_key_request_packet)
|
264
|
+
end
|
265
|
+
|
266
|
+
it 'creates a CloseKeyResponse structure from the expected dcerpc response' do
|
267
|
+
winreg.close_key(handle)
|
268
|
+
expect(described_class::CloseKeyResponse).to have_received(:read).with(response)
|
269
|
+
end
|
270
|
+
|
271
|
+
context 'when an IOError occurs while parsing the response' do
|
272
|
+
it 'raises a RubySMB::Dcerpc::Error::InvalidPacket' do
|
273
|
+
allow(described_class::CloseKeyResponse).to receive(:read).and_raise(IOError)
|
274
|
+
expect { winreg.close_key(handle) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
context 'when the response error status is not WindowsError::Win32::ERROR_SUCCESS' do
|
279
|
+
it 'raises a RubySMB::Dcerpc::Error::WinregError' do
|
280
|
+
allow(close_key_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_INVALID_DATA)
|
281
|
+
expect { winreg.close_key(handle) }.to raise_error(RubySMB::Dcerpc::Error::WinregError)
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
it 'returns the expected error status' do
|
286
|
+
expect(winreg.close_key(handle)).to eq(WindowsError::Win32::ERROR_SUCCESS)
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
describe '#query_info_key' do
|
291
|
+
let(:handle) { double('Handle') }
|
292
|
+
let(:query_info_key_request_packet) { double('CloseKey Request Packet') }
|
293
|
+
let(:response) { double('Response') }
|
294
|
+
let(:query_info_key_response) { double('CloseKey Response') }
|
295
|
+
let(:lp_class) { double('LpClass') }
|
296
|
+
let(:lp_class_referent) { double('LpClass referent') }
|
297
|
+
let(:lp_class_buf_ref) { double('LpClass buffer referent') }
|
298
|
+
before :example do
|
299
|
+
allow(described_class::QueryInfoKeyRequest).to receive(:new).and_return(query_info_key_request_packet)
|
300
|
+
allow(query_info_key_request_packet).to receive_messages(
|
301
|
+
:lp_class= => nil,
|
302
|
+
:lp_class => lp_class,
|
303
|
+
)
|
304
|
+
allow(lp_class).to receive(:referent).and_return(lp_class_referent)
|
305
|
+
allow(lp_class_referent).to receive(:actual_count=)
|
306
|
+
allow(lp_class).to receive(:maximum_length=)
|
307
|
+
allow(lp_class).to receive_message_chain(:buffer, :referent => lp_class_buf_ref)
|
308
|
+
allow(lp_class_buf_ref).to receive(:max_count=)
|
309
|
+
allow(winreg).to receive(:dcerpc_request).and_return(response)
|
310
|
+
allow(described_class::QueryInfoKeyResponse).to receive(:read).and_return(query_info_key_response)
|
311
|
+
allow(query_info_key_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_SUCCESS)
|
312
|
+
end
|
313
|
+
|
314
|
+
it 'create the expected QueryInfoKeyRequest packet' do
|
315
|
+
winreg.query_info_key(handle)
|
316
|
+
expect(described_class::QueryInfoKeyRequest).to have_received(:new).with(hkey: handle)
|
317
|
+
end
|
318
|
+
|
319
|
+
it 'sends the expected dcerpc request' do
|
320
|
+
winreg.query_info_key(handle)
|
321
|
+
expect(winreg).to have_received(:dcerpc_request).with(query_info_key_request_packet)
|
322
|
+
end
|
323
|
+
|
324
|
+
it 'sets the expected fields on the request packet' do
|
325
|
+
winreg.query_info_key(handle)
|
326
|
+
expect(query_info_key_request_packet).to have_received(:lp_class=).with('')
|
327
|
+
expect(lp_class_referent).to have_received(:actual_count=).with(0)
|
328
|
+
expect(lp_class).to have_received(:maximum_length=).with(1024)
|
329
|
+
expect(lp_class_buf_ref).to have_received(:max_count=).with(1024 / 2)
|
330
|
+
end
|
331
|
+
|
332
|
+
it 'creates a QueryInfoKeyResponse structure from the expected dcerpc response' do
|
333
|
+
winreg.query_info_key(handle)
|
334
|
+
expect(described_class::QueryInfoKeyResponse).to have_received(:read).with(response)
|
335
|
+
end
|
336
|
+
|
337
|
+
context 'when an IOError occurs while parsing the response' do
|
338
|
+
it 'raises a RubySMB::Dcerpc::Error::InvalidPacket' do
|
339
|
+
allow(described_class::QueryInfoKeyResponse).to receive(:read).and_raise(IOError)
|
340
|
+
expect { winreg.query_info_key(handle) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
|
341
|
+
end
|
342
|
+
end
|
343
|
+
|
344
|
+
context 'when the response error status is not WindowsError::Win32::ERROR_SUCCESS' do
|
345
|
+
it 'raises a RubySMB::Dcerpc::Error::WinregError' do
|
346
|
+
allow(query_info_key_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_INVALID_DATA)
|
347
|
+
expect { winreg.query_info_key(handle) }.to raise_error(RubySMB::Dcerpc::Error::WinregError)
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
it 'returns the expected response' do
|
352
|
+
expect(winreg.query_info_key(handle)).to eq(query_info_key_response)
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
356
|
+
describe '#enum_key' do
|
357
|
+
let(:handle) { double('Handle') }
|
358
|
+
let(:index) { double('Index') }
|
359
|
+
let(:enum_key_request_packet) { double('enum_key Request Packet') }
|
360
|
+
let(:lp_name) { double('Lp Name') }
|
361
|
+
let(:buffer) { double('Buffer') }
|
362
|
+
let(:lp_name_buffer_referent) { double('Lp Name buffer referent') }
|
363
|
+
let(:response) { double('Response') }
|
364
|
+
let(:enum_key_response) { double('enum_key Response') }
|
365
|
+
let(:result_str) { double('Result String') }
|
366
|
+
let(:lp_class) { double('Lp Class') }
|
367
|
+
let(:lp_class_buffer_referent) { double('Lp Class buffer referent') }
|
368
|
+
before :example do
|
369
|
+
allow(described_class::EnumKeyRequest).to receive(:new).and_return(enum_key_request_packet)
|
370
|
+
allow(enum_key_request_packet).to receive_messages(
|
371
|
+
:lpft_last_write_time= => nil,
|
372
|
+
:lp_class= => nil,
|
373
|
+
:lp_name => lp_name,
|
374
|
+
:lp_class => lp_class
|
375
|
+
)
|
376
|
+
allow(lp_class).to receive(:referent).and_return(lp_class_buffer_referent)
|
377
|
+
allow(lp_class_buffer_referent).to receive(:buffer=)
|
378
|
+
allow(lp_name).to receive(:buffer).and_return(buffer)
|
379
|
+
allow(lp_name).to receive(:buffer=)
|
380
|
+
allow(buffer).to receive(:referent).and_return(lp_name_buffer_referent)
|
381
|
+
allow(lp_name_buffer_referent).to receive(:max_count=)
|
382
|
+
allow(winreg).to receive(:dcerpc_request).and_return(response)
|
383
|
+
allow(described_class::EnumKeyResponse).to receive(:read).and_return(enum_key_response)
|
384
|
+
allow(enum_key_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_SUCCESS)
|
385
|
+
allow(enum_key_response).to receive_message_chain(:lp_name, :to_s => result_str)
|
386
|
+
end
|
387
|
+
|
388
|
+
it 'create the expected EnumKeyRequest packet' do
|
389
|
+
winreg.enum_key(handle, index)
|
390
|
+
expect(described_class::EnumKeyRequest).to have_received(:new).with(hkey: handle, dw_index: index)
|
391
|
+
end
|
392
|
+
|
393
|
+
it 'sets the expected parameters on the request packet' do
|
394
|
+
winreg.enum_key(handle, index)
|
395
|
+
expect(enum_key_request_packet).to have_received(:lpft_last_write_time=).with(0)
|
396
|
+
expect(enum_key_request_packet).to have_received(:lp_class=).with('')
|
397
|
+
expect(lp_class_buffer_referent).to have_received(:buffer=).with(:null)
|
398
|
+
expect(lp_name).to have_received(:buffer=).with('')
|
399
|
+
expect(lp_name_buffer_referent).to have_received(:max_count=).with(256)
|
400
|
+
end
|
401
|
+
|
402
|
+
it 'sends the expected dcerpc request' do
|
403
|
+
winreg.enum_key(handle, index)
|
404
|
+
expect(winreg).to have_received(:dcerpc_request).with(enum_key_request_packet)
|
405
|
+
end
|
406
|
+
|
407
|
+
it 'creates a EnumKeyResponse structure from the expected dcerpc response' do
|
408
|
+
winreg.enum_key(handle, index)
|
409
|
+
expect(described_class::EnumKeyResponse).to have_received(:read).with(response)
|
410
|
+
end
|
411
|
+
|
412
|
+
context 'when an IOError occurs while parsing the response' do
|
413
|
+
it 'raises a RubySMB::Dcerpc::Error::InvalidPacket' do
|
414
|
+
allow(described_class::EnumKeyResponse).to receive(:read).and_raise(IOError)
|
415
|
+
expect { winreg.enum_key(handle, index) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
|
416
|
+
end
|
417
|
+
end
|
418
|
+
|
419
|
+
context 'when the response error status is not WindowsError::Win32::ERROR_SUCCESS' do
|
420
|
+
it 'raises a RubySMB::Dcerpc::Error::WinregError' do
|
421
|
+
allow(enum_key_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_INVALID_DATA)
|
422
|
+
expect { winreg.enum_key(handle, index) }.to raise_error(RubySMB::Dcerpc::Error::WinregError)
|
423
|
+
end
|
424
|
+
end
|
425
|
+
|
426
|
+
it 'returns the expected key name' do
|
427
|
+
expect(winreg.enum_key(handle, index)).to eq(result_str)
|
428
|
+
end
|
429
|
+
end
|
430
|
+
|
431
|
+
describe '#enum_value' do
|
432
|
+
let(:handle) { double('Handle') }
|
433
|
+
let(:index) { double('Index') }
|
434
|
+
let(:enum_value_request_packet) { double('EnumValue Request Packet') }
|
435
|
+
let(:lp_value_name) { double('Lp Value Name') }
|
436
|
+
let(:buffer) { double('Buffer') }
|
437
|
+
let(:referent) { double('Referent') }
|
438
|
+
let(:response) { double('Response') }
|
439
|
+
let(:enum_value_response) { double('EnumValue Response') }
|
440
|
+
let(:result_str) { double('Result String') }
|
441
|
+
before :example do
|
442
|
+
allow(described_class::EnumValueRequest).to receive(:new).and_return(enum_value_request_packet)
|
443
|
+
allow(enum_value_request_packet).to receive(:lp_value_name).and_return(lp_value_name)
|
444
|
+
allow(lp_value_name).to receive(:buffer).and_return(buffer)
|
445
|
+
allow(lp_value_name).to receive(:buffer=)
|
446
|
+
allow(buffer).to receive(:referent).and_return(referent)
|
447
|
+
allow(referent).to receive(:max_count=)
|
448
|
+
allow(winreg).to receive(:dcerpc_request).and_return(response)
|
449
|
+
allow(described_class::EnumValueResponse).to receive(:read).and_return(enum_value_response)
|
450
|
+
allow(enum_value_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_SUCCESS)
|
451
|
+
allow(enum_value_response).to receive_message_chain(:lp_value_name, :to_s => result_str)
|
452
|
+
end
|
453
|
+
|
454
|
+
it 'create the expected EnumValueRequest packet' do
|
455
|
+
winreg.enum_value(handle, index)
|
456
|
+
expect(described_class::EnumValueRequest).to have_received(:new).with(hkey: handle, dw_index: index)
|
457
|
+
end
|
458
|
+
|
459
|
+
it 'sets the expected buffer on the request packet' do
|
460
|
+
winreg.enum_value(handle, index)
|
461
|
+
expect(referent).to have_received(:max_count=).with(256)
|
462
|
+
expect(lp_value_name).to have_received(:buffer=).with('')
|
463
|
+
end
|
464
|
+
|
465
|
+
it 'sends the expected dcerpc request' do
|
466
|
+
winreg.enum_value(handle, index)
|
467
|
+
expect(winreg).to have_received(:dcerpc_request).with(enum_value_request_packet)
|
468
|
+
end
|
469
|
+
|
470
|
+
it 'creates a EnumValueResponse structure from the expected dcerpc response' do
|
471
|
+
winreg.enum_value(handle, index)
|
472
|
+
expect(described_class::EnumValueResponse).to have_received(:read).with(response)
|
473
|
+
end
|
474
|
+
|
475
|
+
context 'when an IOError occurs while parsing the response' do
|
476
|
+
it 'raises a RubySMB::Dcerpc::Error::InvalidPacket' do
|
477
|
+
allow(described_class::EnumValueResponse).to receive(:read).and_raise(IOError)
|
478
|
+
expect { winreg.enum_value(handle, index) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
|
479
|
+
end
|
480
|
+
end
|
481
|
+
|
482
|
+
context 'when the response error status is not WindowsError::Win32::ERROR_SUCCESS' do
|
483
|
+
it 'raises a RubySMB::Dcerpc::Error::WinregError' do
|
484
|
+
allow(enum_value_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_INVALID_DATA)
|
485
|
+
expect { winreg.enum_value(handle, index) }.to raise_error(RubySMB::Dcerpc::Error::WinregError)
|
486
|
+
end
|
487
|
+
end
|
488
|
+
|
489
|
+
it 'returns the expected key name' do
|
490
|
+
expect(winreg.enum_value(handle, index)).to eq(result_str)
|
491
|
+
end
|
492
|
+
end
|
493
|
+
|
494
|
+
describe '#has_registry_key?' do
|
495
|
+
let(:root_key) { 'HKLM' }
|
496
|
+
let(:sub_key) { 'my\\sub\\key\\path' }
|
497
|
+
let(:key) { "#{root_key}\\#{sub_key}" }
|
498
|
+
let(:root_key_handle) { double('Root Key Handle') }
|
499
|
+
let(:subkey_handle) { double('Subkey Handle') }
|
500
|
+
before :example do
|
501
|
+
allow(winreg).to receive_messages(
|
502
|
+
:bind => nil,
|
503
|
+
:open_root_key => root_key_handle,
|
504
|
+
:open_key => subkey_handle,
|
505
|
+
:close_key => nil
|
506
|
+
)
|
507
|
+
end
|
508
|
+
|
509
|
+
it 'binds a DCERPC connection to the expected remote endpoint' do
|
510
|
+
winreg.has_registry_key?(key)
|
511
|
+
expect(winreg).to have_received(:bind).with(endpoint: RubySMB::Dcerpc::Winreg)
|
512
|
+
end
|
513
|
+
|
514
|
+
it 'does not bind a DCERPC connection if #bind argument is false' do
|
515
|
+
winreg.has_registry_key?(key, bind: false)
|
516
|
+
expect(winreg).to_not have_received(:bind)
|
517
|
+
end
|
518
|
+
|
519
|
+
it 'opens the expected root key' do
|
520
|
+
winreg.has_registry_key?(key)
|
521
|
+
expect(winreg).to have_received(:open_root_key).with(root_key)
|
522
|
+
end
|
523
|
+
|
524
|
+
it 'opens the expected registry key' do
|
525
|
+
winreg.has_registry_key?(key)
|
526
|
+
expect(winreg).to have_received(:open_key).with(root_key_handle, sub_key)
|
527
|
+
end
|
528
|
+
|
529
|
+
context 'when a WinregError occurs while opening the root key' do
|
530
|
+
it 'returns false' do
|
531
|
+
allow(winreg).to receive(:open_root_key).and_raise(RubySMB::Dcerpc::Error::WinregError)
|
532
|
+
expect(winreg.has_registry_key?(key)).to be false
|
533
|
+
end
|
534
|
+
end
|
535
|
+
|
536
|
+
context 'when a WinregError occurs while opening the registry key' do
|
537
|
+
it 'returns false' do
|
538
|
+
allow(winreg).to receive(:open_key).and_raise(RubySMB::Dcerpc::Error::WinregError)
|
539
|
+
expect(winreg.has_registry_key?(key)).to be false
|
540
|
+
end
|
541
|
+
end
|
542
|
+
|
543
|
+
it 'closes the key' do
|
544
|
+
winreg.has_registry_key?(key)
|
545
|
+
expect(winreg).to have_received(:close_key).with(subkey_handle)
|
546
|
+
expect(winreg).to have_received(:close_key).with(root_key_handle)
|
547
|
+
end
|
548
|
+
|
549
|
+
it 'returns true when no error occurs' do
|
550
|
+
expect(winreg.has_registry_key?(key)).to be true
|
551
|
+
end
|
552
|
+
end
|
553
|
+
|
554
|
+
describe '#read_registry_key_value' do
|
555
|
+
let(:root_key) { 'HKLM' }
|
556
|
+
let(:sub_key) { 'my\\sub\\key\\path' }
|
557
|
+
let(:key) { "#{root_key}\\#{sub_key}" }
|
558
|
+
let(:value_name) { 'registry_value_name' }
|
559
|
+
let(:root_key_handle) { double('Root Key Handle') }
|
560
|
+
let(:subkey_handle) { double('Subkey Handle') }
|
561
|
+
let(:value) { double('Value') }
|
562
|
+
before :example do
|
563
|
+
allow(winreg).to receive_messages(
|
564
|
+
:bind => nil,
|
565
|
+
:open_root_key => root_key_handle,
|
566
|
+
:open_key => subkey_handle,
|
567
|
+
:query_value => value,
|
568
|
+
:close_key => nil
|
569
|
+
)
|
570
|
+
end
|
571
|
+
|
572
|
+
it 'binds a DCERPC connection to the expected remote endpoint' do
|
573
|
+
winreg.read_registry_key_value(key, value_name)
|
574
|
+
expect(winreg).to have_received(:bind).with(endpoint: RubySMB::Dcerpc::Winreg)
|
575
|
+
end
|
576
|
+
|
577
|
+
it 'does not bind a DCERPC connection if #bind argument is false' do
|
578
|
+
winreg.read_registry_key_value(key, value_name, bind: false)
|
579
|
+
expect(winreg).to_not have_received(:bind)
|
580
|
+
end
|
581
|
+
|
582
|
+
it 'opens the expected root key' do
|
583
|
+
winreg.read_registry_key_value(key, value_name)
|
584
|
+
expect(winreg).to have_received(:open_root_key).with(root_key)
|
585
|
+
end
|
586
|
+
|
587
|
+
it 'opens the expected registry key' do
|
588
|
+
winreg.read_registry_key_value(key, value_name)
|
589
|
+
expect(winreg).to have_received(:open_key).with(root_key_handle, sub_key)
|
590
|
+
end
|
591
|
+
|
592
|
+
it 'queries the expected registry key value' do
|
593
|
+
winreg.read_registry_key_value(key, value_name)
|
594
|
+
expect(winreg).to have_received(:query_value).with(subkey_handle, value_name)
|
595
|
+
end
|
596
|
+
|
597
|
+
it 'closes the key' do
|
598
|
+
winreg.read_registry_key_value(key, value_name)
|
599
|
+
expect(winreg).to have_received(:close_key).with(subkey_handle)
|
600
|
+
expect(winreg).to have_received(:close_key).with(root_key_handle)
|
601
|
+
end
|
602
|
+
|
603
|
+
it 'returns expect registry key value' do
|
604
|
+
expect(winreg.read_registry_key_value(key, value_name)).to eq(value)
|
605
|
+
end
|
606
|
+
end
|
607
|
+
|
608
|
+
describe '#enum_registry_key' do
|
609
|
+
let(:root_key) { 'HKLM' }
|
610
|
+
let(:sub_key) { 'my\\sub\\key\\path' }
|
611
|
+
let(:key) { "#{root_key}\\#{sub_key}" }
|
612
|
+
let(:value_name) { 'registry_value_name' }
|
613
|
+
let(:root_key_handle) { double('Root Key Handle') }
|
614
|
+
let(:subkey_handle) { double('Subkey Handle') }
|
615
|
+
let(:query_info_key_response) { double('Query Info Key Response') }
|
616
|
+
let(:subkey_nb) { 2 }
|
617
|
+
before :example do
|
618
|
+
allow(winreg).to receive_messages(
|
619
|
+
:bind => nil,
|
620
|
+
:open_root_key => root_key_handle,
|
621
|
+
:open_key => subkey_handle,
|
622
|
+
:query_info_key => query_info_key_response,
|
623
|
+
:enum_key => nil,
|
624
|
+
:close_key => nil
|
625
|
+
)
|
626
|
+
allow(query_info_key_response).to receive(:lpc_sub_keys).and_return(subkey_nb)
|
627
|
+
end
|
628
|
+
|
629
|
+
it 'binds a DCERPC connection to the expected remote endpoint' do
|
630
|
+
winreg.enum_registry_key(key)
|
631
|
+
expect(winreg).to have_received(:bind).with(endpoint: RubySMB::Dcerpc::Winreg)
|
632
|
+
end
|
633
|
+
|
634
|
+
it 'does not bind a DCERPC connection if #bind argument is false' do
|
635
|
+
winreg.enum_registry_key(key, bind: false)
|
636
|
+
expect(winreg).to_not have_received(:bind)
|
637
|
+
end
|
638
|
+
|
639
|
+
it 'opens the expected root key' do
|
640
|
+
winreg.enum_registry_key(key)
|
641
|
+
expect(winreg).to have_received(:open_root_key).with(root_key)
|
642
|
+
end
|
643
|
+
|
644
|
+
context 'when the registry key only contains the root key' do
|
645
|
+
it 'queries information for the root key' do
|
646
|
+
winreg.enum_registry_key(root_key)
|
647
|
+
expect(winreg).to have_received(:query_info_key).with(root_key_handle)
|
648
|
+
end
|
649
|
+
end
|
650
|
+
|
651
|
+
it 'opens the expected registry key' do
|
652
|
+
winreg.enum_registry_key(key)
|
653
|
+
expect(winreg).to have_received(:open_key).with(root_key_handle, sub_key)
|
654
|
+
end
|
655
|
+
|
656
|
+
it 'queries information for the expected registry key' do
|
657
|
+
winreg.enum_registry_key(key)
|
658
|
+
expect(winreg).to have_received(:query_info_key).with(subkey_handle)
|
659
|
+
end
|
660
|
+
|
661
|
+
it 'calls #enum_key the expected number of times' do
|
662
|
+
winreg.enum_registry_key(key)
|
663
|
+
expect(winreg).to have_received(:enum_key).with(subkey_handle, instance_of(Fixnum)).twice
|
664
|
+
end
|
665
|
+
|
666
|
+
it 'closes the key' do
|
667
|
+
winreg.enum_registry_key(key)
|
668
|
+
expect(winreg).to have_received(:close_key).with(subkey_handle)
|
669
|
+
expect(winreg).to have_received(:close_key).with(root_key_handle)
|
670
|
+
end
|
671
|
+
|
672
|
+
it 'returns the expected array of enumerated keys' do
|
673
|
+
key1 = 'key1'
|
674
|
+
key2 = 'key2'
|
675
|
+
allow(winreg).to receive(:enum_key).with(subkey_handle, 0).and_return(key1)
|
676
|
+
allow(winreg).to receive(:enum_key).with(subkey_handle, 1).and_return(key2)
|
677
|
+
expect(winreg.enum_registry_key(key)).to eq([key1, key2])
|
678
|
+
end
|
679
|
+
end
|
680
|
+
|
681
|
+
describe '#enum_registry_values' do
|
682
|
+
let(:root_key) { 'HKLM' }
|
683
|
+
let(:sub_key) { 'my\\sub\\key\\path' }
|
684
|
+
let(:key) { "#{root_key}\\#{sub_key}" }
|
685
|
+
let(:value_name) { 'registry_value_name' }
|
686
|
+
let(:root_key_handle) { double('Root Key Handle') }
|
687
|
+
let(:subkey_handle) { double('Subkey Handle') }
|
688
|
+
let(:query_info_key_response) { double('Query Info Key Response') }
|
689
|
+
let(:subkey_nb) { 2 }
|
690
|
+
before :example do
|
691
|
+
allow(winreg).to receive_messages(
|
692
|
+
:bind => nil,
|
693
|
+
:open_root_key => root_key_handle,
|
694
|
+
:open_key => subkey_handle,
|
695
|
+
:query_info_key => query_info_key_response,
|
696
|
+
:enum_value => nil,
|
697
|
+
:close_key => nil
|
698
|
+
)
|
699
|
+
allow(query_info_key_response).to receive(:lpc_values).and_return(subkey_nb)
|
700
|
+
end
|
701
|
+
|
702
|
+
it 'binds a DCERPC connection to the expected remote endpoint' do
|
703
|
+
winreg.enum_registry_values(key)
|
704
|
+
expect(winreg).to have_received(:bind).with(endpoint: RubySMB::Dcerpc::Winreg)
|
705
|
+
end
|
706
|
+
|
707
|
+
it 'does not bind a DCERPC connection if #bind argument is false' do
|
708
|
+
winreg.enum_registry_values(key, bind: false)
|
709
|
+
expect(winreg).to_not have_received(:bind)
|
710
|
+
end
|
711
|
+
|
712
|
+
it 'opens the expected root key' do
|
713
|
+
winreg.enum_registry_values(key)
|
714
|
+
expect(winreg).to have_received(:open_root_key).with(root_key)
|
715
|
+
end
|
716
|
+
|
717
|
+
context 'when the registry key only contains the root key' do
|
718
|
+
it 'queries information for the root key' do
|
719
|
+
winreg.enum_registry_values(root_key)
|
720
|
+
expect(winreg).to have_received(:query_info_key).with(root_key_handle)
|
721
|
+
end
|
722
|
+
end
|
723
|
+
|
724
|
+
it 'opens the expected registry key' do
|
725
|
+
winreg.enum_registry_values(key)
|
726
|
+
expect(winreg).to have_received(:open_key).with(root_key_handle, sub_key)
|
727
|
+
end
|
728
|
+
|
729
|
+
it 'queries information for the expected registry key' do
|
730
|
+
winreg.enum_registry_values(key)
|
731
|
+
expect(winreg).to have_received(:query_info_key).with(subkey_handle)
|
732
|
+
end
|
733
|
+
|
734
|
+
it 'calls #enum_key the expected number of times' do
|
735
|
+
winreg.enum_registry_values(key)
|
736
|
+
expect(winreg).to have_received(:enum_value).with(subkey_handle, instance_of(Fixnum)).twice
|
737
|
+
end
|
738
|
+
|
739
|
+
it 'closes the key' do
|
740
|
+
winreg.enum_registry_values(key)
|
741
|
+
expect(winreg).to have_received(:close_key).with(subkey_handle)
|
742
|
+
expect(winreg).to have_received(:close_key).with(root_key_handle)
|
743
|
+
end
|
744
|
+
|
745
|
+
it 'returns the expected array of enumerated keys' do
|
746
|
+
value1 = 'value1'
|
747
|
+
value2 = 'value2'
|
748
|
+
allow(winreg).to receive(:enum_value).with(subkey_handle, 0).and_return(value1)
|
749
|
+
allow(winreg).to receive(:enum_value).with(subkey_handle, 1).and_return(value2)
|
750
|
+
expect(winreg.enum_registry_values(key)).to eq([value1, value2])
|
751
|
+
end
|
752
|
+
end
|
753
|
+
|
754
|
+
describe '#create_key' do
|
755
|
+
let(:handle) { double('Handle') }
|
756
|
+
let(:sub_key) { double('Sub key') }
|
757
|
+
let(:create_key_request) { double('CreateKey Request') }
|
758
|
+
let(:response) { double('Response') }
|
759
|
+
let(:create_key_response) { double('CreateKey Response') }
|
760
|
+
let(:hkey) { double('hkey') }
|
761
|
+
before :example do
|
762
|
+
allow(described_class::CreateKeyRequest).to receive(:new).and_return(create_key_request)
|
763
|
+
allow(winreg).to receive(:dcerpc_request).and_return(response)
|
764
|
+
allow(described_class::CreateKeyResponse).to receive(:read).and_return(create_key_response)
|
765
|
+
allow(create_key_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_SUCCESS)
|
766
|
+
allow(create_key_response).to receive(:hkey).and_return(hkey)
|
767
|
+
end
|
768
|
+
|
769
|
+
it 'create the expected CreateKeyRequest packet with the default options' do
|
770
|
+
opts = {
|
771
|
+
hkey: handle,
|
772
|
+
lp_sub_key: sub_key,
|
773
|
+
lp_class: :null,
|
774
|
+
dw_options: RubySMB::Dcerpc::Winreg::CreateKeyRequest::REG_KEY_TYPE_VOLATILE,
|
775
|
+
sam_desired: RubySMB::Dcerpc::Winreg::Regsam.new(maximum: 1),
|
776
|
+
lp_security_attributes: RubySMB::Dcerpc::RpcSecurityAttributes.new,
|
777
|
+
lpdw_disposition: RubySMB::Dcerpc::Winreg::CreateKeyRequest::REG_CREATED_NEW_KEY
|
778
|
+
}
|
779
|
+
winreg.create_key(handle, sub_key)
|
780
|
+
expect(described_class::CreateKeyRequest).to have_received(:new).with(opts)
|
781
|
+
end
|
782
|
+
|
783
|
+
it 'create the expected CreateKeyRequest packet with custom options' do
|
784
|
+
opts = {
|
785
|
+
hkey: handle,
|
786
|
+
lp_sub_key: sub_key,
|
787
|
+
lp_class: 'MyClass',
|
788
|
+
dw_options: RubySMB::Dcerpc::Winreg::CreateKeyRequest::REG_KEY_TYPE_SYMLINK,
|
789
|
+
sam_desired: RubySMB::Dcerpc::Winreg::Regsam.new(key_set_value: 1),
|
790
|
+
lp_security_attributes: RubySMB::Dcerpc::RpcSecurityAttributes.new(n_length: 3),
|
791
|
+
lpdw_disposition: RubySMB::Dcerpc::Winreg::CreateKeyRequest::REG_OPENED_EXISTING_KEY
|
792
|
+
}
|
793
|
+
winreg.create_key(handle, sub_key, opts)
|
794
|
+
expect(described_class::CreateKeyRequest).to have_received(:new).with(opts)
|
795
|
+
end
|
796
|
+
|
797
|
+
it 'sends the expected dcerpc request' do
|
798
|
+
winreg.create_key(handle, sub_key)
|
799
|
+
expect(winreg).to have_received(:dcerpc_request).with(create_key_request)
|
800
|
+
end
|
801
|
+
|
802
|
+
it 'creates a CreateKeyResponse structure from the expected dcerpc response' do
|
803
|
+
winreg.create_key(handle, sub_key)
|
804
|
+
expect(described_class::CreateKeyResponse).to have_received(:read).with(response)
|
805
|
+
end
|
806
|
+
|
807
|
+
context 'when an IOError occurs while parsing the response' do
|
808
|
+
it 'raises a RubySMB::Dcerpc::Error::InvalidPacket' do
|
809
|
+
allow(described_class::CreateKeyResponse).to receive(:read).and_raise(IOError)
|
810
|
+
expect { winreg.create_key(handle, sub_key) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
|
811
|
+
end
|
812
|
+
end
|
813
|
+
|
814
|
+
context 'when the response error status is not WindowsError::Win32::ERROR_SUCCESS' do
|
815
|
+
it 'raises a RubySMB::Dcerpc::Error::WinregError' do
|
816
|
+
allow(create_key_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_INVALID_DATA)
|
817
|
+
expect { winreg.create_key(handle, sub_key) }.to raise_error(RubySMB::Dcerpc::Error::WinregError)
|
818
|
+
end
|
819
|
+
end
|
820
|
+
|
821
|
+
it 'returns the expected key name' do
|
822
|
+
expect(winreg.create_key(handle, sub_key)).to eq(hkey)
|
823
|
+
end
|
824
|
+
end
|
825
|
+
|
826
|
+
describe '#save_key' do
|
827
|
+
let(:handle) { double('Handle') }
|
828
|
+
let(:filename) { double('Filename') }
|
829
|
+
let(:save_key_request) { double('CreateKey Request') }
|
830
|
+
let(:response) { double('Response') }
|
831
|
+
let(:save_key_response) { double('CreateKey Response') }
|
832
|
+
let(:hkey) { double('hkey') }
|
833
|
+
before :example do
|
834
|
+
allow(described_class::SaveKeyRequest).to receive(:new).and_return(save_key_request)
|
835
|
+
allow(winreg).to receive(:dcerpc_request).and_return(response)
|
836
|
+
allow(described_class::SaveKeyResponse).to receive(:read).and_return(save_key_response)
|
837
|
+
allow(save_key_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_SUCCESS)
|
838
|
+
end
|
839
|
+
|
840
|
+
it 'create the expected SaveKeyRequest packet with the default options' do
|
841
|
+
opts = {
|
842
|
+
hkey: handle,
|
843
|
+
lp_file: filename,
|
844
|
+
lp_security_attributes: :null,
|
845
|
+
}
|
846
|
+
winreg.save_key(handle, filename)
|
847
|
+
expect(described_class::SaveKeyRequest).to have_received(:new).with(opts)
|
848
|
+
end
|
849
|
+
|
850
|
+
it 'create the expected SaveKeyRequest packet with custom options' do
|
851
|
+
opts = {
|
852
|
+
hkey: handle,
|
853
|
+
lp_file: filename,
|
854
|
+
lp_security_attributes: RubySMB::Dcerpc::RpcSecurityAttributes.new,
|
855
|
+
}
|
856
|
+
winreg.save_key(handle, filename, opts)
|
857
|
+
expect(described_class::SaveKeyRequest).to have_received(:new).with(opts)
|
858
|
+
end
|
859
|
+
|
860
|
+
it 'sends the expected dcerpc request' do
|
861
|
+
winreg.save_key(handle, filename)
|
862
|
+
expect(winreg).to have_received(:dcerpc_request).with(save_key_request)
|
863
|
+
end
|
864
|
+
|
865
|
+
it 'creates a SaveKeyResponse structure from the expected dcerpc response' do
|
866
|
+
winreg.save_key(handle, filename)
|
867
|
+
expect(described_class::SaveKeyResponse).to have_received(:read).with(response)
|
868
|
+
end
|
869
|
+
|
870
|
+
context 'when an IOError occurs while parsing the response' do
|
871
|
+
it 'raises a RubySMB::Dcerpc::Error::InvalidPacket' do
|
872
|
+
allow(described_class::SaveKeyResponse).to receive(:read).and_raise(IOError)
|
873
|
+
expect { winreg.save_key(handle, filename) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
|
874
|
+
end
|
875
|
+
end
|
876
|
+
|
877
|
+
context 'when the response error status is not WindowsError::Win32::ERROR_SUCCESS' do
|
878
|
+
it 'raises a RubySMB::Dcerpc::Error::WinregError' do
|
879
|
+
allow(save_key_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_INVALID_DATA)
|
880
|
+
expect { winreg.save_key(handle, filename) }.to raise_error(RubySMB::Dcerpc::Error::WinregError)
|
881
|
+
end
|
882
|
+
end
|
883
|
+
end
|
884
|
+
end
|