Initial commit of an esx/esxi driver for the lab plugin (thanks to kernelsmith). Also updated documentation in lib/lab/README.

git-svn-id: file:///home/svn/framework3/trunk@13151 4d416f70-5f16-0410-b530-b9f4589650da
unstable
Jonathan Cran 2011-07-11 05:52:51 +00:00
parent 7737cb22d9
commit 24d2b48f64
9 changed files with 364 additions and 125 deletions

View File

@ -1,61 +1,81 @@
This folder contains the libraries necessary to run the lab plugin, and can also be used in a standalone way to automate virtual machines. This folder contains the libraries necessary to run the lab plugin, and can also be used in a standalone way to automate virtual machines.
Currently you will need to have this code running on a linux box, and your VMHost will likely need to be linux as well. If you're interested in porting it to windows, please contact jcran@metasploit.com.
######### #########
CONCEPTS: CONCEPTS:
######### #########
The lab is designed to provided a clean interface to common vm functions such as start / stop / snapshot / revert and even running system commands. It's designed in an easily-extensible way, so that different VM technologies have the same interface, and you can ignore the specifics of the VM tech. The majority of the functionality is implemented in the form of drivers and controllers. Drivers implement the underlying command for each vm (such as start/stop/revert), whereas controllers implement the commands which apply to all vms (such as listing all running vms).
Drivers: Drivers implement the underlying command for each vm (such as start/stop/revert) If you're interested in porting a technology (see below), please take a look at the workstation_driver.rb and the workstation_controller.rb -- This is the most simple driver / controller in the lab, and you can simply copy / modify this to implement a new technology.
Controllers: Controllers implement the commands which apply to all vms (such as listing all running vms) ##########################
SUPPORTED VM TECHNOLOGIES:
##########################
Currently Supported: Implemented:
workstation (wraps vmrun command) - workstation (Tested against 7.x)
workstation_vixr (uses the vixr gem from rhythmx) - remote_workstation (Tested against 7.x)
remote_workstation (wraps vmrun command on a remote host) - virtualbox (Tested against 4.x)
virtualbox
dynagen (underlying vm for GNS3 - cisco hardware)
Planned:
qemu
qemudo
amazon
others?
DEPENDENCIES: Partially Implemented:
- whatever vm software is necessary for the driver you're using - remote_esxi (VMware ESX Host Agent 4.1.0 build-348481)
- workstation_vixr (via the vixr gem)
- dynagen
Need Implementation:
- qemu
- qemudo
- amazon_ec2
- others?
#################
PLATFORM SUPPORT:
#################
You will need to have this code running on a linux box, Currently this has only been run / tested on Ubuntu 9.04 -> 10.04, though it should run on any linux with an ssh client and the dependencies below. Remote VM Hosts will need to be linux as well, though other platforms may work (untested). If you're interested in porting it to windows, please contact me (jcran).
Platform Dependencies:
- whatever vm software is necessary for the driver you're using (see SUPPORTED VM TECHNOLOGIES)
- net/ssh - the gem (net-ssh), not the msf library. Required to perform ssh_exec in the case tools are not installed on the device. Not necessary if tools are installed. - net/ssh - the gem (net-ssh), not the msf library. Required to perform ssh_exec in the case tools are not installed on the device. Not necessary if tools are installed.
- net/scp - the gem (net-scp). Required to copy files to/from the devices in the case that tools are not installed. Not necessary if tools are installed. - net/scp - the gem (net-scp). Required to copy files to/from the devices in the case that tools are not installed. Not necessary if tools are installed.
- vixr - required to use the workstation_vixr driver - vixr - required to use the workstation_vixr driver.
- fog - required to use the fog_amazon driver
########### ######################
LAB PLUGIN: INTERFACE: LAB PLUGIN:
########### ######################
BACKGROUND: BACKGROUND:
The lab plugin adds a number of commands which may be useful if you're interested in automating remote hosts with rc scripts. If you are testing an IPS / IDS, or determing if an exploit was successful, you'll need to have targets which can be easily started / reverted. The lab plugin provides those commands.
The lab plugin for msfconsole adds a number of commands which may be useful if you're interested in automating remote hosts with rc scripts, or if you need to control targets / support systems while utilizing the metasploit console. A potential use case is testing an IPS / IDS, and resetting the target after running each exploit.
USAGE: USAGE:
msf> load lab
msf> lab_help
msf> lab_load <path_to_lab_file> // see data/lab/test_targets.yml for an example
msf> lab_start vm1
msf> lab_snapshot vm1 emosheep
// do some stuff
msf> lab_revert vm1 emosheep
msf> lab_stop vm1
########### Here's some example usage for the lab plugin.
STANDALONE:
########### msf> load lab // Loads the lab plugin
msf> lab_load <path_to_lab_file> // Loads from a lab configuration file. See data/lab/test_targets.yml for an example
msf> lab_load_dir workstation /path/to/vmx/files // Loads from a local directory.
msf> lab_load_running remote_esx root esx_server // Loads all running vms.
msf> lab_start vm1 // Start a vm which was loaded above
msf> lab_snapshot vm1 snapshot_1 // Snapshot a vm as 'snapshot_1'
msf> lab_run_command ("rm -rf /") // oops!
msf> lab_show // Show all vms that we're aware of
msf> lab_show_running // Show only running vms
msf> lab_start vm2 // Start another vm
msf> lab_suspend vm1 // Suspend a vm
msf> lab_revert all snapshot_1 // Revert all vms back to 'snapshot_1'
###############
STANDALONE API:
###############
BACKGROUND: BACKGROUND:
The lab libraries add tons of useful functionality that isn't exposed through the lab plugin, such as the ability to run commands on hosts. This library can serve as an excellent base for more complex operations on a remote host as well.
The lab libraries add tons of useful functionality that isn't exposed through the lab plugin, such as the ability to run commands on hosts. This library can serve as an excellent base for more complex operations on a remote host as well.
USAGE: USAGE:
You must first create a yaml file which describes your vm. See data/lab/test_targets.yml for an example.
You must first create a yaml file which describes your vm. See data/lab/test_targets.yml for an example.
require 'vm_controller' require 'vm_controller'
vm_controller = ::Lab::Controllers::VmController.new(YAML.load_file(lab_def)) vm_controller = ::Lab::Controllers::VmController.new(YAML.load_file(lab_def))
@ -64,3 +84,5 @@ USAGE:
vm_controller['vm1'].run_command("rm /etc/resolv.conf") vm_controller['vm1'].run_command("rm /etc/resolv.conf")
vm_controller['vm1'].open_uri("http://autopwn:8080") vm_controller['vm1'].open_uri("http://autopwn:8080")
vm_controller['vm1'].revert("clean") vm_controller['vm1'].revert("clean")
vm_controller['vm1'].revert("clean")

