CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/spec/tools/md5_lookup_spec.rb
Views: 1904
1
load Metasploit::Framework.root.join('tools/password/md5_lookup.rb').to_path
2
require 'spec_helper'
3
4
require 'stringio'
5
6
RSpec.describe Md5LookupUtility do
7
8
#
9
# Init some data
10
#
11
12
let(:input_data) do
13
'098f6bcd4621d373cade4e832627b4f6'
14
end
15
16
let(:bad_input_data) do
17
''
18
end
19
20
let(:good_result) do
21
'test'
22
end
23
24
let(:empty_result) do
25
''
26
end
27
28
let(:good_json_response) do
29
%Q|{ "status":true, "result":"test", "message":"" }|
30
end
31
32
let(:bad_json_response) do
33
%Q|{ "status":false, "result":"", "message":"not found" }|
34
end
35
36
let(:db_source) do
37
'i337.net'
38
end
39
40
let(:input_file) do
41
'input.txt'
42
end
43
44
let(:output_file) do
45
'output.txt'
46
end
47
48
let(:options) do
49
{
50
:databases => [db_source],
51
:outfile => output_file,
52
:input => input_file
53
}
54
end
55
56
subject do
57
Md5LookupUtility::Md5Lookup.new
58
end
59
60
def set_expected_response(body)
61
res = Rex::Proto::Http::Response.new
62
res.code = 200
63
res.body = body
64
res
65
end
66
67
def set_send_request_cgi(body)
68
allow(subject).to receive(:send_request_cgi) do |opts|
69
set_expected_response(body)
70
end
71
end
72
73
#
74
# Tests start here
75
#
76
77
78
describe Md5LookupUtility::Disclaimer do
79
80
let(:group_name) { 'MD5Lookup' }
81
let(:setting_name) { 'waiver' }
82
let(:data) { true }
83
let(:t_path) { 'filepath' }
84
85
def stub_save
86
ini = Rex::Parser::Ini.new(t_path)
87
allow(ini).to receive(:to_file).with(any_args)
88
allow(Rex::Parser::Ini).to receive(:new).and_return(ini)
89
return ini
90
end
91
92
def stub_load(with_setting=true)
93
if with_setting
94
ini = stub_save
95
disclaimer.save_waiver
96
else
97
ini = Rex::Parser::Ini.new(t_path)
98
end
99
100
allow(Rex::Parser::Ini).to receive(:new).and_return(ini)
101
return ini
102
end
103
104
subject(:disclaimer) do
105
Md5LookupUtility::Disclaimer.new
106
end
107
108
describe '#ack' do
109
context 'When \'Y\' is entered' do
110
it 'returns true' do
111
agree = "Y\n"
112
allow($stdin).to receive(:gets).and_return(agree)
113
get_stdout { expect(disclaimer.ack).to be_truthy }
114
end
115
end
116
end
117
118
describe '#save_waiver' do
119
context 'when waiver is true' do
120
it 'saves the wavier setting' do
121
ini = stub_save
122
disclaimer.save_waiver
123
expect(ini[group_name]).to eq({setting_name=>true})
124
end
125
end
126
end
127
128
describe '#has_waiver?' do
129
context 'when there is a waiver' do
130
it 'returns true' do
131
ini = stub_load(true)
132
expect(disclaimer.send(:has_waiver?)).to be_truthy
133
end
134
end
135
136
context 'when there is no waiver' do
137
it 'returns false' do
138
ini = stub_load(false)
139
expect(disclaimer.send(:has_waiver?)).to be_falsey
140
end
141
end
142
end
143
144
describe '#save_setting' do
145
context 'when a setting is given' do
146
it 'saves the setting' do
147
ini = stub_save
148
disclaimer.send(:save_setting, setting_name, data)
149
expect(ini[group_name]).to eq({setting_name=>true})
150
end
151
end
152
end
153
154
describe '#load_setting' do
155
end
156
157
end
158
159
160
describe Md5LookupUtility::Md5Lookup do
161
162
describe '.new' do
163
it 'returns a Md5LookupUtility::Md5Lookup instance' do
164
expect(subject).to be_a(Md5LookupUtility::Md5Lookup)
165
end
166
end
167
168
describe '#lookup' do
169
170
context 'when a hash is found' do
171
it 'returns the cracked result' do
172
set_send_request_cgi(good_json_response)
173
expect(subject.lookup(input_data, db_source)).to eq(good_result)
174
end
175
end
176
177
context 'when a hash is not found' do
178
it 'returns an empty result' do
179
set_send_request_cgi(bad_json_response)
180
expect(subject.lookup(input_data, db_source)).to eq(empty_result)
181
end
182
end
183
end
184
185
describe '#get_json_results' do
186
context 'when JSON contains the found result' do
187
it 'returns the cracked result' do
188
res = set_expected_response(good_json_response)
189
expect(subject.send(:get_json_result, res)).to eq(good_result)
190
end
191
end
192
193
context 'when there is no JSON data' do
194
it 'returns an empty result' do
195
res = set_expected_response('')
196
expect(subject.send(:get_json_result, res)).to eq(empty_result)
197
end
198
end
199
end
200
201
end
202
203
204
describe Md5LookupUtility::Driver do
205
206
let(:expected_result) {
207
{
208
:hash => input_data,
209
:cracked_hash => good_result,
210
:credit => db_source
211
}
212
}
213
214
before(:example) do
215
expect(Md5LookupUtility::OptsConsole).to receive(:parse).with(any_args).and_return(options)
216
allow(File).to receive(:open).with(input_file, 'rb').and_yield(StringIO.new(input_data))
217
allow(File).to receive(:new).with(output_file, 'wb').and_return(StringIO.new)
218
end
219
220
subject do
221
Md5LookupUtility::Driver.new
222
end
223
224
describe '.new' do
225
it 'returns a Md5LookupUtility::Driver instance' do
226
expect(subject).to be_a(Md5LookupUtility::Driver)
227
end
228
end
229
230
describe '#run' do
231
context 'when a hash is found' do
232
it 'prints a \'found\' message' do
233
disclaimer = Md5LookupUtility::Disclaimer.new
234
allow(disclaimer).to receive(:has_waiver?).and_return(true)
235
allow(Md5LookupUtility::Disclaimer).to receive(:new).and_return(disclaimer)
236
allow(subject).to receive(:get_hash_results).and_yield(expected_result)
237
output = get_stdout { subject.run }
238
expect(output).to include('Found:')
239
end
240
end
241
end
242
243
describe '#save_result' do
244
context 'when a result is given' do
245
it 'writes the result to file' do
246
subject.send(:save_result, expected_result)
247
expect(subject.instance_variable_get(:@output_handle).string).to include(good_result)
248
end
249
end
250
end
251
252
describe '#get_hash_results' do
253
context 'when a hash is found' do
254
it 'yields a result' do
255
search_engine = Md5LookupUtility::Md5Lookup.new
256
allow(search_engine).to receive(:lookup).and_return(good_result)
257
allow(Md5LookupUtility::Md5Lookup).to receive(:new).and_return(search_engine)
258
259
expect{ |b| subject.send(:get_hash_results, input_file, [db_source], &b) }.to yield_with_args(expected_result)
260
end
261
end
262
end
263
264
describe '#extract_hashes' do
265
context 'when a MD5 file is supplied' do
266
it 'yields the MD5 hash' do
267
expect{ |b| subject.send(:extract_hashes, input_file, &b) }.to yield_with_args(input_data)
268
end
269
end
270
271
context 'when an empty file is supplied' do
272
before do
273
allow(File).to receive(:open).with(input_file, 'rb').and_yield(StringIO.new(''))
274
end
275
276
it 'yields nothing' do
277
expect{ |b| subject.send(:extract_hashes, input_file, &b) }.not_to yield_control
278
end
279
end
280
end
281
282
describe '#is_md5_format?' do
283
context 'when a valid MD5 is given' do
284
it 'returns true' do
285
expect(subject.send(:is_md5_format?,input_data)).to be_truthy
286
end
287
end
288
289
context 'when a non-MD5 value is given' do
290
it 'returns false' do
291
expect(subject.send(:is_md5_format?, bad_input_data)).to be_falsey
292
end
293
end
294
end
295
296
end
297
298
299
describe Md5LookupUtility::OptsConsole do
300
let(:valid_argv) { "-i #{input_file} -d all -o #{output_file}".split }
301
302
let(:invalid_argv) { "".split }
303
304
subject do
305
Md5LookupUtility::OptsConsole
306
end
307
308
describe '.parse' do
309
context 'when valid arguments are passed' do
310
let(:opts) { subject.parse(valid_argv) }
311
312
before(:example) do
313
allow(File).to receive(:exist?).and_return(true)
314
end
315
316
it 'returns the input file path' do
317
expect(opts[:input]).to eq(input_file)
318
end
319
320
it 'returns the output file path' do
321
expect(opts[:outfile]).to eq(output_file)
322
end
323
324
it 'returns the databases in an array' do
325
expect(opts[:databases]).to be_a(Array)
326
expect(opts[:databases]).to include(db_source)
327
end
328
end
329
330
context 'when the required input file is not set' do
331
before(:example) do
332
allow(File).to receive(:exist?).and_return(false)
333
end
334
335
it 'raises an OptionParser::MissingArgument error' do
336
expect{subject.parse(invalid_argv)}.to raise_error(OptionParser::MissingArgument)
337
end
338
end
339
340
end
341
342
343
describe '.extract_db_names' do
344
let(:list) {'i337,invalid'}
345
context 'when database symbols \'i337\' and \'invalid\' are given' do
346
it 'returns i337.net in an array' do
347
db_names = subject.extract_db_names(list)
348
expect(db_names).to be_a(Array)
349
expect(db_names).to include(db_source)
350
end
351
end
352
end
353
354
describe '.get_database_symbols' do
355
it 'returns an array' do
356
expect(subject.get_database_symbols).to be_a(Array)
357
end
358
end
359
360
describe '.get_database_names' do
361
it 'returns an array' do
362
expect(subject.get_database_names).to be_a(Array)
363
end
364
end
365
end
366
367
end
368
369