mirror of
https://github.com/rapid7/metasploit-framework
synced 2024-10-29 18:07:27 +01:00
Refactor msfcli, delete the bash test script, add rspec for msfcli
This commit is contained in:
parent
a0decf502f
commit
1a85262afd
8
msfcli
8
msfcli
@ -62,7 +62,7 @@ class Msfcli
|
||||
# This is what happens if the user doesn't specify a module name:
|
||||
# msfcli will end up loading EVERYTHING to memory to show you a help
|
||||
# menu plus a list of modules available. Really expensive if you ask me.
|
||||
$stderr.puts "[*] Please wait while we load the module tree..."
|
||||
$stdout.puts "[*] Please wait while we load the module tree..."
|
||||
framework = Msf::Simple::Framework.create
|
||||
ext = ''
|
||||
|
||||
@ -267,6 +267,9 @@ class Msfcli
|
||||
# Initializes exploit/payload/encoder/nop modules.
|
||||
#
|
||||
def init_modules
|
||||
@framework = Msf::Simple::Framework.create({'DeferModuleLoads'=>true})
|
||||
$stdout.puts "[*] Initializing modules..."
|
||||
|
||||
module_name = @args[:module_name]
|
||||
modules = {
|
||||
:module => nil, # aux or exploit instance
|
||||
@ -515,9 +518,6 @@ class Msfcli
|
||||
exit
|
||||
end
|
||||
|
||||
@framework = Msf::Simple::Framework.create({'DeferModuleLoads'=>true})
|
||||
$stderr.puts "[*] Initializing modules..."
|
||||
|
||||
begin
|
||||
modules = init_modules
|
||||
rescue Rex::ArgumentParseError => e
|
||||
|
216
test/tests/msfcli.rb
Normal file
216
test/tests/msfcli.rb
Normal file
@ -0,0 +1,216 @@
|
||||
msfbase = __FILE__
|
||||
while File.symlink?(msfbase)
|
||||
msfbase = File.expand_path(File.readlink(msfbase), File.dirname(msfbase))
|
||||
end
|
||||
|
||||
$:.unshift(File.expand_path(File.join(File.dirname(msfbase), '..', '..')))
|
||||
|
||||
# No .rb file extension, use load statement
|
||||
load 'msfcli'
|
||||
|
||||
require 'fastlib'
|
||||
require 'msfenv'
|
||||
require 'msf/ui'
|
||||
require 'msf/base'
|
||||
|
||||
|
||||
# Get stdout:
|
||||
# http://stackoverflow.com/questions/11349270/test-output-to-command-line-with-rspec
|
||||
def get_stdout(&block)
|
||||
out = $stdout
|
||||
$stdout = fake = StringIO.new
|
||||
begin
|
||||
yield
|
||||
ensure
|
||||
$stdout = out
|
||||
end
|
||||
fake.string
|
||||
end
|
||||
|
||||
describe Msfcli do
|
||||
context "Class methods" do
|
||||
|
||||
context ".usage" do
|
||||
it "should see a help menu" do
|
||||
out = get_stdout {
|
||||
cli = Msfcli.new([])
|
||||
cli.usage
|
||||
}
|
||||
out.should =~ /Usage/
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# This one is slow because we're loading all modules
|
||||
#
|
||||
context ".dump_module_list" do
|
||||
it "it should dump a list of modules" do
|
||||
tbl = ''
|
||||
stdout = get_stdout {
|
||||
cli = Msfcli.new([])
|
||||
tbl = cli.dump_module_list
|
||||
}
|
||||
tbl.should =~ /Exploits/ and stdout.should =~ /Please wait/
|
||||
end
|
||||
end
|
||||
|
||||
context ".guess_payload_name" do
|
||||
cli = Msfcli.new([])
|
||||
|
||||
it "should contain matches nedded for windows/meterpreter/reverse_tcp" do
|
||||
m = cli.guess_payload_name('windows/meterpreter/reverse_tcp')
|
||||
m.should eq([/stages\/windows\/meterpreter/, /payloads\/(stagers|stages)\/windows\/.*(reverse_tcp)\.rb$/])
|
||||
end
|
||||
|
||||
it "should contain matches needed for windows/shell/reverse_tcp" do
|
||||
m = cli.guess_payload_name('windows/shell/reverse_tcp')
|
||||
m.should eq([/stages\/windows\/shell/, /payloads\/(stagers|stages)\/windows\/.*(reverse_tcp)\.rb$/])
|
||||
end
|
||||
|
||||
it "should contain matches needed for windows/shell_reverse_tcp" do
|
||||
m = cli.guess_payload_name('windows/shell_reverse_tcp')
|
||||
m.should eq([/stages\/windows\/shell/, /payloads\/(singles|stagers|stages)\/windows\/.*(shell_reverse_tcp)\.rb$/])
|
||||
end
|
||||
|
||||
it "should contain matches needed for php/meterpreter_reverse_tcp" do
|
||||
m = cli.guess_payload_name('php/meterpreter_reverse_tcp')
|
||||
m.should eq([/stages\/php\/meterpreter/, /payloads\/(stagers|stages)\/php\/.*(meterpreter_reverse_tcp)\.rb$/])
|
||||
end
|
||||
|
||||
it "should contain matches needed for linux/x86/meterpreter/reverse_tcp" do
|
||||
m = cli.guess_payload_name('linux/x86/meterpreter/reverse_tcp')
|
||||
m.should eq([/stages\/linux\/x86\/meterpreter/, /payloads\/(stagers|stages)\/linux\/x86\/.*(reverse_tcp)\.rb$/])
|
||||
end
|
||||
|
||||
it "should contain matches needed for java/meterpreter/reverse_tcp" do
|
||||
m = cli.guess_payload_name('java/meterpreter/reverse_tcp')
|
||||
m.should eq([/stages\/java\/meterpreter/, /payloads\/(stagers|stages)\/java\/.*(reverse_tcp)\.rb$/])
|
||||
end
|
||||
|
||||
it "should contain matches needed for cmd/unix/reverse" do
|
||||
m = cli.guess_payload_name('cmd/unix/reverse')
|
||||
m.should eq([/stages\/cmd\/shell/, /payloads\/(singles|stagers|stages)\/cmd\/.*(reverse)\.rb$/])
|
||||
end
|
||||
|
||||
it "should contain matches needed for bsd/x86/shell_reverse_tcp" do
|
||||
m = cli.guess_payload_name('bsd/x86/shell_reverse_tcp')
|
||||
m.should eq([/stages\/bsd\/x86\/shell/, /payloads\/(singles|stagers|stages)\/bsd\/x86\/.*(shell_reverse_tcp)\.rb$/])
|
||||
end
|
||||
end
|
||||
|
||||
context ".guess_encoder_name" do
|
||||
cli = Msfcli.new([])
|
||||
it "should contain a match for x86/shikata_ga_nai" do
|
||||
encoder = 'x86/shikata_ga_nai'
|
||||
m = cli.guess_encoder_name(encoder)
|
||||
m.should eq([/encoders\/#{encoder}/])
|
||||
end
|
||||
end
|
||||
|
||||
context ".guess_nop_name" do
|
||||
cli = Msfcli.new([])
|
||||
it "should contain a match for guess_nop_name" do
|
||||
nop = 'x86/single_byte'
|
||||
m = cli.guess_nop_name(nop)
|
||||
m.should eq([/nops\/#{nop}/])
|
||||
end
|
||||
end
|
||||
|
||||
context ".generate_whitelist" do
|
||||
it "should generate a whitelist for windows/meterpreter/reverse_tcp with default options" do
|
||||
args = 'multi/handler payload=windows/meterpreter/reverse_tcp lhost=127.0.0.1 E'
|
||||
cli = Msfcli.new(args.split(' '))
|
||||
list = cli.generate_whitelist.map { |e| e.to_s }
|
||||
answer = [
|
||||
/multi\/handler/,
|
||||
/stages\/windows\/meterpreter/,
|
||||
/payloads\/(stagers|stages)\/windows\/.*(reverse_tcp)\.rb$/,
|
||||
/post\/.+/,
|
||||
/encoders\/generic\/*/,
|
||||
/encoders\/.+/,
|
||||
/nops\/.+/
|
||||
].map { |e| e.to_s }
|
||||
|
||||
list.should eq(answer)
|
||||
end
|
||||
|
||||
it "should generate a whitelist for windows/meterpreter/reverse_tcp with options: encoder='' post='' nop=''" do
|
||||
args = "multi/handler payload=windows/meterpreter/reverse_tcp lhost=127.0.0.1 encoder='' post='' nop='' E"
|
||||
cli = Msfcli.new(args.split(' '))
|
||||
list = cli.generate_whitelist.map { |e| e.to_s }
|
||||
answer = [
|
||||
/multi\/handler/,
|
||||
/stages\/windows\/meterpreter/,
|
||||
/payloads\/(stagers|stages)\/windows\/.*(reverse_tcp)\.rb$/,
|
||||
/encoders\/''/,
|
||||
/post\/''/,
|
||||
/nops\/''/,
|
||||
/encoders\/generic\/*/
|
||||
].map { |e| e.to_s }
|
||||
|
||||
list.should eq(answer)
|
||||
end
|
||||
|
||||
it "should generate a whitelist for windows/meterpreter/reverse_tcp with options: encoder= post= nop=" do
|
||||
args = "multi/handler payload=windows/meterpreter/reverse_tcp lhost=127.0.0.1 encoder= post= nop= E"
|
||||
cli = Msfcli.new(args.split(' '))
|
||||
list = cli.generate_whitelist.map { |e| e.to_s }
|
||||
answer = [
|
||||
/multi\/handler/,
|
||||
/stages\/windows\/meterpreter/,
|
||||
/payloads\/(stagers|stages)\/windows\/.*(reverse_tcp)\.rb$/,
|
||||
/encoders\/generic\/*/
|
||||
].map { |e| e.to_s }
|
||||
|
||||
list.should eq(answer)
|
||||
end
|
||||
end
|
||||
|
||||
context ".init_modules" do
|
||||
it "should have multi/handler module initialized" do
|
||||
args = "multi/handler payload=windows/meterpreter/reverse_tcp lhost=127.0.0.1 E"
|
||||
m = ''
|
||||
stdout = get_stdout {
|
||||
cli = Msfcli.new(args.split(' '))
|
||||
m = cli.init_modules
|
||||
}
|
||||
|
||||
m[:module].class.to_s.should =~ /^Msf::Modules::/
|
||||
end
|
||||
|
||||
it "should have my payload windows/meterpreter/reverse_tcp initialized" do
|
||||
args = "multi/handler payload=windows/meterpreter/reverse_tcp lhost=127.0.0.1 E"
|
||||
m = ''
|
||||
stdout = get_stdout {
|
||||
cli = Msfcli.new(args.split(' '))
|
||||
m = cli.init_modules
|
||||
}
|
||||
|
||||
m[:payload].class.to_s.should =~ /<Class:/
|
||||
end
|
||||
|
||||
it "should have my modules initialized with the correct parameters" do
|
||||
args = "multi/handler payload=windows/meterpreter/reverse_tcp lhost=127.0.0.1 E"
|
||||
m = ''
|
||||
stdout = get_stdout {
|
||||
cli = Msfcli.new(args.split(' '))
|
||||
m = cli.init_modules
|
||||
}
|
||||
|
||||
m[:module].datastore['lhost'].should eq("127.0.0.1")
|
||||
end
|
||||
|
||||
it "should give me an empty hash as a result of an invalid module name" do
|
||||
args = "WHATEVER payload=windows/meterpreter/reverse_tcp lhost=127.0.0.1 E"
|
||||
m = ''
|
||||
stdout = get_stdout {
|
||||
cli = Msfcli.new(args.split(' '))
|
||||
m = cli.init_modules
|
||||
}
|
||||
|
||||
m.should eq({})
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
@ -1,171 +0,0 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
##
|
||||
#
|
||||
# Test cases for msfcli
|
||||
# Before using this, you need to modify your msfcli like to let to automatically exit
|
||||
# after it's done loading. At line 341, you should see:
|
||||
#
|
||||
# con.run_single("exploit")
|
||||
#
|
||||
# Modify that line to:
|
||||
#
|
||||
# con.run_single("exploit -j")
|
||||
# con.run_single("exit")
|
||||
#
|
||||
##
|
||||
|
||||
|
||||
#
|
||||
# Ask for LHOST
|
||||
#
|
||||
print "[*] Enter LHOST:"
|
||||
lhost = gets.strip
|
||||
|
||||
if lhost.empty?
|
||||
puts "[*] I need a lhost"
|
||||
exit
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Test case keys:
|
||||
# :description = Describe the test case
|
||||
# :command = The command to test
|
||||
# :response = A valid response you expect to see
|
||||
#
|
||||
test_cases = [
|
||||
{
|
||||
:description => "I should see a help menu and a list of modules",
|
||||
:command => "msfcli",
|
||||
:response => "Usage:"
|
||||
},
|
||||
{
|
||||
:description => "I should see a help menu",
|
||||
:command => "msfcli -h",
|
||||
:response => "Usage:"
|
||||
},
|
||||
{
|
||||
:description => "I should get an error saying my module is invalid",
|
||||
:command => "msfcli RANDOMCRAP",
|
||||
:response => "Error: Invalid module"
|
||||
},
|
||||
{
|
||||
:description => "I should get options for module windows/browser/ie_cbutton_uaf",
|
||||
:command => "msfcli windows/browser/ie_cbutton_uaf O",
|
||||
:response => "The URI to use for this exploit"
|
||||
},
|
||||
{
|
||||
:description => "I should be able to run windows/browser/ie_cbutton_uaf",
|
||||
:command => "msfcli windows/browser/ie_cbutton_uaf payload=windows/meterpreter/reverse_tcp lhost=#{lhost} E",
|
||||
:response => "Exploit running"
|
||||
},
|
||||
{
|
||||
:description => "I should be able to run http_version against metasploit.com (208.118.237.137)",
|
||||
:command => "msfcli scanner/http/http_version rhosts=208.118.237.137 E",
|
||||
:response => "Auxiliary module running"
|
||||
},
|
||||
{
|
||||
:description => "I should be able to start a multi/handler with windows/meterpreter/reverse_tcp",
|
||||
:command => "msfcli multi/handler payload=windows/meterpreter/reverse_tcp lhost=#{lhost} E",
|
||||
:response => "Exploit running"
|
||||
},
|
||||
{
|
||||
:description => "I should be able to start a multi/handler with windows/shell_reverse_tcp",
|
||||
:command => "msfcli multi/handler payload=windows/shell_reverse_tcp lhost=#{lhost} E",
|
||||
:response => "Exploit running"
|
||||
},
|
||||
{
|
||||
:description => "I should be able to start a multi/handler with windows/shell/reverse_tcp",
|
||||
:command => "msfcli multi/handler payload=windows/shell/reverse_tcp lhost=#{lhost} E",
|
||||
:response => "Exploit running"
|
||||
},
|
||||
{
|
||||
:description => "I should be able to start a multi/handler with php/meterpreter/reverse_tcp",
|
||||
:command => "msfcli multi/handler payload=php/meterpreter/reverse_tcp lhost=#{lhost} E",
|
||||
:response => "Exploit running"
|
||||
},
|
||||
{
|
||||
:description => "I should be able to start a multi/handler with cmd/unix/generic",
|
||||
:command => "msfcli multi/handler payload=cmd/unix/generic cmd=id E",
|
||||
:response => "Exploit running"
|
||||
},
|
||||
{
|
||||
:description => "I should be able to start multi/handler with bsd/x86/exec",
|
||||
:command => "msfcli multi/handler payload=bsd/x86/exec cmd=id E",
|
||||
:response => "Exploit running"
|
||||
},
|
||||
{
|
||||
:description => "I should be able to start a multi/handler with java/meterpreter/reverse_tcp",
|
||||
:command => "msfcli multi/handler payload=java/meterpreter/reverse_tcp lhost=#{lhost} E",
|
||||
:response => "Exploit running"
|
||||
},
|
||||
{
|
||||
:description => "I should be able to start a multi/handler with linux/x64/exec",
|
||||
:command => "msfcli multi/handler payload=linux/x64/exec cmd=id E",
|
||||
:response => "Exploit running"
|
||||
},
|
||||
{
|
||||
:description => "I should be able to start a multi/handler with linux/x86/meterpreter/reverse_tcp",
|
||||
:command => "msfcli multi/handler payload=linux/x86/meterpreter/reverse_tcp lhost=#{lhost} E",
|
||||
:response => "Exploit running"
|
||||
},
|
||||
{
|
||||
:description => "I should be able to start a multi/handler with linux/x86/shell_reverse_tcp",
|
||||
:command => "msfcli multi/handler payload=linux/x86/shell_reverse_tcp lhost=#{lhost} E",
|
||||
:response => "Exploit running"
|
||||
},
|
||||
{
|
||||
:description => "I should be able to start a multi/handler with windows/x64/shell_reverse_tcp",
|
||||
:command => "msfcli multi/handler payload=windows/x64/shell_reverse_tcp lhost=#{lhost} E",
|
||||
:response => "Exploit running"
|
||||
},
|
||||
{
|
||||
:description => "I should be able to start a multi/handler with windows/meterpreter/reverse_tcp with a x86/fnstenv_mov encoder",
|
||||
:command => "msfcli multi/handler payload=windows/meterpreter/reverse_tcp lhost=#{lhost} encoder=x86/fnstenv_mov E",
|
||||
:response => "Exploit running"
|
||||
},
|
||||
{
|
||||
:description => "I should get an error saying I have a bad encoder",
|
||||
:command => "msfcli multi/handler payload=windows/exec cmd=id encoder=BADENCODER E",
|
||||
:response => "No encoders encoded the buffer successfully"
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
#
|
||||
# Runs a command, checks the response, and returns a pass/fail message.
|
||||
#
|
||||
def test(opts)
|
||||
command = opts[:command]
|
||||
response = opts[:response]
|
||||
description = opts[:description]
|
||||
|
||||
pass_msg = "\033[92mPass\033[0m"
|
||||
fail_msg = "\033[38mFail\033[0m"
|
||||
|
||||
puts "[*] Test: #{description}"
|
||||
o = `#{command}`
|
||||
return (o =~ /#{response}/) ? pass_msg : fail_msg
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Run the test cases
|
||||
#
|
||||
pass_count = 0
|
||||
fail_count = 0
|
||||
puts "[*] Running #{test_cases.length.to_s} test scenarios for msfcli..."
|
||||
test_cases.each do |c|
|
||||
result = test(c)
|
||||
puts "[*] Result: #{result}"
|
||||
if result =~ /Pass/
|
||||
pass_count += 1
|
||||
else
|
||||
fail_count += 1
|
||||
end
|
||||
puts
|
||||
end
|
||||
puts
|
||||
puts "=" * 50
|
||||
puts "[*] Finished #{test_cases.length.to_s} cases. #{pass_count.to_s} passed, #{fail_count.to_s} failed"
|
Loading…
Reference in New Issue
Block a user