|
2 | 2 | require 'msf/core/payload_generator'
|
3 | 3 |
|
4 | 4 | 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' |
11 | 6 |
|
12 | 7 | let(:lhost) { "192.168.172.1"}
|
13 | 8 | let(:lport) { "8443" }
|
14 | 9 | let(:datastore) { { "LHOST" => lhost, "LPORT" => lport } }
|
15 | 10 | let(:add_code) { false }
|
16 | 11 | let(:arch) { "x86" }
|
17 | 12 | 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 | + } |
19 | 17 | let(:format) { "raw" }
|
20 |
| - let(:framework) { PAYLOAD_FRAMEWORK } |
21 | 18 | let(:iterations) { 1 }
|
22 | 19 | let(:keep) { false }
|
23 | 20 | 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 | + } |
25 | 25 | let(:platform) { "Windows" }
|
26 | 26 | let(:space) { 1073741824 }
|
27 | 27 | let(:stdin) { nil }
|
|
31 | 31 | add_code: add_code,
|
32 | 32 | arch: arch,
|
33 | 33 | badchars: badchars,
|
34 |
| - encoder: encoder, |
| 34 | + encoder: encoder_reference_name, |
35 | 35 | datastore: datastore,
|
36 | 36 | format: format,
|
37 | 37 | framework: framework,
|
38 | 38 | iterations: iterations,
|
39 | 39 | keep: keep,
|
40 | 40 | nops: nops,
|
41 |
| - payload: payload, |
| 41 | + payload: payload_reference_name, |
42 | 42 | platform: platform,
|
43 | 43 | space: space,
|
44 | 44 | stdin: stdin,
|
45 | 45 | template: template
|
46 | 46 | }
|
47 | 47 | }
|
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 | + } |
49 | 58 | 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 | + } |
51 | 65 |
|
52 |
| - subject(:payload_generator) { described_class.new(generator_opts) } |
| 66 | + subject(:payload_generator) { |
| 67 | + described_class.new(generator_opts) |
| 68 | + } |
53 | 69 |
|
54 | 70 | it { should respond_to :add_code }
|
55 | 71 | it { should respond_to :arch }
|
|
77 | 93 | add_code: add_code,
|
78 | 94 | arch: arch,
|
79 | 95 | badchars: badchars,
|
80 |
| - encoder: encoder, |
| 96 | + encoder: encoder_reference_name, |
81 | 97 | datastore: datastore,
|
82 | 98 | format: format,
|
83 | 99 | iterations: iterations,
|
84 | 100 | keep: keep,
|
85 | 101 | nops: nops,
|
86 |
| - payload: payload, |
| 102 | + payload: payload_reference_name, |
87 | 103 | platform: platform,
|
88 | 104 | space: space,
|
89 | 105 | stdin: stdin,
|
|
95 | 111 | end
|
96 | 112 |
|
97 | 113 | context 'when not given a payload' do
|
98 |
| - let(:payload) { nil } |
| 114 | + let(:payload_reference_name) { nil } |
99 | 115 |
|
100 | 116 | it { should raise_error(ArgumentError, "Invalid Payload Selected") }
|
101 | 117 | end
|
102 | 118 |
|
103 | 119 | context 'when given an invalid payload' do
|
104 |
| - let(:payload) { "beos/meterpreter/reverse_gopher" } |
| 120 | + let(:payload_reference_name) { "beos/meterpreter/reverse_gopher" } |
105 | 121 |
|
106 | 122 | it { should raise_error(ArgumentError, "Invalid Payload Selected") }
|
107 | 123 | end
|
108 | 124 |
|
109 | 125 | context 'when given a payload through stdin' do
|
110 |
| - let(:payload) { "stdin" } |
| 126 | + let(:payload_reference_name) { "stdin" } |
111 | 127 |
|
112 | 128 | it { should_not raise_error }
|
113 | 129 | end
|
|
230 | 246 |
|
231 | 247 | context 'when passing a payload through stdin' do
|
232 | 248 | let(:stdin) { "\x90\x90\x90"}
|
233 |
| - let(:payload) { "stdin" } |
| 249 | + let(:payload_reference_name) { "stdin" } |
234 | 250 |
|
235 | 251 | context 'when no arch has been selected' do
|
236 | 252 | let(:arch) { '' }
|
|
330 | 346 | end
|
331 | 347 |
|
332 | 348 | 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 | + |
333 | 356 | context 'when nops are set to 0' do
|
334 | 357 | it 'returns the unmodified shellcode' do
|
335 | 358 | expect(payload_generator.prepend_nops(shellcode)).to eq shellcode
|
|
367 | 390 | end
|
368 | 391 |
|
369 | 392 | 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 |
371 | 420 |
|
372 | 421 | it 'returns an array of the right size' do
|
373 | 422 | expect(payload_generator.get_encoders.count).to eq 2
|
374 | 423 | end
|
375 | 424 |
|
376 | 425 | 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 |
379 | 428 | end
|
380 | 429 | end
|
381 | 430 |
|
|
385 | 434 | end
|
386 | 435 |
|
387 | 436 | context 'when no encoder is selected but badchars are present' do
|
388 |
| - let(:encoder) { '' } |
| 437 | + let(:encoder_reference_name) { '' } |
389 | 438 |
|
390 | 439 | it 'returns an array of all encoders with a compatible arch' do
|
391 | 440 | payload_generator.get_encoders.each do |my_encoder|
|
392 |
| - expect(my_encoder.arch).to include arch |
| 441 | + expect(encoder_module.arch).to include arch |
393 | 442 | end
|
394 | 443 | end
|
395 | 444 | end
|
396 | 445 |
|
397 | 446 | context 'when no encoder or badchars are selected' do
|
398 |
| - let(:encoder) { '' } |
| 447 | + let(:encoder_reference_name) { '' } |
399 | 448 | let(:badchars) { '' }
|
400 | 449 |
|
401 | 450 | it 'returns an empty array' do
|
|
407 | 456 | context '#run_encoder' do
|
408 | 457 |
|
409 | 458 | 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) |
413 | 461 | end
|
414 | 462 |
|
415 | 463 | context 'when the encoder makes a buffer too large' do
|
|
454 | 502 | let(:format) { 'war' }
|
455 | 503 |
|
456 | 504 | 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 | + |
458 | 516 | 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 |
463 | 520 | payload_generator.generate_java_payload
|
464 | 521 | end
|
465 | 522 | end
|
|
473 | 530 | let(:format) { 'raw' }
|
474 | 531 |
|
475 | 532 | 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 | + |
477 | 544 | 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 |
482 | 548 | payload_generator.generate_java_payload
|
483 | 549 | end
|
484 | 550 | end
|
485 | 551 |
|
486 | 552 | 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 | + |
488 | 563 | 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 |
493 | 567 | payload_generator.generate_java_payload
|
494 | 568 | end
|
495 | 569 | end
|
|
510 | 584 | context '#generate_payload' do
|
511 | 585 |
|
512 | 586 | 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 |
520 | 593 | end
|
521 | 594 |
|
522 | 595 | 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 | + } |
524 | 606 |
|
525 | 607 | 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 |
529 | 610 | end
|
530 | 611 | end
|
531 | 612 | end
|
|
0 commit comments