ruby_smb 0.0.21 → 0.0.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +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
|