View File

@ -0,0 +1,62 @@
# This controller was built against:
# VMware ESX Host Agent 4.1.0 build-348481
module Lab
module Controllers
module RemoteEsxController
# Note that 3.5 was different (vmware-vim-cmd)
VIM_CMD = 'vim-cmd'.freeze
def self.dir_list(basepath=nil)
# Does this method really even make sense for esx?
return "Unsupported :("
end
def self.running_list(user, host)
user.gsub!(/(\W)*/, '')
host.gsub!(/(\W)*/, '')
# first get all registered vms
registered_vms = self.get_vms(user, host) || []
running_vms = []
# now let's see which ones are running
# TODO: this is ghetto, would be better not to connect repeatedly
registered_vms.each do |vm|
remote_cmd = "ssh #{user}@#{host} \"#{VIM_CMD} vmsvc/power.getstate #{vm[:id]}\""
raw = `#{remote_cmd}`
running_vms << vm if raw =~ /Powered on/
end
return running_vms
end
private
def self.get_vms(user, host)
user.gsub!(/(\W)*/, '')
host.gsub!(/(\W)*/, '')
vms = [] # array of VM hashes
remote_cmd = "ssh #{user}@#{host} \"#{VIM_CMD} vmsvc/getallvms | grep ^[0-9] | sed 's/[[:blank:]]\\{3,\\}/ /g'\""
raw = `#{remote_cmd}`.split("\n")
raw.each do |line|
# So effing ghetto
id_and_name = line.split('[datastore').first
id = id_and_name.split(' ').first
## TODO - there's surely a better way to do this.
name_array = id_and_name.split(' ')
name_array.shift
name = name_array.join(' ')
vms << {:id => id, :name => name}
end
return vms
end
end
end
end

View File

