ruby_smb 1.0.3 → 2.0.1
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/enum_registry_key.rb +28 -0
- data/examples/enum_registry_values.rb +30 -0
- data/examples/negotiate.rb +51 -8
- data/examples/pipes.rb +2 -1
- data/examples/read_file_encryption.rb +56 -0
- data/examples/read_registry_key_value.rb +32 -0
- data/lib/ruby_smb.rb +4 -1
- data/lib/ruby_smb/client.rb +233 -22
- data/lib/ruby_smb/client/authentication.rb +70 -33
- data/lib/ruby_smb/client/echo.rb +20 -2
- data/lib/ruby_smb/client/encryption.rb +62 -0
- data/lib/ruby_smb/client/negotiation.rb +172 -24
- data/lib/ruby_smb/client/signing.rb +19 -0
- data/lib/ruby_smb/client/tree_connect.rb +24 -18
- 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 +38 -0
- data/lib/ruby_smb/dcerpc/bind.rb +2 -2
- data/lib/ruby_smb/dcerpc/bind_ack.rb +2 -2
- data/lib/ruby_smb/dcerpc/error.rb +3 -0
- data/lib/ruby_smb/dcerpc/ndr.rb +95 -16
- data/lib/ruby_smb/dcerpc/pdu_header.rb +1 -1
- data/lib/ruby_smb/dcerpc/request.rb +28 -9
- data/lib/ruby_smb/dcerpc/rrp_unicode_string.rb +35 -0
- data/lib/ruby_smb/dcerpc/srvsvc.rb +10 -0
- data/lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all.rb +9 -0
- data/lib/ruby_smb/dcerpc/winreg.rb +340 -0
- data/lib/ruby_smb/dcerpc/winreg/close_key_request.rb +24 -0
- data/lib/ruby_smb/dcerpc/winreg/close_key_response.rb +27 -0
- data/lib/ruby_smb/dcerpc/winreg/enum_key_request.rb +45 -0
- data/lib/ruby_smb/dcerpc/winreg/enum_key_response.rb +42 -0
- data/lib/ruby_smb/dcerpc/winreg/enum_value_request.rb +39 -0
- data/lib/ruby_smb/dcerpc/winreg/enum_value_response.rb +36 -0
- data/lib/ruby_smb/dcerpc/winreg/open_key_request.rb +34 -0
- data/lib/ruby_smb/dcerpc/winreg/open_key_response.rb +25 -0
- data/lib/ruby_smb/dcerpc/winreg/open_root_key_request.rb +43 -0
- data/lib/ruby_smb/dcerpc/winreg/open_root_key_response.rb +35 -0
- data/lib/ruby_smb/dcerpc/winreg/query_info_key_request.rb +27 -0
- data/lib/ruby_smb/dcerpc/winreg/query_info_key_response.rb +40 -0
- data/lib/ruby_smb/dcerpc/winreg/query_value_request.rb +39 -0
- data/lib/ruby_smb/dcerpc/winreg/query_value_response.rb +57 -0
- data/lib/ruby_smb/dcerpc/winreg/regsam.rb +40 -0
- data/lib/ruby_smb/dispatcher/socket.rb +4 -3
- data/lib/ruby_smb/error.rb +68 -2
- data/lib/ruby_smb/generic_packet.rb +33 -4
- data/lib/ruby_smb/smb1/commands.rb +1 -1
- data/lib/ruby_smb/smb1/file.rb +66 -15
- data/lib/ruby_smb/smb1/packet/close_request.rb +2 -5
- data/lib/ruby_smb/smb1/packet/close_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/echo_request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/echo_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/empty_packet.rb +10 -1
- data/lib/ruby_smb/smb1/packet/logoff_request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/logoff_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/negotiate_request.rb +2 -5
- data/lib/ruby_smb/smb1/packet/negotiate_response.rb +3 -7
- data/lib/ruby_smb/smb1/packet/negotiate_response_extended.rb +4 -4
- data/lib/ruby_smb/smb1/packet/nt_create_andx_request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/nt_create_andx_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/nt_trans/create_request.rb +2 -1
- data/lib/ruby_smb/smb1/packet/nt_trans/create_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/nt_trans/request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/nt_trans/response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/read_andx_request.rb +2 -5
- data/lib/ruby_smb/smb1/packet/read_andx_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/session_setup_legacy_request.rb +2 -1
- data/lib/ruby_smb/smb1/packet/session_setup_legacy_response.rb +3 -2
- data/lib/ruby_smb/smb1/packet/session_setup_request.rb +2 -5
- data/lib/ruby_smb/smb1/packet/session_setup_response.rb +3 -2
- data/lib/ruby_smb/smb1/packet/trans/peek_nmpipe_request.rb +0 -1
- data/lib/ruby_smb/smb1/packet/trans/peek_nmpipe_response.rb +3 -2
- data/lib/ruby_smb/smb1/packet/trans/request.rb +2 -5
- data/lib/ruby_smb/smb1/packet/trans/response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans/transact_nmpipe_request.rb +1 -1
- data/lib/ruby_smb/smb1/packet/trans/transact_nmpipe_response.rb +1 -1
- data/lib/ruby_smb/smb1/packet/trans2/find_first2_request.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans2/find_first2_response.rb +8 -2
- data/lib/ruby_smb/smb1/packet/trans2/find_next2_request.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans2/find_next2_response.rb +8 -2
- data/lib/ruby_smb/smb1/packet/trans2/open2_request.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans2/open2_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans2/request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/trans2/request_secondary.rb +2 -4
- data/lib/ruby_smb/smb1/packet/trans2/response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans2/set_file_information_request.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans2/set_file_information_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/tree_connect_request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/tree_connect_response.rb +13 -3
- data/lib/ruby_smb/smb1/packet/tree_disconnect_request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/tree_disconnect_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/write_andx_request.rb +3 -6
- data/lib/ruby_smb/smb1/packet/write_andx_response.rb +2 -1
- data/lib/ruby_smb/smb1/pipe.rb +87 -6
- data/lib/ruby_smb/smb1/tree.rb +50 -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 +103 -25
- 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/close_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/close_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/compression_transform_header.rb +41 -0
- data/lib/ruby_smb/smb2/packet/create_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/create_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/echo_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/echo_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/error_packet.rb +15 -3
- data/lib/ruby_smb/smb2/packet/ioctl_request.rb +2 -5
- data/lib/ruby_smb/smb2/packet/ioctl_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/logoff_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/logoff_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/negotiate_request.rb +51 -17
- data/lib/ruby_smb/smb2/packet/negotiate_response.rb +52 -5
- data/lib/ruby_smb/smb2/packet/query_directory_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/query_directory_response.rb +8 -2
- data/lib/ruby_smb/smb2/packet/read_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/read_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/session_setup_request.rb +2 -5
- data/lib/ruby_smb/smb2/packet/session_setup_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/set_info_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/set_info_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/transform_header.rb +84 -0
- data/lib/ruby_smb/smb2/packet/tree_connect_request.rb +93 -10
- data/lib/ruby_smb/smb2/packet/tree_connect_response.rb +10 -22
- data/lib/ruby_smb/smb2/packet/tree_disconnect_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/tree_disconnect_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/write_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/write_response.rb +2 -1
- data/lib/ruby_smb/smb2/pipe.rb +86 -12
- data/lib/ruby_smb/smb2/smb2_header.rb +1 -1
- data/lib/ruby_smb/smb2/tree.rb +65 -21
- data/lib/ruby_smb/version.rb +1 -1
- data/ruby_smb.gemspec +5 -3
- data/spec/lib/ruby_smb/client_spec.rb +1612 -108
- 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 +410 -0
- data/spec/lib/ruby_smb/dcerpc/request_spec.rb +50 -7
- data/spec/lib/ruby_smb/dcerpc/rrp_unicode_string_spec.rb +98 -0
- data/spec/lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all_spec.rb +13 -0
- data/spec/lib/ruby_smb/dcerpc/srvsvc_spec.rb +60 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/close_key_request_spec.rb +28 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/close_key_response_spec.rb +36 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_request_spec.rb +108 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_response_spec.rb +97 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_request_spec.rb +94 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_response_spec.rb +82 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/open_key_request_spec.rb +74 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/open_key_response_spec.rb +35 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_request_spec.rb +90 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_response_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/query_info_key_request_spec.rb +39 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/query_info_key_response_spec.rb +113 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/query_value_request_spec.rb +88 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/query_value_response_spec.rb +150 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/regsam_spec.rb +32 -0
- data/spec/lib/ruby_smb/dcerpc/winreg_spec.rb +710 -0
- data/spec/lib/ruby_smb/dcerpc_spec.rb +81 -0
- data/spec/lib/ruby_smb/dispatcher/socket_spec.rb +2 -2
- data/spec/lib/ruby_smb/error_spec.rb +59 -0
- data/spec/lib/ruby_smb/generic_packet_spec.rb +52 -4
- data/spec/lib/ruby_smb/smb1/file_spec.rb +191 -2
- data/spec/lib/ruby_smb/smb1/packet/empty_packet_spec.rb +68 -0
- 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/packet/trans2/find_first2_response_spec.rb +11 -2
- data/spec/lib/ruby_smb/smb1/packet/trans2/find_next2_response_spec.rb +11 -2
- data/spec/lib/ruby_smb/smb1/packet/tree_connect_response_spec.rb +40 -0
- data/spec/lib/ruby_smb/smb1/pipe_spec.rb +272 -149
- data/spec/lib/ruby_smb/smb1/tree_spec.rb +44 -7
- 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 +323 -6
- 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 +78 -0
- 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/query_directory_response_spec.rb +8 -0
- 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 -22
- data/spec/lib/ruby_smb/smb2/pipe_spec.rb +286 -149
- data/spec/lib/ruby_smb/smb2/smb2_header_spec.rb +2 -2
- data/spec/lib/ruby_smb/smb2/tree_spec.rb +261 -2
- metadata +191 -83
- metadata.gz.sig +0 -0
- data/lib/ruby_smb/smb1/dcerpc.rb +0 -67
- data/lib/ruby_smb/smb2/dcerpc.rb +0 -70
- data/spec/lib/ruby_smb/smb1/packet/error_packet_spec.rb +0 -37
@@ -8,6 +8,7 @@ RSpec.describe RubySMB::SMB2::Packet::NegotiateRequest do
|
|
8
8
|
it { is_expected.to respond_to :reserved1 }
|
9
9
|
it { is_expected.to respond_to :capabilities }
|
10
10
|
it { is_expected.to respond_to :client_guid }
|
11
|
+
it { is_expected.to respond_to :negotiate_context_info}
|
11
12
|
it { is_expected.to respond_to :client_start_time }
|
12
13
|
it { is_expected.to respond_to :dialects }
|
13
14
|
|
@@ -45,6 +46,11 @@ RSpec.describe RubySMB::SMB2::Packet::NegotiateRequest do
|
|
45
46
|
it 'should be a 16-bit unsigned integer' do
|
46
47
|
expect(packet.dialect_count).to be_a BinData::Uint16le
|
47
48
|
end
|
49
|
+
|
50
|
+
it 'is initially set to the #dialects array size' do
|
51
|
+
packet.dialects = [1,2,3]
|
52
|
+
expect(packet.dialect_count).to eq(3)
|
53
|
+
end
|
48
54
|
end
|
49
55
|
|
50
56
|
describe '#security_mode' do
|
@@ -69,7 +75,65 @@ RSpec.describe RubySMB::SMB2::Packet::NegotiateRequest do
|
|
69
75
|
end
|
70
76
|
end
|
71
77
|
|
78
|
+
describe '#negotiate_context_info' do
|
79
|
+
it 'only exists if the 0x0311 dialect is included' do
|
80
|
+
packet.dialects << 0x0311
|
81
|
+
expect(packet.negotiate_context_info?).to be true
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'does not exist if the 0x0311 dialect is not included' do
|
85
|
+
packet.dialects << 0x0300
|
86
|
+
expect(packet.negotiate_context_info?).to be false
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'should be a Struct field' do
|
90
|
+
expect(packet.negotiate_context_info).to be_a BinData::Struct
|
91
|
+
end
|
92
|
+
|
93
|
+
subject(:struct) do
|
94
|
+
packet.dialects << 0x0311
|
95
|
+
packet.negotiate_context_info
|
96
|
+
end
|
97
|
+
it { is_expected.to respond_to :negotiate_context_offset }
|
98
|
+
it { is_expected.to respond_to :negotiate_context_count }
|
99
|
+
|
100
|
+
describe '#negotiate_context_offset' do
|
101
|
+
it 'should be a 32-bit unsigned integer' do
|
102
|
+
expect(struct.negotiate_context_offset).to be_a BinData::Uint32le
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'is set to the #negotiate_context_list absolute offset' do
|
106
|
+
expect(struct.negotiate_context_offset).to eq(packet.negotiate_context_list.abs_offset)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
describe '#negotiate_context_count' do
|
111
|
+
it 'should be a 16-bit unsigned integer' do
|
112
|
+
expect(struct.negotiate_context_count).to be_a BinData::Uint16le
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'is set to the #negotiate_context_list array size' do
|
116
|
+
nc = RubySMB::SMB2::NegotiateContext.new(
|
117
|
+
context_type: RubySMB::SMB2::NegotiateContext::SMB2_PREAUTH_INTEGRITY_CAPABILITIES
|
118
|
+
)
|
119
|
+
packet.negotiate_context_list << nc
|
120
|
+
packet.negotiate_context_list << nc
|
121
|
+
expect(struct.negotiate_context_count).to eq(2)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
72
126
|
describe '#client_start_time' do
|
127
|
+
it 'does not exist if the 0x0311 dialect is included' do
|
128
|
+
packet.dialects << 0x0311
|
129
|
+
expect(packet.client_start_time?).to be false
|
130
|
+
end
|
131
|
+
|
132
|
+
it 'only exists if the 0x0311 dialect is not included' do
|
133
|
+
packet.dialects << 0x0300
|
134
|
+
expect(packet.client_start_time?).to be true
|
135
|
+
end
|
136
|
+
|
73
137
|
it 'should be a Filetime field' do
|
74
138
|
expect(packet.client_start_time).to be_a RubySMB::Field::FileTime
|
75
139
|
end
|
@@ -85,15 +149,51 @@ RSpec.describe RubySMB::SMB2::Packet::NegotiateRequest do
|
|
85
149
|
end
|
86
150
|
end
|
87
151
|
|
152
|
+
describe '#pad' do
|
153
|
+
it 'only exists if the 0x0311 dialect is included' do
|
154
|
+
packet.dialects << 0x0311
|
155
|
+
expect(packet.pad?).to be true
|
156
|
+
end
|
157
|
+
|
158
|
+
it 'does not exist if the 0x0311 dialect is not included' do
|
159
|
+
packet.dialects << 0x0300
|
160
|
+
expect(packet.pad?).to be false
|
161
|
+
end
|
162
|
+
|
163
|
+
it 'should be a binary string' do
|
164
|
+
expect(packet.pad).to be_a BinData::String
|
165
|
+
end
|
166
|
+
|
167
|
+
it 'should keep #negotiate_context_list 8-byte aligned' do
|
168
|
+
packet.dialects << 0x0311
|
169
|
+
expect(packet.negotiate_context_list.abs_offset % 8).to eq 0
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
describe '#negotiate_context_list' do
|
174
|
+
it 'only exists if the 0x0311 dialect is included' do
|
175
|
+
packet.dialects << 0x0311
|
176
|
+
expect(packet.negotiate_context_list?).to be true
|
177
|
+
end
|
178
|
+
|
179
|
+
it 'does not exist if the 0x0311 dialect is not included' do
|
180
|
+
packet.dialects << 0x0300
|
181
|
+
expect(packet.negotiate_context_list?).to be false
|
182
|
+
end
|
183
|
+
|
184
|
+
it 'is an array field as per the SMB spec' do
|
185
|
+
expect(packet.negotiate_context_list).to be_a BinData::Array
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
88
189
|
describe '#add_dialect' do
|
89
190
|
it 'adds the dialect to the Dialects array' do
|
90
191
|
packet.add_dialect 0x0201
|
91
192
|
expect(packet.dialects).to include(0x0201)
|
92
193
|
end
|
93
194
|
|
94
|
-
it '
|
95
|
-
packet.add_dialect
|
96
|
-
expect(packet.dialect_count).to eq 1
|
195
|
+
it 'raises an ArgumentError exceptionif it is not an Integer' do
|
196
|
+
expect { packet.add_dialect('dialect') }.to raise_error(ArgumentError)
|
97
197
|
end
|
98
198
|
end
|
99
199
|
|
@@ -119,4 +219,39 @@ RSpec.describe RubySMB::SMB2::Packet::NegotiateRequest do
|
|
119
219
|
expect(packet.dialect_count).to eq 3
|
120
220
|
end
|
121
221
|
end
|
222
|
+
|
223
|
+
describe '#add_negotiate_context' do
|
224
|
+
it 'raises an ArgumentError exceptionif it is not a NegotiateContext structure' do
|
225
|
+
expect { packet.add_negotiate_context('nc') }.to raise_error(ArgumentError)
|
226
|
+
end
|
227
|
+
|
228
|
+
it 'updates the NegotiateContext#pad length to make sure the structure is 8-byte aligned' do
|
229
|
+
packet.dialects << 0x0311
|
230
|
+
[
|
231
|
+
RubySMB::SMB2::NegotiateContext::SMB2_PREAUTH_INTEGRITY_CAPABILITIES,
|
232
|
+
RubySMB::SMB2::NegotiateContext::SMB2_ENCRYPTION_CAPABILITIES,
|
233
|
+
RubySMB::SMB2::NegotiateContext::SMB2_COMPRESSION_CAPABILITIES,
|
234
|
+
RubySMB::SMB2::NegotiateContext::SMB2_NETNAME_NEGOTIATE_CONTEXT_ID
|
235
|
+
].each do |context_type|
|
236
|
+
nc = RubySMB::SMB2::NegotiateContext.new(context_type: context_type)
|
237
|
+
packet.add_negotiate_context(nc)
|
238
|
+
expect(packet.negotiate_context_list.last.context_type.abs_offset % 8).to eq 0
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
it 'reads binary data as expected' do
|
244
|
+
data = described_class.new
|
245
|
+
data.set_dialects([0x0202, 0x0210, 0x0311])
|
246
|
+
[
|
247
|
+
RubySMB::SMB2::NegotiateContext::SMB2_PREAUTH_INTEGRITY_CAPABILITIES,
|
248
|
+
RubySMB::SMB2::NegotiateContext::SMB2_ENCRYPTION_CAPABILITIES,
|
249
|
+
RubySMB::SMB2::NegotiateContext::SMB2_COMPRESSION_CAPABILITIES,
|
250
|
+
RubySMB::SMB2::NegotiateContext::SMB2_NETNAME_NEGOTIATE_CONTEXT_ID
|
251
|
+
].each do |context_type|
|
252
|
+
nc = RubySMB::SMB2::NegotiateContext.new(context_type: context_type)
|
253
|
+
data.add_negotiate_context(nc)
|
254
|
+
expect(described_class.read(data.to_binary_s)).to eq(data)
|
255
|
+
end
|
256
|
+
end
|
122
257
|
end
|
@@ -61,12 +61,28 @@ RSpec.describe RubySMB::SMB2::Packet::NegotiateResponse do
|
|
61
61
|
end
|
62
62
|
|
63
63
|
describe '#negotiate_context_count' do
|
64
|
+
it 'only exists if the 0x0311 dialect is included' do
|
65
|
+
packet.dialect_revision = 0x0311
|
66
|
+
expect(packet.negotiate_context_count?).to be true
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'does not exist if the 0x0311 dialect is not included' do
|
70
|
+
packet.dialect_revision = 0x0300
|
71
|
+
expect(packet.negotiate_context_count?).to be false
|
72
|
+
end
|
73
|
+
|
64
74
|
it 'is a 16-bit unsigned integer' do
|
65
75
|
expect(packet.negotiate_context_count).to be_a BinData::Uint16le
|
66
76
|
end
|
67
77
|
|
68
|
-
it '
|
69
|
-
|
78
|
+
it 'is set to the #negotiate_context_list array size' do
|
79
|
+
packet.dialect_revision = 0x0311
|
80
|
+
nc = RubySMB::SMB2::NegotiateContext.new(
|
81
|
+
context_type: RubySMB::SMB2::NegotiateContext::SMB2_PREAUTH_INTEGRITY_CAPABILITIES
|
82
|
+
)
|
83
|
+
packet.negotiate_context_list << nc
|
84
|
+
packet.negotiate_context_list << nc
|
85
|
+
expect(packet.negotiate_context_count).to eq(2)
|
70
86
|
end
|
71
87
|
end
|
72
88
|
|
@@ -134,6 +150,16 @@ RSpec.describe RubySMB::SMB2::Packet::NegotiateResponse do
|
|
134
150
|
end
|
135
151
|
|
136
152
|
describe '#negotiate_context_offset' do
|
153
|
+
it 'only exists if the 0x0311 dialect is included' do
|
154
|
+
packet.dialect_revision = 0x0311
|
155
|
+
expect(packet.negotiate_context_offset?).to be true
|
156
|
+
end
|
157
|
+
|
158
|
+
it 'does not exist if the 0x0311 dialect is not included' do
|
159
|
+
packet.dialect_revision = 0x0300
|
160
|
+
expect(packet.negotiate_context_offset?).to be false
|
161
|
+
end
|
162
|
+
|
137
163
|
it 'is a 32-bit unsigned integer' do
|
138
164
|
expect(packet.negotiate_context_offset).to be_a BinData::Uint32le
|
139
165
|
end
|
@@ -144,4 +170,96 @@ RSpec.describe RubySMB::SMB2::Packet::NegotiateResponse do
|
|
144
170
|
expect(packet.security_buffer).to be_a BinData::String
|
145
171
|
end
|
146
172
|
end
|
173
|
+
|
174
|
+
describe '#pad' do
|
175
|
+
it 'only exists if the 0x0311 dialect is included' do
|
176
|
+
packet.dialect_revision = 0x0311
|
177
|
+
expect(packet.pad?).to be true
|
178
|
+
end
|
179
|
+
|
180
|
+
it 'does not exist if the 0x0311 dialect is not included' do
|
181
|
+
packet.dialect_revision = 0x0300
|
182
|
+
expect(packet.pad?).to be false
|
183
|
+
end
|
184
|
+
|
185
|
+
it 'should be a binary string' do
|
186
|
+
expect(packet.pad).to be_a BinData::String
|
187
|
+
end
|
188
|
+
|
189
|
+
it 'should keep #negotiate_context_list 8-byte aligned' do
|
190
|
+
packet.dialect_revision = 0x0311
|
191
|
+
expect(packet.negotiate_context_list.abs_offset % 8).to eq 0
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
describe '#negotiate_context_list' do
|
196
|
+
it 'only exists if the 0x0311 dialect is included' do
|
197
|
+
packet.dialect_revision = 0x0311
|
198
|
+
expect(packet.negotiate_context_list?).to be true
|
199
|
+
end
|
200
|
+
|
201
|
+
it 'does not exist if the 0x0311 dialect is not included' do
|
202
|
+
packet.dialect_revision = 0x0300
|
203
|
+
expect(packet.negotiate_context_list?).to be false
|
204
|
+
end
|
205
|
+
|
206
|
+
it 'is an array field as per the SMB spec' do
|
207
|
+
expect(packet.negotiate_context_list).to be_a BinData::Array
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
describe '#find_negotiate_context' do
|
212
|
+
before :example do
|
213
|
+
packet.add_negotiate_context(
|
214
|
+
RubySMB::SMB2::NegotiateContext.new(context_type: RubySMB::SMB2::NegotiateContext::SMB2_PREAUTH_INTEGRITY_CAPABILITIES)
|
215
|
+
)
|
216
|
+
packet.add_negotiate_context(
|
217
|
+
RubySMB::SMB2::NegotiateContext.new(context_type: RubySMB::SMB2::NegotiateContext::SMB2_ENCRYPTION_CAPABILITIES)
|
218
|
+
)
|
219
|
+
end
|
220
|
+
|
221
|
+
it 'returns the expected Negotiate Context structure' do
|
222
|
+
expect(packet.find_negotiate_context(RubySMB::SMB2::NegotiateContext::SMB2_ENCRYPTION_CAPABILITIES)).to eq(packet.negotiate_context_list[1])
|
223
|
+
end
|
224
|
+
|
225
|
+
it 'returns nil if the Negotiate Context structure is not found' do
|
226
|
+
expect(packet.find_negotiate_context(10)).to be nil
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
describe '#add_negotiate_context' do
|
231
|
+
it 'raises an ArgumentError exception if it is not a NegotiateContext structure' do
|
232
|
+
expect { packet.add_negotiate_context('nc') }.to raise_error(ArgumentError)
|
233
|
+
end
|
234
|
+
|
235
|
+
it 'updates the NegotiateContext#pad length to make sure the structure is 8-byte aligned' do
|
236
|
+
packet.dialect_revision = 0x0311
|
237
|
+
[
|
238
|
+
RubySMB::SMB2::NegotiateContext::SMB2_PREAUTH_INTEGRITY_CAPABILITIES,
|
239
|
+
RubySMB::SMB2::NegotiateContext::SMB2_ENCRYPTION_CAPABILITIES,
|
240
|
+
RubySMB::SMB2::NegotiateContext::SMB2_COMPRESSION_CAPABILITIES,
|
241
|
+
RubySMB::SMB2::NegotiateContext::SMB2_NETNAME_NEGOTIATE_CONTEXT_ID
|
242
|
+
].each do |context_type|
|
243
|
+
nc = RubySMB::SMB2::NegotiateContext.new(context_type: context_type)
|
244
|
+
packet.add_negotiate_context(nc)
|
245
|
+
expect(packet.negotiate_context_list.last.context_type.abs_offset % 8).to eq 0
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
it 'reads binary data as expected' do
|
251
|
+
data = described_class.new
|
252
|
+
data.dialect_revision = 0x0311
|
253
|
+
data.security_buffer = 'security buf test'
|
254
|
+
[
|
255
|
+
RubySMB::SMB2::NegotiateContext::SMB2_PREAUTH_INTEGRITY_CAPABILITIES,
|
256
|
+
RubySMB::SMB2::NegotiateContext::SMB2_ENCRYPTION_CAPABILITIES,
|
257
|
+
RubySMB::SMB2::NegotiateContext::SMB2_COMPRESSION_CAPABILITIES,
|
258
|
+
RubySMB::SMB2::NegotiateContext::SMB2_NETNAME_NEGOTIATE_CONTEXT_ID
|
259
|
+
].each do |context_type|
|
260
|
+
nc = RubySMB::SMB2::NegotiateContext.new(context_type: context_type)
|
261
|
+
data.add_negotiate_context(nc)
|
262
|
+
expect(described_class.read(data.to_binary_s)).to eq(data)
|
263
|
+
end
|
264
|
+
end
|
147
265
|
end
|
@@ -60,5 +60,13 @@ RSpec.describe RubySMB::SMB2::Packet::QueryDirectoryResponse do
|
|
60
60
|
packet.buffer = names_blob
|
61
61
|
expect(packet.results(RubySMB::Fscc::FileInformation::FileNamesInformation)).to eq names_array
|
62
62
|
end
|
63
|
+
|
64
|
+
context 'when the File Information is not a valid' do
|
65
|
+
it 'raises an InvalidPacket exception' do
|
66
|
+
packet.buffer = names_blob
|
67
|
+
allow(RubySMB::Fscc::FileInformation::FileNamesInformation).to receive(:read).and_raise(IOError)
|
68
|
+
expect { packet.results(RubySMB::Fscc::FileInformation::FileNamesInformation) }.to raise_error(RubySMB::Error::InvalidPacket)
|
69
|
+
end
|
70
|
+
end
|
63
71
|
end
|
64
72
|
end
|
@@ -0,0 +1,220 @@
|
|
1
|
+
RSpec.describe RubySMB::SMB2::Packet::TransformHeader do
|
2
|
+
subject(:packet) { described_class.new }
|
3
|
+
|
4
|
+
it { is_expected.to respond_to :protocol }
|
5
|
+
it { is_expected.to respond_to :signature }
|
6
|
+
it { is_expected.to respond_to :nonce }
|
7
|
+
it { is_expected.to respond_to :original_message_size }
|
8
|
+
it { is_expected.to respond_to :flags }
|
9
|
+
it { is_expected.to respond_to :session_id }
|
10
|
+
it { is_expected.to respond_to :encrypted_data }
|
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 '#protocol' do
|
17
|
+
it 'is a 32-bit field' do
|
18
|
+
expect(packet.protocol).to be_a BinData::Bit32
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'has an initial value of 0xFD534D42' do
|
22
|
+
expect(packet.protocol).to eq(0xFD534D42)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '#signature' do
|
27
|
+
it 'is a String' do
|
28
|
+
expect(packet.signature).to be_a BinData::String
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe '#nonce' do
|
33
|
+
it 'is a String' do
|
34
|
+
expect(packet.nonce).to be_a BinData::String
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe '#original_message_size ' do
|
39
|
+
it 'is a 32-bit unsigned integer' do
|
40
|
+
expect(packet.original_message_size).to be_a BinData::Uint32le
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe '#flags' do
|
45
|
+
it 'is a 16-bit unsigned integer' do
|
46
|
+
expect(packet.flags).to be_a BinData::Uint16le
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe '#session_id' do
|
51
|
+
it 'is a 64-bit unsigned integer' do
|
52
|
+
expect(packet.session_id).to be_a BinData::Uint64le
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe '#encrypted_data' do
|
57
|
+
it 'is an Array' do
|
58
|
+
expect(packet.encrypted_data).to be_a BinData::Array
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe '#decrypt' do
|
63
|
+
let(:key) { "\x56\x89\xd1\xbb\xf7\x45\xc0\xb6\x68\x81\x07\xe4\x7d\x35\xaf\xd3".b }
|
64
|
+
let(:data) { 'data'.b }
|
65
|
+
before :example do
|
66
|
+
packet.original_message_size = data.length
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'raises the expected exception if the given algorithm is invalid' do
|
70
|
+
expect { packet.decrypt(key, algorithm: 'RC4') }.to raise_error(
|
71
|
+
RubySMB::Error::EncryptionError,
|
72
|
+
'Error while decrypting with \'RC4\' (ArgumentError: Invalid algorithm, must be either AES-128-CCM or AES-128-GCM)'
|
73
|
+
)
|
74
|
+
end
|
75
|
+
|
76
|
+
context 'with AES-128-GCM algorithm (default)' do
|
77
|
+
before :example do
|
78
|
+
begin
|
79
|
+
OpenSSL::Cipher.new('AES-128-GCM')
|
80
|
+
rescue
|
81
|
+
skip(
|
82
|
+
"This test cannot be run since the version of OpenSSL the ruby "\
|
83
|
+
"OpenSSL extension was built with (#{OpenSSL::OPENSSL_VERSION}) "\
|
84
|
+
"does not support AES-128-GCM cipher")
|
85
|
+
end
|
86
|
+
packet.encrypted_data = "\x06\x45\x16\x36".bytes
|
87
|
+
packet.signature = "\x63\xb2\xf9\xe0\xb7\x43\xdb\xaf\x26\x8e\xd7\x42\xd3\xb2\xde\x0d"
|
88
|
+
packet.nonce = "\xe1\xb0\xa7\x20\xd9\xd9\x69\x3c\x79\xd0\x9c\x53\x00\x00\x00\x00"
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'generates a cipher using OpenSSL::Cipher' do
|
92
|
+
expect(OpenSSL::Cipher).to receive(:new).with('AES-128-GCM').and_call_original
|
93
|
+
packet.decrypt(key)
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'returns the expected decrypted string' do
|
97
|
+
expect(packet.decrypt(key)).to eq(data)
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'raises the expected exception if an error occurs' do
|
101
|
+
allow(OpenSSL::Cipher).to receive(:new).and_raise(
|
102
|
+
RuntimeError.new('unsupported cipher algorithm (AES-128-GCM)'))
|
103
|
+
expect { packet.decrypt(key) }.to raise_error(
|
104
|
+
RubySMB::Error::EncryptionError,
|
105
|
+
'Error while decrypting with \'AES-128-GCM\' (RuntimeError: unsupported cipher algorithm (AES-128-GCM))'
|
106
|
+
)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
context 'with AES-128-CCM algorithm' do
|
111
|
+
before :example do
|
112
|
+
packet.encrypted_data = "\xf0\x05\x61\x91".bytes
|
113
|
+
packet.signature = "\xdd\x51\x9a\xc5\x6d\x38\x68\xdc\x36\x89\xb8\x99\xd8\x4a\xb8\x4a".b
|
114
|
+
packet.nonce = "\x8a\x6e\x2a\x87\x11\x61\x85\xd2\x15\x69\xf7\x00\x00\x00\x00\x00".b
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'generates a cipher using OpenSSL::CCM' do
|
118
|
+
expect(OpenSSL::CCM).to receive(:new).with('AES', key, 16).and_call_original
|
119
|
+
packet.decrypt(key, algorithm: 'AES-128-CCM')
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'returns the expected decrypted string' do
|
123
|
+
expect(packet.decrypt(key, algorithm: 'AES-128-CCM')).to eq(data)
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'raises the expected exception if an error occurs' do
|
127
|
+
allow(OpenSSL::CCM).to receive(:new).and_raise(
|
128
|
+
OpenSSL::CCMError.new('unsupported cipher algorithm (AES-128-CCM)'))
|
129
|
+
expect { packet.decrypt(key, algorithm: 'AES-128-CCM') }.to raise_error(
|
130
|
+
RubySMB::Error::EncryptionError,
|
131
|
+
'Error while decrypting with \'AES-128-CCM\' (OpenSSL::CCMError: unsupported cipher algorithm (AES-128-CCM))'
|
132
|
+
)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
describe '#encrypt' do
|
138
|
+
let(:key) { "\x56\x89\xd1\xbb\xf7\x45\xc0\xb6\x68\x81\x07\xe4\x7d\x35\xaf\xd3".b }
|
139
|
+
let(:struct) { RubySMB::SMB2::Packet::TreeConnectRequest.new }
|
140
|
+
|
141
|
+
it 'raises the expected exception if the given algorithm is invalid' do
|
142
|
+
expect { packet.encrypt(struct, key, algorithm: 'RC4') }.to raise_error(
|
143
|
+
RubySMB::Error::EncryptionError,
|
144
|
+
'Error while encrypting with \'RC4\' (ArgumentError: Invalid algorithm, must be either AES-128-CCM or AES-128-GCM)'
|
145
|
+
)
|
146
|
+
end
|
147
|
+
|
148
|
+
context 'with AES-128-GCM algorithm (default)' do
|
149
|
+
before :example do
|
150
|
+
begin
|
151
|
+
OpenSSL::Cipher.new('AES-128-GCM')
|
152
|
+
rescue
|
153
|
+
skip(
|
154
|
+
"This test cannot be run since the version of OpenSSL the ruby "\
|
155
|
+
"OpenSSL extension was built with (#{OpenSSL::OPENSSL_VERSION}) "\
|
156
|
+
"does not support AES-128-GCM cipher")
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
it 'generates a cipher using OpenSSL::Cipher' do
|
161
|
+
expect(OpenSSL::Cipher).to receive(:new).with('AES-128-GCM').and_call_original
|
162
|
+
packet.encrypt(struct, key)
|
163
|
+
end
|
164
|
+
|
165
|
+
it 'encrypts a BinData structure' do
|
166
|
+
packet.encrypt(struct, key)
|
167
|
+
expect(packet.decrypt(key)).to eq(struct.to_binary_s)
|
168
|
+
end
|
169
|
+
|
170
|
+
it 'encrypts a string' do
|
171
|
+
packet.encrypt('data', key)
|
172
|
+
expect(packet.decrypt(key)).to eq('data')
|
173
|
+
end
|
174
|
+
|
175
|
+
it 'raises the expected exception if an error occurs' do
|
176
|
+
allow(OpenSSL::Cipher).to receive(:new).and_raise(
|
177
|
+
RuntimeError.new('unsupported cipher algorithm (AES-128-GCM)'))
|
178
|
+
expect { packet.encrypt('data', key) }.to raise_error(
|
179
|
+
RubySMB::Error::EncryptionError,
|
180
|
+
'Error while encrypting with \'AES-128-GCM\' (RuntimeError: unsupported cipher algorithm (AES-128-GCM))'
|
181
|
+
)
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
context 'with AES-128-CCM algorithm' do
|
186
|
+
it 'generates a cipher using OpenSSL::CCM' do
|
187
|
+
expect(OpenSSL::CCM).to receive(:new).with('AES', key, 16).and_call_original
|
188
|
+
packet.encrypt(struct, key, algorithm: 'AES-128-CCM')
|
189
|
+
end
|
190
|
+
|
191
|
+
it 'encrypts a BinData structure' do
|
192
|
+
packet.encrypt(struct, key, algorithm: 'AES-128-CCM')
|
193
|
+
expect(packet.decrypt(key, algorithm: 'AES-128-CCM')).to eq(struct.to_binary_s)
|
194
|
+
end
|
195
|
+
|
196
|
+
it 'encrypts a string' do
|
197
|
+
packet.encrypt('data', key, algorithm: 'AES-128-CCM')
|
198
|
+
expect(packet.decrypt(key, algorithm: 'AES-128-CCM')).to eq('data')
|
199
|
+
end
|
200
|
+
|
201
|
+
it 'raises the expected exception if an error occurs' do
|
202
|
+
allow(OpenSSL::CCM).to receive(:new).and_raise(
|
203
|
+
OpenSSL::CCMError.new('unsupported cipher algorithm (AES-128-CCM)'))
|
204
|
+
expect { packet.encrypt('data', key, algorithm: 'AES-128-CCM') }.to raise_error(
|
205
|
+
RubySMB::Error::EncryptionError,
|
206
|
+
'Error while encrypting with \'AES-128-CCM\' (OpenSSL::CCMError: unsupported cipher algorithm (AES-128-CCM))'
|
207
|
+
)
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
it 'reads binary data as expected' do
|
213
|
+
data = described_class.new
|
214
|
+
key = "\x56\x89\xd1\xbb\xf7\x45\xc0\xb6\x68\x81\x07\xe4\x7d\x35\xaf\xd3".b
|
215
|
+
struct = RubySMB::SMB2::Packet::TreeConnectRequest.new
|
216
|
+
data.encrypt(struct, key, algorithm: 'AES-128-CCM')
|
217
|
+
expect(described_class.read(data.to_binary_s)).to eq(data)
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|