Skip to content

Commit 78ea930

Browse files
committed
Fix Msf::PayloadGenerator spec constant leaks
MSP-11130 Remove the constant PAYLOAD_FRAMEWORK as it leads to a Msf::Simple::Framework instance that is not cleaned up and loads modules prior to the beginning of the suite run.
1 parent ff0391c commit 78ea930

File tree

1 file changed

+136
-55
lines changed

1 file changed

+136
-55
lines changed

spec/lib/msf/core/payload_generator_spec.rb

Lines changed: 136 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,26 @@
22
require 'msf/core/payload_generator'
33

44
describe Msf::PayloadGenerator do
5-
6-
PAYLOAD_FRAMEWORK = Msf::Simple::Framework.create(
7-
:module_types => [ ::Msf::MODULE_PAYLOAD, ::Msf::MODULE_ENCODER, ::Msf::MODULE_NOP],
8-
'DisableDatabase' => true,
9-
'DisableLogging' => true
10-
)
5+
include_context 'Msf::Simple::Framework#modules loading'
116

127
let(:lhost) { "192.168.172.1"}
138
let(:lport) { "8443" }
149
let(:datastore) { { "LHOST" => lhost, "LPORT" => lport } }
1510
let(:add_code) { false }
1611
let(:arch) { "x86" }
1712
let(:badchars) { "\x20\x0D\x0A" }
18-
let(:encoder) { 'x86/shikata_ga_nai' }
13+
let(:encoder_reference_name) {
14+
# use encoder_module to ensure it is loaded prior to passing to generator
15+
encoder_module.refname
16+
}
1917
let(:format) { "raw" }
20-
let(:framework) { PAYLOAD_FRAMEWORK }
2118
let(:iterations) { 1 }
2219
let(:keep) { false }
2320
let(:nops) { 0 }
24-
let(:payload) { "windows/meterpreter/reverse_tcp"}
21+
let(:payload_reference_name) {
22+
# use payload_module to ensure it is loaded prior to passing to generator
23+
payload_module.refname
24+
}
2525
let(:platform) { "Windows" }
2626
let(:space) { 1073741824 }
2727
let(:stdin) { nil }
@@ -31,25 +31,41 @@
3131
add_code: add_code,
3232
arch: arch,
3333
badchars: badchars,
34-
encoder: encoder,
34+
encoder: encoder_reference_name,
3535
datastore: datastore,
3636
format: format,
3737
framework: framework,
3838
iterations: iterations,
3939
keep: keep,
4040
nops: nops,
41-
payload: payload,
41+
payload: payload_reference_name,
4242
platform: platform,
4343
space: space,
4444
stdin: stdin,
4545
template: template
4646
}
4747
}
48-
let(:payload_module) { framework.payloads.create(payload)}
48+
let(:payload_module) {
49+
load_and_create_module(
50+
ancestor_reference_names: %w{
51+
stagers/windows/reverse_tcp
52+
stages/windows/meterpreter
53+
},
54+
module_type: 'payload',
55+
reference_name: 'windows/meterpreter/reverse_tcp'
56+
)
57+
}
4958
let(:shellcode) { "\x50\x51\x58\x59" }
50-
let(:encoder_module) { framework.encoders.create('x86/shikata_ga_nai') }
59+
let(:encoder_module) {
60+
load_and_create_module(
61+
module_type: 'encoder',
62+
reference_name: 'x86/shikata_ga_nai'
63+
)
64+
}
5165

52-
subject(:payload_generator) { described_class.new(generator_opts) }
66+
subject(:payload_generator) {
67+
described_class.new(generator_opts)
68+
}
5369

5470
it { should respond_to :add_code }
5571
it { should respond_to :arch }
@@ -77,13 +93,13 @@
7793
add_code: add_code,
7894
arch: arch,
7995
badchars: badchars,
80-
encoder: encoder,
96+
encoder: encoder_reference_name,
8197
datastore: datastore,
8298
format: format,
8399
iterations: iterations,
84100
keep: keep,
85101
nops: nops,
86-
payload: payload,
102+
payload: payload_reference_name,
87103
platform: platform,
88104
space: space,
89105
stdin: stdin,
@@ -95,19 +111,19 @@
95111
end
96112

97113
context 'when not given a payload' do
98-
let(:payload) { nil }
114+
let(:payload_reference_name) { nil }
99115

100116
it { should raise_error(ArgumentError, "Invalid Payload Selected") }
101117
end
102118