@ -0,0 +1,122 @@
require 'vm_driver'
##
## $Id: remote_esx_driver.rb 12713 2011-05-25 07:30:22Z jcran $
##
# This driver was built against:
# VMware ESX Host Agent 4.1.0 build-348481
module Lab
module Drivers
class RemoteEsxDriver < VmDriver
attr_accessor :location # among other things
def initialize(vmid, location, os=nil, tools=false, user=nil, host=nil, credentials=nil)
unless user then raise ArgumentError, "Must provide a username" end
unless host then raise ArgumentError, "Must provide a hostname" end
@vmid = filter_input(vmid)
@location = filter_input(location)
@user = filter_input(user)
@host = filter_input(host)
@credentials = credentials # individually filtered
@tools = tools # not used in command lines, no filter
@os = os # not used in command lines, no filter
# TODO - Currently only implemented for the first set
if @credentials.count > 0
@vm_user = filter_input(@credentials[0]['user'])
@vm_pass = filter_input(@credentials[0]['pass'])
@vm_keyfile = filter_input(@credentials[0]['keyfile'])
end
end
def start
system_command("ssh #{@user}@#{@host} \"vim-cmd vmsvc/power.on #{@vmid}\"")
end
def stop
system_command("ssh #{@user}@#{@host} \"vim-cmd vmsvc/power.off #{@vmid}\"")
end
def suspend
system_command("ssh #{@user}@#{@host} \"vim-cmd vmsvc/power.suspend #{@vmid}\"")
end
def pause # no concept of pause?
system_command("ssh #{@user}@#{@host} \"vim-cmd vmsvc/power.suspend #{@vmid}\"")
end
def resume
system_command("ssh #{@user}@#{@host} \"vim-cmd vmsvc/power.suspendResume #{@vmid}\"")
end
def reset
system_command("ssh #{@user}@#{@host} \"vim-cmd vmsvc/power.reset #{@vmid}\"")
end
def create_snapshot(snapshot)
snapshot = filter_input(snapshot)
#vmware-vim-cmd vmsvc/snapshot.create [vmid: int] [snapshotName: string]
# [snapshotDescription: string] [includeMemory:bool]
system_command("ssh #{@user}@#{@host} \"vim-cmd vmsvc/snapshot.create #{@vmid} #{snapshot} \'lab created snapshot\' 1 true\"")
end
def revert_snapshot(snapshot)
raise "Not Implemented"
#vmware-vim-cmd vmsvc/snapshot.revert [vmid: int] [snapshotlevel: int] [snapshotindex: int]
# not sure how we can do this, would have to list snapshots and map name to level & index
#snapshot = filter_input(snapshot)
#system_command("ssh #{@user}@#{@host} \"vim-cmd vmsvc/snapshot.revert #{@vmid} 0 0\"")
end
def delete_snapshot(snapshot)
raise "Not Implemented"
#snapshot = filter_input(snapshot)
#system_command("ssh #{@user}@#{@host} \"vim-cmd vmsvc/snapshot.remove #{@vmid} true 0 0\"")
end
def run_command(command)
raise "Not Implemented"
end
def copy_from(from, to)
raise "Not Implemented"
end
def copy_to(from, to)
raise "Not Implemented"
end
def check_file_exists(file)
raise "Not Implemented"
end
def create_directory(directory)
raise "Not Implemented"
end
def cleanup
end
def running?
power_status_string = `ssh #{@user}@#{@host} \"vim-cmd vmsvc/power.getstate #{@vmid}\"`
return true if power_status_string =~ /Powered on/
false
end
end
end
end

View File

@ -7,7 +7,6 @@ module RemoteWorkstationController
host.gsub!(/(\W)*/, '') host.gsub!(/(\W)*/, '')
remote_cmd = "ssh #{user}@#{host} \"vmrun list nogui\"" remote_cmd = "ssh #{user}@#{host} \"vmrun list nogui\""
puts "running #{remote_cmd}"
vm_list = `#{remote_cmd}`.split("\n") vm_list = `#{remote_cmd}`.split("\n")
vm_list.shift vm_list.shift

View File

@ -24,7 +24,7 @@ module Drivers
raise ArgumentError,"Error, no vm at: #{@location}" raise ArgumentError,"Error, no vm at: #{@location}"
end end
puts "Registering #{@location}" # Registering @location
@vmid = register_and_return_vmid @vmid = register_and_return_vmid
end end

View File

