ruby_smb 0.0.21 → 0.0.22
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/examples/net_share_enum_all.rb +5 -2
- data/lib/ruby_smb.rb +1 -1
- data/lib/ruby_smb/client.rb +4 -35
- data/lib/ruby_smb/dcerpc.rb +7 -22
- data/lib/ruby_smb/dcerpc/bind.rb +30 -36
- data/lib/ruby_smb/dcerpc/bind_ack.rb +72 -0
- data/lib/ruby_smb/dcerpc/error.rb +15 -0
- data/lib/ruby_smb/dcerpc/ndr.rb +31 -30
- data/lib/ruby_smb/dcerpc/p_syntax_id_t.rb +11 -0
- data/lib/ruby_smb/dcerpc/pdu_header.rb +29 -0
- data/lib/ruby_smb/dcerpc/ptypes.rb +26 -0
- data/lib/ruby_smb/dcerpc/request.rb +17 -30
- data/lib/ruby_smb/dcerpc/response.rb +15 -34
- data/lib/ruby_smb/dcerpc/srvsvc.rb +5 -7
- data/lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all.rb +8 -4
- data/lib/ruby_smb/dcerpc/uuid.rb +31 -13
- data/lib/ruby_smb/smb1/bit_field.rb +0 -1
- data/lib/ruby_smb/smb1/bit_field/trans_flags.rb +3 -2
- data/lib/ruby_smb/smb1/data_block.rb +5 -0
- data/lib/ruby_smb/smb1/dcerpc.rb +67 -0
- data/lib/ruby_smb/smb1/packet.rb +1 -0
- data/lib/ruby_smb/smb1/packet/trans.rb +7 -1
- data/lib/ruby_smb/smb1/packet/trans/data_block.rb +19 -7
- data/lib/ruby_smb/smb1/packet/trans/request.rb +36 -25
- data/lib/ruby_smb/smb1/packet/trans/response.rb +22 -21
- data/lib/ruby_smb/smb1/packet/trans/subcommands.rb +1 -0
- data/lib/ruby_smb/smb1/packet/trans/transact_nmpipe_request.rb +61 -0
- data/lib/ruby_smb/smb1/packet/trans/transact_nmpipe_response.rb +44 -0
- data/lib/ruby_smb/smb1/packet/trans2/request.rb +1 -1
- data/lib/ruby_smb/smb1/pipe.rb +3 -0
- data/lib/ruby_smb/smb2/dcerpc.rb +68 -0
- data/lib/ruby_smb/smb2/pipe.rb +3 -0
- data/lib/ruby_smb/version.rb +1 -1
- data/spec/lib/ruby_smb/client_spec.rb +53 -6
- data/spec/lib/ruby_smb/dcerpc/bind_ack_spec.rb +224 -0
- data/spec/lib/ruby_smb/dcerpc/bind_spec.rb +255 -7
- data/spec/lib/ruby_smb/dcerpc/p_syntax_id_t_spec.rb +31 -0
- data/spec/lib/ruby_smb/dcerpc/pdu_header_spec.rb +84 -0
- data/spec/lib/ruby_smb/dcerpc/request_spec.rb +106 -13
- data/spec/lib/ruby_smb/dcerpc/response_spec.rb +89 -8
- data/spec/lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all_spec.rb +176 -0
- data/spec/lib/ruby_smb/dcerpc/uuid_spec.rb +97 -1
- data/spec/lib/ruby_smb/smb1/data_block_spec.rb +43 -3
- data/spec/lib/ruby_smb/smb1/packet/trans/data_block_spec.rb +137 -0
- data/spec/lib/ruby_smb/smb1/packet/trans/request_spec.rb +239 -13
- data/spec/lib/ruby_smb/smb1/packet/trans/response_spec.rb +122 -13
- data/spec/lib/ruby_smb/smb1/packet/trans/transact_nmpipe_request_spec.rb +254 -0
- data/spec/lib/ruby_smb/smb1/packet/trans/transact_nmpipe_response_spec.rb +122 -0
- data/spec/lib/ruby_smb/smb1/packet/trans2/request_spec.rb +2 -2
- data/spec/lib/ruby_smb/smb1/pipe_spec.rb +199 -1
- data/spec/lib/ruby_smb/smb2/file_spec.rb +2 -1
- data/spec/lib/ruby_smb/smb2/pipe_spec.rb +196 -1
- metadata +25 -10
- metadata.gz.sig +0 -0
- data/lib/ruby_smb/dcerpc/handle.rb +0 -60
- data/lib/ruby_smb/smb1/bit_field/trans2_flags.rb +0 -15
- data/spec/lib/ruby_smb/dcerpc/handle_spec.rb +0 -31
- data/spec/lib/ruby_smb/dcerpc/srvsvc_spec.rb +0 -13
- data/spec/lib/ruby_smb/smb1/bit_field/trans2_flags_spec.rb +0 -26
@@ -0,0 +1,254 @@
|
|
1
|
+
RSpec.describe RubySMB::SMB1::Packet::Trans::TransactNmpipeRequest do
|
2
|
+
subject(:packet) { described_class.new }
|
3
|
+
|
4
|
+
describe '#smb_header' do
|
5
|
+
subject(:header) { packet.smb_header }
|
6
|
+
|
7
|
+
it 'is a standard SMB Header' do
|
8
|
+
expect(header).to be_a RubySMB::SMB1::SMBHeader
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should have the command set to SMB_COM_TRANSACTION' do
|
12
|
+
expect(header.command).to eq RubySMB::SMB1::Commands::SMB_COM_TRANSACTION
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should not have the response flag set' do
|
16
|
+
expect(header.flags.reply).to eq 0
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '#parameter_block' do
|
21
|
+
subject(:parameter_block) { packet.parameter_block }
|
22
|
+
|
23
|
+
it 'is a Packet Trans Request ParameterBlock' do
|
24
|
+
expect(parameter_block).to be_a RubySMB::SMB1::Packet::Trans::Request::ParameterBlock
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '#total_parameter_count' do
|
28
|
+
it 'is set to 0x0000' do
|
29
|
+
expect(parameter_block.total_parameter_count).to eq(0x0000)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe '#total_data_count' do
|
34
|
+
it 'has a default value equal to #data_count' do
|
35
|
+
parameter_block.data_count = 5
|
36
|
+
expect(parameter_block.total_data_count).to eq 5
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe '#max_parameter_count' do
|
41
|
+
it 'is set to 0x0000' do
|
42
|
+
expect(parameter_block.max_parameter_count).to eq(0x0000)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe '#max_setup_count' do
|
47
|
+
it 'is set to 0x00' do
|
48
|
+
expect(parameter_block.max_setup_count).to eq(0x00)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe '#flags' do
|
53
|
+
it 'is set to 0x0000' do
|
54
|
+
expect(parameter_block.flags.to_binary_s.to_i).to eq(0x0000)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe '#timeout' do
|
59
|
+
it 'is set to 0x00000000' do
|
60
|
+
expect(parameter_block.timeout).to eq 0x00000000
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe '#parameter_count' do
|
65
|
+
it 'is set to 0x0000' do
|
66
|
+
expect(parameter_block.parameter_count).to eq(0x0000)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe '#data_count' do
|
71
|
+
it 'is set to the number of data bytes to be written to the named pipe' do
|
72
|
+
packet.data_block.trans_data.write_data = "\x00\x01\x02\x03"
|
73
|
+
expect(parameter_block.data_count).to eq 4
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe '#setup_count' do
|
78
|
+
it 'is set to 2' do
|
79
|
+
expect(parameter_block.setup_count).to eq(2)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe '#setup' do
|
84
|
+
it 'includes the TRANSACT_NMPIPE subcommand code' do
|
85
|
+
expect(parameter_block.setup[0]).to eq(RubySMB::SMB1::Packet::Trans::Subcommands::TRANSACT_NMPIPE)
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'includes the FID set to 0x0000 by default' do
|
89
|
+
expect(parameter_block.setup[1]).to eq(0x0000)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
describe '#data_block' do
|
95
|
+
subject(:data_block) { packet.data_block }
|
96
|
+
|
97
|
+
it 'is a standard DataBlock' do
|
98
|
+
expect(data_block).to be_a RubySMB::SMB1::DataBlock
|
99
|
+
end
|
100
|
+
|
101
|
+
it { is_expected.to respond_to :name }
|
102
|
+
it { is_expected.to respond_to :trans_parameters }
|
103
|
+
it { is_expected.to respond_to :trans_data }
|
104
|
+
|
105
|
+
describe '#pad_name' do
|
106
|
+
context 'when the UNICODE flag is not set in the Flags2 field of the SMB Header' do
|
107
|
+
it 'does not exists' do
|
108
|
+
expect(data_block).to_not be_pad_name
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
context 'when the UNICODE flag is set in the Flags2 field of the SMB Header' do
|
113
|
+
before :example do
|
114
|
+
packet.smb_header.flags2.unicode = 1
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'exists' do
|
118
|
+
expect(data_block).to be_pad_name
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'is one null byte when #name is not 2-byte aligned' do
|
122
|
+
expect(data_block.pad_name).to eq("\x00")
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'should keep #name 2-byte aligned' do
|
126
|
+
expect(data_block.name.abs_offset % 2).to eq 0
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
describe '#name' do
|
132
|
+
context 'when the UNICODE flag is not set in the Flags2 field of the SMB Header' do
|
133
|
+
it 'is a Stringz' do
|
134
|
+
expect(data_block.name.current_choice).to be_a BinData::Stringz
|
135
|
+
end
|
136
|
+
|
137
|
+
it 'is ASCII encoded' do
|
138
|
+
expect(data_block.name.encoding.name).to eq("ASCII-8BIT")
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'is set to "\\PIPE\\\x00" by default' do
|
142
|
+
expect(data_block.name.to_binary_s).to eq("\\PIPE\\\x00")
|
143
|
+
end
|
144
|
+
|
145
|
+
it 'adds a NULL terminator to the string' do
|
146
|
+
str = "test"
|
147
|
+
data_block.name = str
|
148
|
+
expect(data_block.name.to_binary_s).to eq(str + "\x00")
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
context 'when the UNICODE flag is set in the Flags2 field of the SMB Header' do
|
153
|
+
before :example do
|
154
|
+
packet.smb_header.flags2.unicode = 1
|
155
|
+
end
|
156
|
+
|
157
|
+
it 'is a Stringz16' do
|
158
|
+
expect(data_block.name.current_choice).to be_a RubySMB::Field::Stringz16
|
159
|
+
end
|
160
|
+
|
161
|
+
it 'is UTF-16LE encoded' do
|
162
|
+
expect(data_block.name.encoding.name).to eq("UTF-16LE")
|
163
|
+
end
|
164
|
+
|
165
|
+
it 'is set to the null terminated unicode string "\\PIPE\\" by default' do
|
166
|
+
binary_str = "\\PIPE\\\x00".encode('utf-16le').force_encoding('ASCII')
|
167
|
+
expect(data_block.name.to_binary_s).to eq(binary_str)
|
168
|
+
end
|
169
|
+
|
170
|
+
it 'adds a NULL terminator to the string' do
|
171
|
+
str = "test"
|
172
|
+
data_block.name = str
|
173
|
+
binary_str = (str + "\x00").encode('utf-16le').force_encoding('ASCII')
|
174
|
+
expect(data_block.name.to_binary_s).to eq(binary_str)
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
context 'when switching from ASCII to UNICODE' do
|
179
|
+
it 'encodes the same string to UNICODE' do
|
180
|
+
packet = RubySMB::SMB1::Packet::Trans::Request.new
|
181
|
+
data_block = packet.data_block
|
182
|
+
|
183
|
+
str = "test"
|
184
|
+
data_block.name = str
|
185
|
+
expect(data_block.name.to_binary_s).to eq(str + "\x00")
|
186
|
+
packet.smb_header.flags2.unicode = 1
|
187
|
+
binary_str = (str + "\x00").encode('utf-16le').force_encoding('ASCII')
|
188
|
+
expect(data_block.name.to_binary_s).to eq(binary_str)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
describe '#trans_parameters' do
|
194
|
+
it 'is a String' do
|
195
|
+
expect(data_block.trans_parameters).to be_a BinData::String
|
196
|
+
end
|
197
|
+
|
198
|
+
it 'reads the number of bytes specified in parameter_block parameter_count field' do
|
199
|
+
packet.parameter_block.parameter_count = 3
|
200
|
+
data_block.trans_parameters.read("ABCDEF")
|
201
|
+
expect(data_block.trans_parameters).to eq("ABC")
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
describe '#trans_data' do
|
206
|
+
subject(:data) { data_block.trans_data }
|
207
|
+
|
208
|
+
it { is_expected.to respond_to :write_data }
|
209
|
+
|
210
|
+
describe '#write_data' do
|
211
|
+
it 'is a String' do
|
212
|
+
expect(data.write_data).to be_a BinData::String
|
213
|
+
end
|
214
|
+
|
215
|
+
it 'reads the number of bytes specified in parameter_block parameter_count field' do
|
216
|
+
packet.parameter_block.data_count = 3
|
217
|
+
data.write_data.read("ABCDEF")
|
218
|
+
expect(data.write_data).to eq("ABC")
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
describe '#pad1' do
|
224
|
+
it 'should keep #trans_parameters 4-byte aligned' do
|
225
|
+
expect(data_block.trans_parameters.abs_offset % 4).to eq 0
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
describe '#pad2' do
|
230
|
+
it 'should keep #trans_data 4-byte aligned' do
|
231
|
+
data_block.trans_parameters = 'a'
|
232
|
+
expect(data_block.trans_data.abs_offset % 4).to eq 0
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
describe '#set_fid' do
|
238
|
+
it 'sets the FID in the parameter_block #setup field' do
|
239
|
+
fid = 0xAABB
|
240
|
+
packet.set_fid(fid)
|
241
|
+
expect(packet.parameter_block.setup[1]).to eq(fid)
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
it 'reads its own binary representation and output the same packet' do
|
246
|
+
# Adding some data to the ParameterBlock and DataBlock to make sure
|
247
|
+
# paddings and lengths are handled correctly
|
248
|
+
packet.set_fid(0xAABB)
|
249
|
+
packet.data_block.trans_data.write_data = 'a'
|
250
|
+
binary = packet.to_binary_s
|
251
|
+
expect(described_class.read(binary)).to eq(packet)
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
@@ -0,0 +1,122 @@
|
|
1
|
+
RSpec.describe RubySMB::SMB1::Packet::Trans::TransactNmpipeResponse do
|
2
|
+
subject(:packet) { described_class.new }
|
3
|
+
|
4
|
+
describe '#smb_header' do
|
5
|
+
subject(:header) { packet.smb_header }
|
6
|
+
|
7
|
+
it 'is a standard SMB Header' do
|
8
|
+
expect(header).to be_a RubySMB::SMB1::SMBHeader
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should have the command set to SMB_COM_TRANSACTION' do
|
12
|
+
expect(header.command).to eq RubySMB::SMB1::Commands::SMB_COM_TRANSACTION
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should have the response flag set' do
|
16
|
+
expect(header.flags.reply).to eq 1
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '#parameter_block' do
|
21
|
+
subject(:parameter_block) { packet.parameter_block }
|
22
|
+
|
23
|
+
it 'is a Packet Trans Response ParameterBlock' do
|
24
|
+
expect(parameter_block).to be_a RubySMB::SMB1::Packet::Trans::Response::ParameterBlock
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '#total_parameter_count' do
|
28
|
+
it 'is set to 0x0000' do
|
29
|
+
expect(parameter_block.total_parameter_count).to eq(0x0000)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe '#total_data_count' do
|
34
|
+
it 'has a default value equal to #data_count' do
|
35
|
+
parameter_block.data_count = 5
|
36
|
+
expect(parameter_block.total_data_count).to eq 5
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe '#parameter_count' do
|
41
|
+
it 'is set to 0x0000' do
|
42
|
+
expect(parameter_block.parameter_count).to eq(0x0000)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe '#data_count' do
|
47
|
+
it 'is set to the number of data bytes read from the named pipe' do
|
48
|
+
packet.data_block.trans_data.read_data = "\x00\x01\x02\x03"
|
49
|
+
expect(parameter_block.data_count).to eq 4
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe '#setup_count' do
|
54
|
+
it 'is set to 0' do
|
55
|
+
expect(parameter_block.setup_count).to eq(0)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe '#data_block' do
|
61
|
+
subject(:data_block) { packet.data_block }
|
62
|
+
|
63
|
+
it 'is a standard DataBlock' do
|
64
|
+
expect(data_block).to be_a RubySMB::SMB1::DataBlock
|
65
|
+
end
|
66
|
+
|
67
|
+
it { is_expected.to respond_to :trans_parameters }
|
68
|
+
it { is_expected.to respond_to :trans_data }
|
69
|
+
|
70
|
+
describe '#trans_parameters' do
|
71
|
+
it 'is a String' do
|
72
|
+
expect(data_block.trans_parameters).to be_a BinData::String
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'reads the number of bytes specified in parameter_block parameter_count field' do
|
76
|
+
packet.parameter_block.parameter_count = 3
|
77
|
+
data_block.trans_parameters.read("ABCDEF")
|
78
|
+
expect(data_block.trans_parameters).to eq("ABC")
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe '#trans_data' do
|
83
|
+
subject(:data) { data_block.trans_data }
|
84
|
+
|
85
|
+
it { is_expected.to respond_to :read_data }
|
86
|
+
|
87
|
+
describe '#read_data' do
|
88
|
+
it 'is a String' do
|
89
|
+
expect(data.read_data).to be_a BinData::String
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'reads the number of bytes specified in parameter_block parameter_count field' do
|
93
|
+
packet.parameter_block.data_count = 3
|
94
|
+
data.read_data.read("ABCDEF")
|
95
|
+
expect(data.read_data).to eq("ABC")
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
describe '#pad1' do
|
101
|
+
it 'should keep #trans_parameters 4-byte aligned' do
|
102
|
+
expect(data_block.trans_parameters.abs_offset % 4).to eq 0
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
describe '#pad2' do
|
107
|
+
it 'should keep #trans_data 4-byte aligned' do
|
108
|
+
data_block.trans_parameters = 'a'
|
109
|
+
expect(data_block.trans_data.abs_offset % 4).to eq 0
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'reads its own binary representation and output the same packet' do
|
115
|
+
# Adding some data to the DataBlock to make sure
|
116
|
+
# paddings and lengths are handled correctly
|
117
|
+
packet.data_block.trans_data.read_data = 'a'
|
118
|
+
binary = packet.to_binary_s
|
119
|
+
expect(described_class.read(binary)).to eq(packet)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
@@ -39,8 +39,8 @@ RSpec.describe RubySMB::SMB1::Packet::Trans2::Request do
|
|
39
39
|
it { is_expected.to respond_to :setup_count }
|
40
40
|
|
41
41
|
describe 'flags' do
|
42
|
-
it 'is a
|
43
|
-
expect(parameter_block.flags).to be_a RubySMB::SMB1::BitField::
|
42
|
+
it 'is a trans_flags BitField' do
|
43
|
+
expect(parameter_block.flags).to be_a RubySMB::SMB1::BitField::TransFlags
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
@@ -62,4 +62,202 @@ RSpec.describe RubySMB::SMB1::Pipe do
|
|
62
62
|
end
|
63
63
|
end
|
64
64
|
|
65
|
-
|
65
|
+
context 'with DCERPC' do
|
66
|
+
describe '#net_share_enum_all' do
|
67
|
+
let(:host) { '1.2.3.4' }
|
68
|
+
let(:dcerpc_response) { RubySMB::Dcerpc::Response.new }
|
69
|
+
|
70
|
+
before :example do
|
71
|
+
allow(pipe).to receive(:bind)
|
72
|
+
allow(pipe).to receive(:request).and_return(dcerpc_response)
|
73
|
+
allow(RubySMB::Dcerpc::Srvsvc::NetShareEnumAll).to receive(:parse_response).and_return([])
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'calls #bind with the expected arguments' do
|
77
|
+
expect(pipe).to receive(:bind).with(endpoint: RubySMB::Dcerpc::Srvsvc)
|
78
|
+
pipe.net_share_enum_all(host)
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'calls #request with the expected arguments' do
|
82
|
+
expect(pipe).to receive(:request).with(RubySMB::Dcerpc::Srvsvc::NET_SHARE_ENUM_ALL, host: host)
|
83
|
+
pipe.net_share_enum_all(host)
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'parse the response with NetShareEnumAll #parse_response method' do
|
87
|
+
stub = 'ABCD'
|
88
|
+
dcerpc_response.alloc_hint = stub.size
|
89
|
+
dcerpc_response.stub = stub
|
90
|
+
expect(RubySMB::Dcerpc::Srvsvc::NetShareEnumAll).to receive(:parse_response).with(stub)
|
91
|
+
pipe.net_share_enum_all(host)
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'returns the remote shares' do
|
95
|
+
shares = [
|
96
|
+
["C$", "DISK", "Default share"],
|
97
|
+
["Shared", "DISK", ""],
|
98
|
+
["IPC$", "IPC", "Remote IPC"],
|
99
|
+
["ADMIN$", "DISK", "Remote Admin"]
|
100
|
+
]
|
101
|
+
output = [
|
102
|
+
{:name=>"C$", :type=>"DISK", :comment=>"Default share"},
|
103
|
+
{:name=>"Shared", :type=>"DISK", :comment=>""},
|
104
|
+
{:name=>"IPC$", :type=>"IPC", :comment=>"Remote IPC"},
|
105
|
+
{:name=>"ADMIN$", :type=>"DISK", :comment=>"Remote Admin"},
|
106
|
+
]
|
107
|
+
allow(RubySMB::Dcerpc::Srvsvc::NetShareEnumAll).to receive(:parse_response).and_return(shares)
|
108
|
+
expect(pipe.net_share_enum_all(host)).to eq(output)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
describe '#bind' do
|
113
|
+
let(:options) { { endpoint: RubySMB::Dcerpc::Srvsvc } }
|
114
|
+
let(:bind_packet) { RubySMB::Dcerpc::Bind.new(options) }
|
115
|
+
let(:bind_ack_packet) { RubySMB::Dcerpc::BindAck.new }
|
116
|
+
|
117
|
+
before :example do
|
118
|
+
allow(RubySMB::Dcerpc::Bind).to receive(:new).and_return(bind_packet)
|
119
|
+
allow(pipe).to receive(:write)
|
120
|
+
allow(pipe).to receive(:read)
|
121
|
+
bind_ack_packet.p_result_list.n_results = 1
|
122
|
+
bind_ack_packet.p_result_list.p_results[0].result = RubySMB::Dcerpc::BindAck::ACCEPTANCE
|
123
|
+
allow(RubySMB::Dcerpc::BindAck).to receive(:read).and_return(bind_ack_packet)
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'creates a Bind packet' do
|
127
|
+
expect(RubySMB::Dcerpc::Bind).to receive(:new).with(options).and_return(bind_packet)
|
128
|
+
pipe.bind(options)
|
129
|
+
end
|
130
|
+
|
131
|
+
it 'writes to the named pipe' do
|
132
|
+
expect(pipe).to receive(:write).with(data: bind_packet.to_binary_s)
|
133
|
+
pipe.bind(options)
|
134
|
+
end
|
135
|
+
|
136
|
+
it 'reads the socket' do
|
137
|
+
expect(pipe).to receive(:read)
|
138
|
+
pipe.bind(options)
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'creates a BindAck packet from the response' do
|
142
|
+
raw_response = RubySMB::Dcerpc::BindAck.new.to_binary_s
|
143
|
+
allow(pipe).to receive(:read).and_return(raw_response)
|
144
|
+
expect(RubySMB::Dcerpc::BindAck).to receive(:read).with(raw_response).and_return(bind_ack_packet)
|
145
|
+
pipe.bind(options)
|
146
|
+
end
|
147
|
+
|
148
|
+
it 'raises the expected exception when an invalid packet is received' do
|
149
|
+
allow(RubySMB::Dcerpc::BindAck).to receive(:read).and_raise(IOError)
|
150
|
+
expect { pipe.bind(options) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
|
151
|
+
end
|
152
|
+
|
153
|
+
it 'raises the expected exception when it is not a BindAck packet' do
|
154
|
+
response = RubySMB::Dcerpc::Bind.new
|
155
|
+
allow(RubySMB::Dcerpc::BindAck).to receive(:read).and_return(response)
|
156
|
+
expect { pipe.bind(options) }.to raise_error(RubySMB::Dcerpc::Error::BindError)
|
157
|
+
end
|
158
|
+
|
159
|
+
it 'raises an exception when no result is returned' do
|
160
|
+
bind_ack_packet.p_result_list.n_results = 0
|
161
|
+
expect { pipe.bind(options) }.to raise_error(RubySMB::Dcerpc::Error::BindError)
|
162
|
+
end
|
163
|
+
|
164
|
+
it 'raises an exception when result is not ACCEPTANCE' do
|
165
|
+
bind_ack_packet.p_result_list.p_results[0].result = RubySMB::Dcerpc::BindAck::USER_REJECTION
|
166
|
+
expect { pipe.bind(options) }.to raise_error(RubySMB::Dcerpc::Error::BindError)
|
167
|
+
end
|
168
|
+
|
169
|
+
it 'returns the expected BindAck packet' do
|
170
|
+
expect(pipe.bind(options)).to eq(bind_ack_packet)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
describe '#request' do
|
175
|
+
let(:options) { { host: '1.2.3.4' } }
|
176
|
+
let(:opnum) { RubySMB::Dcerpc::Srvsvc::NET_SHARE_ENUM_ALL }
|
177
|
+
let(:req_packet) { RubySMB::Dcerpc::Request.new({ :opnum => opnum }, options) }
|
178
|
+
let(:nmpipe_packet) { RubySMB::SMB1::Packet::Trans::TransactNmpipeRequest.new(options) }
|
179
|
+
let(:nmpipe_response) { RubySMB::SMB1::Packet::Trans::TransactNmpipeResponse.new }
|
180
|
+
let(:res_packet) { RubySMB::Dcerpc::Response.new }
|
181
|
+
|
182
|
+
before :example do
|
183
|
+
allow(RubySMB::Dcerpc::Request).to receive(:new).and_return(req_packet)
|
184
|
+
allow(RubySMB::SMB1::Packet::Trans::TransactNmpipeRequest).to receive(:new).and_return(nmpipe_packet)
|
185
|
+
allow(client).to receive(:send_recv)
|
186
|
+
allow(RubySMB::SMB1::Packet::Trans::TransactNmpipeResponse).to receive(:read).and_return(nmpipe_response)
|
187
|
+
allow(RubySMB::Dcerpc::Response).to receive(:read).and_return(res_packet)
|
188
|
+
end
|
189
|
+
|
190
|
+
it 'creates a Request packet' do
|
191
|
+
expect(RubySMB::Dcerpc::Request).to receive(:new).and_return(req_packet)
|
192
|
+
pipe.request(opnum, options)
|
193
|
+
end
|
194
|
+
|
195
|
+
it 'creates a Trans TransactNmpipeRequest packet' do
|
196
|
+
expect(RubySMB::SMB1::Packet::Trans::TransactNmpipeRequest).to receive(:new).and_return(nmpipe_packet)
|
197
|
+
pipe.request(opnum, options)
|
198
|
+
end
|
199
|
+
|
200
|
+
it 'calls Tree #set_header_fields' do
|
201
|
+
expect(tree).to receive(:set_header_fields).with(nmpipe_packet)
|
202
|
+
pipe.request(opnum, options)
|
203
|
+
end
|
204
|
+
|
205
|
+
it 'calls TransactNmpipeRequest #set_fid' do
|
206
|
+
expect(nmpipe_packet).to receive(:set_fid).with(pipe.fid)
|
207
|
+
pipe.request(opnum, options)
|
208
|
+
end
|
209
|
+
|
210
|
+
it 'sets the expected data on the request' do
|
211
|
+
expect(client).to receive(:send_recv) do
|
212
|
+
expect(nmpipe_packet.data_block.trans_data.write_data).to eq(req_packet.to_binary_s)
|
213
|
+
end
|
214
|
+
pipe.request(opnum, options)
|
215
|
+
end
|
216
|
+
|
217
|
+
it 'sends the expected request' do
|
218
|
+
expect(client).to receive(:send_recv).with(nmpipe_packet)
|
219
|
+
pipe.request(opnum, options)
|
220
|
+
end
|
221
|
+
|
222
|
+
it 'creates a Trans TransactNmpipeResponse packet from the response' do
|
223
|
+
raw_response = double('Raw response')
|
224
|
+
allow(client).to receive(:send_recv).and_return(raw_response)
|
225
|
+
expect(RubySMB::SMB1::Packet::Trans::TransactNmpipeResponse).to receive(:read).with(raw_response).and_return(nmpipe_response)
|
226
|
+
pipe.request(opnum, options)
|
227
|
+
end
|
228
|
+
|
229
|
+
it 'raises the expected exception when it is not a Trans packet' do
|
230
|
+
response = RubySMB::SMB1::Packet::Trans2::Response.new
|
231
|
+
allow(RubySMB::SMB1::Packet::Trans::TransactNmpipeResponse).to receive(:read).and_return(response)
|
232
|
+
expect { pipe.request(opnum, options) }.to raise_error(RubySMB::Error::InvalidPacket)
|
233
|
+
end
|
234
|
+
|
235
|
+
it 'raises the expected exception when the status code is not STATUS_SUCCESS' do
|
236
|
+
nmpipe_response.smb_header.nt_status = WindowsError::NTStatus::STATUS_INVALID_HANDLE.value
|
237
|
+
expect { pipe.request(opnum, options) }.to raise_error(RubySMB::Error::UnexpectedStatusCode)
|
238
|
+
end
|
239
|
+
|
240
|
+
it 'creates a DCERPC Response packet from the response' do
|
241
|
+
nmpipe_response.data_block.trans_data.read_data = "test"
|
242
|
+
expect(RubySMB::Dcerpc::Response).to receive(:read).with(nmpipe_response.data_block.trans_data.read_data)
|
243
|
+
pipe.request(opnum, options)
|
244
|
+
end
|
245
|
+
|
246
|
+
it 'raises the expected exception when an invalid packet is received' do
|
247
|
+
allow(RubySMB::Dcerpc::Response).to receive(:read).and_raise(IOError)
|
248
|
+
expect { pipe.request(opnum, options) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
|
249
|
+
end
|
250
|
+
|
251
|
+
it 'raises the expected exception when it is not a Response packet' do
|
252
|
+
response = RubySMB::Dcerpc::Request.new
|
253
|
+
allow(RubySMB::Dcerpc::Response).to receive(:read).and_return(response)
|
254
|
+
expect { pipe.request(opnum, options) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
|
255
|
+
end
|
256
|
+
|
257
|
+
it 'returns the expected DCERPC Response' do
|
258
|
+
expect(pipe.request(opnum, options)).to eq(res_packet)
|
259
|
+
end
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
end
|