103119
context 'when given an invalid payload' do
104-
let(:payload) { "beos/meterpreter/reverse_gopher" }
120+
let(:payload_reference_name) { "beos/meterpreter/reverse_gopher" }
105121

106122
it { should raise_error(ArgumentError, "Invalid Payload Selected") }
107123
end
108124

109125
context 'when given a payload through stdin' do
110-
let(:payload) { "stdin" }
126+
let(:payload_reference_name) { "stdin" }
111127

112128
it { should_not raise_error }
113129
end
@@ -230,7 +246,7 @@
230246

231247
context 'when passing a payload through stdin' do
232248
let(:stdin) { "\x90\x90\x90"}
233-
let(:payload) { "stdin" }
249+
let(:payload_reference_name) { "stdin" }
234250

235251
context 'when no arch has been selected' do
236252
let(:arch) { '' }
@@ -330,6 +346,13 @@
330346
end
331347

332348
context '#prepend_nops' do
349+
before(:each) do
350+
load_and_create_module(
351+
module_type: 'nop',
352+
reference_name: 'x86/opty2'
353+
)
354+
end
355+
333356
context 'when nops are set to 0' do
334357
it 'returns the unmodified shellcode' do
335358
expect(payload_generator.prepend_nops(shellcode)).to eq shellcode
@@ -367,15 +390,41 @@
367390
end
368391

369392
context 'when multiple encoders are selected' do
370-
let(:encoder) { "x86/shikata_ga_nai,x86/alpha_mixed"}
393+
#
394+
# lets
395+
#
396+
397+
let(:encoder_reference_name) {
398+
encoder_reference_names.join(',')
399+
}
400+
401+
let(:encoder_reference_names) {
402+
%w{
403+
x86/shikata_ga_nai
404+
x86/alpha_mixed
405+
}
406+
}
407+
408+
#
409+
# Callbacks
410+
#
411+
412+
before(:each) do
413+
encoder_reference_names.each do |reference_name|
414+
load_and_create_module(
415+
module_type: 'encoder',
416+
reference_name: reference_name
417+
)
418+
end
419+
end
371420

372421
it 'returns an array of the right size' do
373422
expect(payload_generator.get_encoders.count).to eq 2
374423
end
375424

376425
it 'returns each of the selected encoders in the array' do
377-
payload_generator.get_encoders.each do |my_encoder|
378-
expect(encoder_names).to include my_encoder.name
426+
payload_generator.get_encoders.each do |msf_encoder|
427+
expect(encoder_names).to include msf_encoder.name
379428
end
380429
end
381430

@@ -385,17 +434,17 @@
385434
end
386435

387436
context 'when no encoder is selected but badchars are present' do
388-
let(:encoder) { '' }
437+
let(:encoder_reference_name) { '' }
389438

390439
it 'returns an array of all encoders with a compatible arch' do
391440
payload_generator.get_encoders.each do |my_encoder|
392-
expect(my_encoder.arch).to include arch
441+
expect(encoder_module.arch).to include arch
393442
end
394443
end
395444
end
396445

397446
context 'when no encoder or badchars are selected' do
398-
let(:encoder) { '' }
447+
let(:encoder_reference_name) { '' }
399448
let(:badchars) { '' }
400449

401450
it 'returns an empty array' do
@@ -407,9 +456,8 @@
407456
context '#run_encoder' do
408457

409458
it 'should call the encoder a number of times equal to the iterations' do
410-
my_encoder = encoder_module
411-
my_encoder.should_receive(:encode).exactly(iterations).times.and_return(shellcode)
412-
payload_generator.run_encoder(my_encoder, shellcode)
459+
encoder_module.should_receive(:encode).exactly(iterations).times.and_return(shellcode)
460+
payload_generator.run_encoder(encoder_module, shellcode)
413461
end
414462

415463
context 'when the encoder makes a buffer too large' do
@@ -454,12 +502,21 @@
454502
let(:format) { 'war' }
455503

456504
context 'if the payload is a valid java payload' do
457-
let(:payload) { "java/meterpreter/reverse_tcp"}
505+
let(:payload_module) {
506+
load_and_create_module(
507+
ancestor_reference_names: %w{
508+
stagers/java/reverse_tcp
509+
stages/java/meterpreter
510+
},
511+
module_type: 'payload',
512+
reference_name: 'java/meterpreter/reverse_tcp'
513+
)
514+
}
515+
458516
it 'calls the generate_war on the payload' do
459-
java_payload = framework.payloads.create("java/meterpreter/reverse_tcp")
460-
framework.stub_chain(:payloads, :keys).and_return ["java/meterpreter/reverse_tcp"]
461-
framework.stub_chain(:payloads, :create).and_return(java_payload)
462-
java_payload.should_receive(:generate_war).and_call_original
517+
framework.stub_chain(:payloads, :keys).and_return [payload_reference_name]
518+
framework.stub_chain(:payloads, :create).and_return(payload_module)
519+
payload_module.should_receive(:generate_war).and_call_original
463520
payload_generator.generate_java_payload
464521
end
465522
end
@@ -473,23 +530,40 @@
473530
let(:format) { 'raw' }
474531

