1
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:
sinn3r 2013-07-28 19:51:44 -05:00
parent a0decf502f
commit 1a85262afd
3 changed files with 220 additions and 175 deletions

8
msfcli
View File

@ -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
View 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

View File

@ -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"