@ -7,16 +7,17 @@ require 'workstation_vixr_driver'
require 'remote_workstation_driver' require 'remote_workstation_driver'
require 'virtualbox_driver' require 'virtualbox_driver'
require 'dynagen_driver' require 'dynagen_driver'
#require 'fog_amazon_driver' require 'remote_esx_driver'
#require 'amazon_driver'
#require 'qemu_driver' #require 'qemu_driver'
#require 'qemudo_driver' #require 'qemudo_driver'
#require 'amazon_driver'
module Lab module Lab
class Vm class Vm
attr_accessor :vmid attr_accessor :vmid
attr_accessor :name
attr_accessor :descripition
attr_accessor :location attr_accessor :location
attr_accessor :driver attr_accessor :driver
attr_accessor :credentials attr_accessor :credentials
@ -32,6 +33,7 @@ class Vm
## driver (vm technology) ## driver (vm technology)
## user (if applicable - remote system) ## user (if applicable - remote system)
## host (if applicable - remote system) ## host (if applicable - remote system)
## pass (if applicable - remote system)
## location (file / uri) ## location (file / uri)
## credentials (of the form [ {'user'=>"user",'pass'=>"pass", 'admin' => false}, ... ]) ## credentials (of the form [ {'user'=>"user",'pass'=>"pass", 'admin' => false}, ... ])
## os (currently only linux / windows) ## os (currently only linux / windows)
@ -45,13 +47,16 @@ class Vm
@driver = nil @driver = nil
@driver_type = filter_input(config['driver']) @driver_type = filter_input(config['driver'])
@driver_type.downcase! @driver_type.downcase!
@type = filter_input(config['type']) || "unspecified" @name = config['name'] || "" # not used in command lines
@description = config['description'] || "" # not used in command lines
@tools = config['tools'] || false # don't filter this, not used in cmdlines @tools = config['tools'] || false # don't filter this, not used in cmdlines
@os = config['os'] || nil @os = config['os'] || nil
@arch = config['arch'] || nil @arch = config['arch'] || nil
@type = filter_input(config['type']) || "unspecified"
@credentials = config['credentials'] || [] @credentials = config['credentials'] || []
# Optional for virtualbox # Optional for virtualbox
@location = filter_input(config['location']) @location = filter_input(config['location'])
@ -59,11 +64,12 @@ class Vm
@user = filter_input(config['user']) || nil @user = filter_input(config['user']) || nil
@host = filter_input(config['host']) || nil @host = filter_input(config['host']) || nil
# pass might need to be unfiltered, or filtered less
@pass = filter_input(config['pass']) || nil
#Only dynagen #Only dynagen
@platform = config['platform'] @platform = config['platform']
#puts "DEBUG: " + driver_type + " driver requested."
if @driver_type == "workstation" if @driver_type == "workstation"
@driver = Lab::Drivers::WorkstationDriver.new(@vmid, @location, @os, @tools, @credentials) @driver = Lab::Drivers::WorkstationDriver.new(@vmid, @location, @os, @tools, @credentials)
elsif @driver_type == "workstation_vixr" elsif @driver_type == "workstation_vixr"
@ -74,8 +80,8 @@ class Vm
@driver = Lab::Drivers::VirtualBoxDriver.new(@vmid, @location, @credentials) @driver = Lab::Drivers::VirtualBoxDriver.new(@vmid, @location, @credentials)
elsif @driver_type == "dynagen" elsif @driver_type == "dynagen"
@driver = Lab::Drivers::DynagenDriver.new(@vmid, @location,@platform) @driver = Lab::Drivers::DynagenDriver.new(@vmid, @location,@platform)
#elsif @driver_type == "fog_amazon" elsif @driver_type == "remote_esx"
# @driver = Lab::Drivers::FogAmazonDriver.new @driver = Lab::Drivers::RemoteEsxDriver.new(@vmid, @location, @os, @tools, @user, @host, @credentials)
#elsif @driver_type == "qemu" #elsif @driver_type == "qemu"
# @driver = Lab::Drivers::QemuDriver.new # @driver = Lab::Drivers::QemuDriver.new
#elsif @driver_type == "qemudo" #elsif @driver_type == "qemudo"
@ -198,7 +204,7 @@ private
def filter_input(string) def filter_input(string)
return unless string return unless string
if !(string =~ /^[\d*\w*\s*\[\]\{\}\/\\\.\-\"\(\)]*$/) if !(string =~ /^[(!)\d*\w*\s*\[\]\{\}\/\\\.\-\"\(\)]*$/)
raise "WARNING! Invalid character in: #{string}" raise "WARNING! Invalid character in: #{string}"
end end

View File

@ -5,7 +5,7 @@
## ##
## ##
$:.unshift(File.expand_path(File.dirname(__FILE__))) ## Msf Test libraries $:.unshift(File.expand_path(File.dirname(__FILE__)))
require 'find' require 'find'
require 'enumerator' require 'enumerator'
@ -16,8 +16,7 @@ require 'workstation_vixr_controller'
require 'remote_workstation_controller' require 'remote_workstation_controller'
require 'virtualbox_controller' require 'virtualbox_controller'
require 'dynagen_controller' require 'dynagen_controller'
require 'remote_esx_controller'
#require 'fog_amazon_controller'
#require 'qemu_controller' #require 'qemu_controller'
#require 'qemudo_controller' #require 'qemudo_controller'
#require 'amazon_controller' #require 'amazon_controller'
@ -32,7 +31,7 @@ module Controllers
include Lab::Controllers::RemoteWorkstationController include Lab::Controllers::RemoteWorkstationController
include Lab::Controllers::VirtualBoxController include Lab::Controllers::VirtualBoxController
include Lab::Controllers::DynagenController include Lab::Controllers::DynagenController
#include Lab::Controllers::FogAmazonController include Lab::Controllers::RemoteEsxController
#include Lab::Controllers::QemuController #include Lab::Controllers::QemuController
#include Lab::Controllers::QemudoController #include Lab::Controllers::QemudoController
#include Lab::Controllers::AmazonController #include Lab::Controllers::AmazonController
@ -89,6 +88,7 @@ module Controllers
vm = Vm.new(item) vm = Vm.new(item)
@vms << vm unless includes_vmid? vm.vmid @vms << vm unless includes_vmid? vm.vmid
rescue Exception => e rescue Exception => e
# TODO - this needs to go into a logfile and be raised up to an interface.
puts "Invalid VM definition" puts "Invalid VM definition"
puts "Exception: #{e.to_s}" puts "Exception: #{e.to_s}"
end end
@ -128,6 +128,10 @@ module Controllers
vm_list = ::Lab::Controllers::RemoteWorkstationController::dir_list(dir) vm_list = ::Lab::Controllers::RemoteWorkstationController::dir_list(dir)
elsif driver_type.downcase == "virtualbox" elsif driver_type.downcase == "virtualbox"
vm_list = ::Lab::Controllers::VirtualBoxController::dir_list(dir) vm_list = ::Lab::Controllers::VirtualBoxController::dir_list(dir)
elsif driver_type.downcase == "remote_esx"
vm_list =::Lab::Controllers::RemoteEsxController::dir_list(dir)
#elsif driver_type.downcase == "esxi_vixr"
# vm_list =::Lab::Controllers::EsxiVixrController::dir_list(dir)
#elsif driver_type.downcase == "fog_amazon" #elsif driver_type.downcase == "fog_amazon"
# vm_list = ::Lab::Controllers::FogAmazonController::dir_list(dir) # vm_list = ::Lab::Controllers::FogAmazonController::dir_list(dir)
else else
@ -135,7 +139,6 @@ module Controllers
end end
vm_list.each_index do |index| vm_list.each_index do |index|
puts "Creating VM object for: " + vm_list[index]
@vms << Vm.new( {'vmid' => "vm_#{index}", 'driver' => driver_type, 'location' => vm_list[index]} ) @vms << Vm.new( {'vmid' => "vm_#{index}", 'driver' => driver_type, 'location' => vm_list[index]} )
end end
end end
@ -182,11 +185,24 @@ module Controllers
when :virtualbox when :virtualbox
vm_list = ::Lab::Controllers::VirtualBoxController::running_list vm_list = ::Lab::Controllers::VirtualBoxController::running_list
# TODO - why are user and host specified here?
vm_list.each do |item| vm_list.each do |item|
## Add it to the vm list ## Add it to the vm list
@vms << Vm.new( { 'vmid' => "#{item}", @vms << Vm.new( { 'vmid' => "#{item}",
'driver' => driver_type,
'location' => nil, # this will be filled in by the driver
'user' => user,
'host' => host } )
end
when :remote_esx
vm_list = ::Lab::Controllers::RemoteEsxController::running_list(user,host)
vm_list.each do |item|
@vms << Vm.new( { 'vmid' => "#{item[:id]}",
'name' => "#{item[:name]}",
'driver' => driver_type, 'driver' => driver_type,
'location' => nil,
'user' => user, 'user' => user,
'host' => host } ) 'host' => host } )
end end

View File

@ -15,70 +15,79 @@ module Drivers
class VmDriver class VmDriver
def register # Must be implemented in a child *_driver class def register # Must be implemented in a child *_driver class
raise Exception, "Command not Implemented" raise "Command not Implemented"
end end
def unregister # Must be implemented in a child *_driver class def unregister # Must be implemented in a child *_driver class
raise Exception, "Command Not Implemented" raise "Command not Implemented"
end end
def start # Must be implemented in a child *_driver class def start # Must be implemented in a child *_driver class
raise Exception, "Command Not Implemented" raise "Command not Implemented"
end end
def stop # Must be implemented in a child *_driver class def stop # Must be implemented in a child *_driver class
raise Exception, "Command Not Implemented" raise "Command not Implemented"
end end
def suspend # Must be implemented in a child *_driver class def suspend # Must be implemented in a child *_driver class
raise Exception, "Command Not Implemented" raise "Command not Implemented"
end end
def pause # Must be implemented in a child *_driver class def pause # Must be implemented in a child *_driver class
raise Exception, "Command Not Implemented" raise "Command not Implemented"
end
def resume # Must be implemented in a child *_driver class
raise "Command not Implemented"
end end
def reset # Must be implemented in a child *_driver class def reset # Must be implemented in a child *_driver class
raise Exception, "Command Not Implemented" raise "Command not Implemented"
end end
def create_snapshot(snapshot) # Must be implemented in a child *_driver class def create_snapshot(snapshot) # Must be implemented in a child *_driver class
raise Exception, "Command Not Implemented" raise "Command not Implemented"
end end
def revert_snapshot(snapshot) # Must be implemented in a child *_driver class def revert_snapshot(snapshot) # Must be implemented in a child *_driver class
raise Exception, "Command Not Implemented" raise "Command not Implemented"
end end
def delete_snapshot(snapshot) # Must be implemented in a child *_driver class def delete_snapshot(snapshot) # Must be implemented in a child *_driver class
raise Exception, "Command Not Implemented" raise "Command not Implemented"
end end
def run_command(command) # Must be implemented in a child *_driver class def run_command(command) # Must be implemented in a child *_driver class
raise Exception, "Command Not Implemented" raise "Command not Implemented"
end end
def copy_from(from, to) # Must be implemented in a child *_driver class def copy_from(from, to) # Must be implemented in a child *_driver class
raise Exception, "Command Not Implemented" raise "Command not Implemented"
end end
def copy_to(from, to) # Must be implemented in a child *_driver class def copy_to(from, to) # Must be implemented in a child *_driver class
raise Exception, "Command Not Implemented" raise "Command not Implemented"
end end
def check_file_exists(file) # Must be implemented in a child *_driver class def check_file_exists(file) # Must be implemented in a child *_driver class
raise Exception, "Command Not Implemented" raise "Command not Implemented"
end end
def create_directory(directory) # Must be implemented in a child *_driver class def create_directory(directory) # Must be implemented in a child *_driver class
raise Exception, "Command Not Implemented" raise "Command not Implemented"
end end
def cleanup # Must be implemented in a child *_driver class def cleanup # Must be implemented in a child *_driver class
raise Exception, "Command Not Implemented" raise "Command not Implemented"
end end
private private
# Currently this requires the net-ssh and net-scp gems. Ran into problems doing
# it with within metasploit (even though net-ssh is available). TODO - do something
# about this...
def scp_to(from,to) def scp_to(from,to)
gem 'net-ssh' gem 'net-ssh'
require 'net/ssh' require 'net/ssh'
@ -129,7 +138,7 @@ private
end end
def filter_input(string) def filter_input(string)
return unless string return "" unless string
if !(string =~ /^[\w\s\[\]\{\}\/\\\.\-\"\(\):]*$/) if !(string =~ /^[\w\s\[\]\{\}\/\\\.\-\"\(\):]*$/)
raise "WARNING! Invalid character in: #{string}" raise "WARNING! Invalid character in: #{string}"
@ -140,7 +149,6 @@ private
def system_command(command) def system_command(command)
begin begin
#puts "DEBUG: running command #{command}"
system(command) system(command)
rescue Exception => e rescue Exception => e
return false return false

View File

@ -48,55 +48,7 @@ class Plugin::Lab < Msf::Plugin
def name def name
"Lab" "Lab"
end end
##
## Commands for help
##
def longest_cmd_size
commands.keys.map {|x| x.size}.sort.last
end
# No extended help yet, but this is where more detailed documentation
# on particular commands would live. Key is command, (not cmd_command),
# value is the documentation.
def extended_help
{
"lab_fake_cmd" => "This is a fake command. It's got its own special docs." +
(" " * longest_cmd_size) + "It might be long so so deal with formatting somehow."
}
end
# Map for usages
def lab_usage
caller[0][/`cmd_(.*)'/]
cmd = $1
if extended_help[cmd] || commands[cmd]
cmd_lab_help cmd
else # Should never really get here...
print_error "Unknown command. Try 'help'"
end
end
def cmd_lab_help(*args)
if args.empty?
commands.each_pair {|k,v| print_line "%-#{longest_cmd_size}s - %s" % [k,v] }
else
args.each do |c|
if extended_help[c] || commands[c]
print_line "%-#{longest_cmd_size}s - %s" % [c,extended_help[c] || commands[c]]
else
print_error "Unknown command '#{c}'"
end
end
end
print_line
print_line "In order to use this plugin, you'll want to configure a .yml lab file"
print_line "You can find an example in data/lab/test_targets.yml"
print_line
end
## ##
## Regular Lab Commands ## Regular Lab Commands
## ##
@ -337,6 +289,56 @@ class Plugin::Lab < Msf::Plugin
end end
end end
##
## Commands for help
##
def longest_cmd_size
commands.keys.map {|x| x.size}.sort.last
end
# No extended help yet, but this is where more detailed documentation
# on particular commands would live. Key is command, (not cmd_command),
# value is the documentation.
def extended_help
{
"lab_fake_cmd" => "This is a fake command. It's got its own special docs." +
(" " * longest_cmd_size) + "It might be long so so deal with formatting somehow."
}
end
# Map for usages
def lab_usage
caller[0][/`cmd_(.*)'/]
cmd = $1
if extended_help[cmd] || commands[cmd]
cmd_lab_help cmd
else # Should never really get here...
print_error "Unknown command. Try 'help'"
end
end
def cmd_lab_help(*args)
if args.empty?
commands.each_pair {|k,v| print_line "%-#{longest_cmd_size}s - %s" % [k,v] }
else
args.each do |c|
if extended_help[c] || commands[c]
print_line "%-#{longest_cmd_size}s - %s" % [c,extended_help[c] || commands[c]]
else
print_error "Unknown command '#{c}'"
end
end
end
print_line
print_line "In order to use this plugin, you'll want to configure a .yml lab file"
print_line "You can find an example in data/lab/test_targets.yml"
print_line
end
private private
def hlp_print_lab def hlp_print_lab
indent = ' ' indent = ' '
@ -344,11 +346,12 @@ class Plugin::Lab < Msf::Plugin
tbl = Rex::Ui::Text::Table.new( tbl = Rex::Ui::Text::Table.new(
'Header' => 'Available Lab VMs', 'Header' => 'Available Lab VMs',
'Indent' => indent.length, 'Indent' => indent.length,
'Columns' => [ 'Vmid', 'Location', "Powered On" ] 'Columns' => [ 'Vmid', 'Name', 'Location', "Power?" ]
) )
@controller.each do |vm| @controller.each do |vm|
tbl << [ vm.vmid, tbl << [ vm.vmid,
vm.name,
vm.location, vm.location,
vm.running?] vm.running?]
end end
@ -362,12 +365,13 @@ class Plugin::Lab < Msf::Plugin
tbl = Rex::Ui::Text::Table.new( tbl = Rex::Ui::Text::Table.new(
'Header' => 'Running Lab VMs', 'Header' => 'Running Lab VMs',
'Indent' => indent.length, 'Indent' => indent.length,
'Columns' => [ 'Vmid', 'Location', 'Powered On' ] 'Columns' => [ 'Vmid', 'Name', 'Location', 'Power?' ]
) )
@controller.each do |vm| @controller.each do |vm|
if vm.running? if vm.running?
tbl << [ vm.vmid, tbl << [ vm.vmid,
vm.name,
vm.location, vm.location,
vm.running?] vm.running?]
end end