475532
context 'if the payload responds to generate_jar' do
476-
let(:payload) { "java/meterpreter/reverse_tcp"}
533+
let(:payload_module) {
534+
load_and_create_module(
535+
ancestor_reference_names: %w{
536+
stagers/java/reverse_tcp
537+
stages/java/meterpreter
538+
},
539+
module_type: 'payload',
540+
reference_name: 'java/meterpreter/reverse_tcp'
541+
)
542+
}
543+
477544
it 'calls the generate_jar on the payload' do
478-
java_payload = framework.payloads.create("java/meterpreter/reverse_tcp")
479-
framework.stub_chain(:payloads, :keys).and_return ["java/meterpreter/reverse_tcp"]
480-
framework.stub_chain(:payloads, :create).and_return(java_payload)
481-
java_payload.should_receive(:generate_jar).and_call_original
545+
framework.stub_chain(:payloads, :keys).and_return [payload_reference_name]
546+
framework.stub_chain(:payloads, :create).and_return(payload_module)
547+
payload_module.should_receive(:generate_jar).and_call_original
482548
payload_generator.generate_java_payload
483549
end
484550
end
485551

486552
context 'if the payload does not respond to generate_jar' do
487-
let(:payload) { "java/jsp_shell_reverse_tcp"}
553+
let(:payload_module) {
554+
load_and_create_module(
555+
ancestor_reference_names: %w{
556+
singles/java/jsp_shell_reverse_tcp
557+
},
558+
module_type: 'payload',
559+
reference_name: 'java/jsp_shell_reverse_tcp'
560+
)
561+
}
562+
488563
it 'calls #generate' do
489-
java_payload = framework.payloads.create("java/jsp_shell_reverse_tcp")
490-
framework.stub_chain(:payloads, :keys).and_return ["java/jsp_shell_reverse_tcp"]
491-
framework.stub_chain(:payloads, :create).and_return(java_payload)
492-
java_payload.should_receive(:generate).and_call_original
564+
framework.stub_chain(:payloads, :keys).and_return [payload_reference_name]
565+
framework.stub_chain(:payloads, :create).and_return(payload_module)
566+
payload_module.should_receive(:generate).and_call_original
493567
payload_generator.generate_java_payload
494568
end
495569
end
@@ -510,22 +584,29 @@
510584
context '#generate_payload' do
511585

512586
it 'calls each step of the process' do
513-
my_generator = payload_generator
514-
my_generator.should_receive(:generate_raw_payload).and_call_original
515-
my_generator.should_receive(:add_shellcode).and_call_original
516-
my_generator.should_receive(:encode_payload).and_call_original
517-
my_generator.should_receive(:prepend_nops).and_call_original
518-
my_generator.should_receive(:format_payload).and_call_original
519-
my_generator.generate_payload
587+
payload_generator.should_receive(:generate_raw_payload).and_call_original
588+
payload_generator.should_receive(:add_shellcode).and_call_original
589+
payload_generator.should_receive(:encode_payload).and_call_original
590+
payload_generator.should_receive(:prepend_nops).and_call_original
591+
payload_generator.should_receive(:format_payload).and_call_original
592+
payload_generator.generate_payload
520593
end
521594

522595
context 'when the payload is java' do
523-
let(:payload) { "java/meterpreter/reverse_tcp" }
596+
let(:payload_module) {
597+
load_and_create_module(
598+
ancestor_reference_names: %w{
599+
stagers/java/reverse_tcp
600+
stages/java/meterpreter
601+
},
602+
module_type: 'payload',
603+
reference_name: 'java/meterpreter/reverse_tcp'
604+
)
605+
}
524606

525607
it 'calls generate_java_payload' do
526-
my_generator = payload_generator
527-
my_generator.should_receive(:generate_java_payload)
528-
my_generator.generate_payload
608+
payload_generator.should_receive(:generate_java_payload)
609+
payload_generator.generate_payload
529610
end
530611
end
531612
end

0 commit comments

Comments
 (0)