This commit adds a fog-based driver (so cloud services can easily be used as VMs), an example backtrack5 modifier, a meterpreter modifier (so the framework / meterpreter can be used as a command and control driver) and various cleanups to all drivers.
git-svn-id: file:///home/svn/framework3/trunk@13658 4d416f70-5f16-0410-b530-b9f4589650da
This commit is contained in:
parent
5fa7ddf5f4
commit
1b4dc17e7f
|
@ -0,0 +1,6 @@
|
|||
module Lab
|
||||
module Controllers
|
||||
module FogController
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,10 +1,10 @@
|
|||
require 'controller/workstation_controller'
|
||||
require 'controller/workstation_vixr_controller'
|
||||
require 'controller/remote_workstation_controller'
|
||||
require 'controller/virtualbox_controller'
|
||||
require 'controller/fog_controller'
|
||||
require 'controller/dynagen_controller'
|
||||
require 'controller/remote_workstation_controller'
|
||||
require 'controller/remote_esx_controller'
|
||||
#require 'controller/qemu_controller'
|
||||
#require 'controller/qemudo_controller'
|
||||
#require 'controller/amazon_controller'
|
||||
#require 'controller/fog_controller'
|
||||
|
||||
|
||||
|
|
|
@ -12,23 +12,10 @@ require 'vm_driver'
|
|||
module Lab
|
||||
module Drivers
|
||||
class DynagenDriver < VmDriver
|
||||
|
||||
attr_accessor :type
|
||||
attr_accessor :location
|
||||
|
||||
def initialize(vmid,location,platform)
|
||||
|
||||
@vmid = filter_command(vmid)
|
||||
@location = filter_command(location)
|
||||
|
||||
if !File.exist?(location)
|
||||
raise ArgumentError,"Couldn't find: " + location
|
||||
end
|
||||
|
||||
@type = "dynagen"
|
||||
def initialize(config,dynagen_config)
|
||||
super(config)
|
||||
@running = false
|
||||
@platform = filter_command(platform)
|
||||
@credentials = []
|
||||
@dynagen_platform = filter_command(dynagen_config['dynagen_platform'])
|
||||
end
|
||||
|
||||
def start
|
||||
|
@ -36,7 +23,7 @@ module Drivers
|
|||
# and set the autostart property
|
||||
|
||||
## start background dynamips process
|
||||
system_command("dynamips -H #{@platform} &")
|
||||
system_command("dynamips -H #{@dynagen_platform} &")
|
||||
system_command("dynagen #{@location}")
|
||||
@running = true
|
||||
end
|
||||
|
|
|
@ -0,0 +1,166 @@
|
|||
require 'vm_driver'
|
||||
|
||||
##
|
||||
## $Id$
|
||||
##
|
||||
|
||||
module Lab
|
||||
module Drivers
|
||||
class FogDriver < VmDriver
|
||||
|
||||
def initialize(config,fog_config)
|
||||
|
||||
super(config)
|
||||
@fog_config = fog_config
|
||||
|
||||
puts "Fog Config: #{fog_config}"
|
||||
|
||||
# Soft dependency
|
||||
begin
|
||||
require 'fog'
|
||||
rescue LoadError
|
||||
raise "WARNING: Library fog not found. Could Not Create Driver"
|
||||
end
|
||||
|
||||
if @fog_config['fog_type'] == "ec2"
|
||||
|
||||
# AWS / EC2 Base Credential Configuration
|
||||
@aws_cert_file = IO.read(fog_config['fog_aws_cert_file']).chomp if fog_config['fog_aws_cert_file']
|
||||
@aws_private_key_file = IO.read(fog_config['fog_aws_private_key_file']).chomp if fog_config['fog_aws_private_key_file']
|
||||
@ec2_access_key_file = IO.read(fog_config['fog_ec2_access_key_file']).chomp if fog_config['fog_ec2_access_key_file']
|
||||
@ec2_secret_access_key_file = IO.read(fog_config['fog_ec2_secret_access_key_file']).chomp if fog_config['fog_ec2_secret_access_key_file']
|
||||
|
||||
# Instance Keys
|
||||
@ec2_instance_public_key_file = IO.read(fog_config['fog_ec2_instance_public_key_file']).chomp if fog_config['fog_ec2_instance_public_key_file']
|
||||
@ec2_instance_private_key_file = IO.read(fog_config['fog_ec2_instance_private_key_file']).chomp if fog_config['fog_ec2_instance_private_key_file']
|
||||
|
||||
# Instance Details
|
||||
@ec2_base_ami = fog_config['fog_ec2_base_ami']
|
||||
@ec2_flavor = fog_config['fog_ec2_flavor']
|
||||
@ec2_user = fog_config['fog_ec2_user']
|
||||
@ec2_region = fog_config['fog_ec2_region']
|
||||
|
||||
# Set up a connection
|
||||
@compute = Fog::Compute.new(
|
||||
:provider => "Aws",
|
||||
:aws_access_key_id => @aws_access_key_file,
|
||||
:aws_secret_access_key => @aws_secret_access_key_file )
|
||||
else
|
||||
raise "Unsupported Fog Type"
|
||||
end
|
||||
end
|
||||
|
||||
def start
|
||||
ec2_settings = {
|
||||
:image_id => @ec2_base_ami,
|
||||
:flavor_id => @ec2_flavor,
|
||||
:public_key_path => @ec2_instance_public_key_file,
|
||||
:private_key_path => @ec2_instance_private_key_file,
|
||||
:username => @ec2_user}
|
||||
|
||||
begin
|
||||
@fog_server = @compute.servers.bootstrap(ec2_settings)
|
||||
rescue Fog::Compute::AWS::Error => e
|
||||
raise "Couldn't authenticate to AWS - did you place keys in the creds/ directory?"
|
||||
exit
|
||||
end
|
||||
end
|
||||
|
||||
def stop
|
||||
@fog_server.destroy
|
||||
end
|
||||
|
||||
def suspend
|
||||
raise "unimplemented"
|
||||
end
|
||||
|
||||
def pause
|
||||
raise "unimplemented"
|
||||
end
|
||||
|
||||
def reset
|
||||
raise "unimplemented"
|
||||
end
|
||||
|
||||
def create_snapshot(snapshot)
|
||||
raise "unimplemented"
|
||||
end
|
||||
|
||||
def revert_snapshot(snapshot)
|
||||
raise "unimplemented"
|
||||
end
|
||||
|
||||
def delete_snapshot(snapshot)
|
||||
raise "unimplemented"
|
||||
end
|
||||
|
||||
=begin
|
||||
|
||||
def run_command(command)
|
||||
## vm_driver will need a little patching for this to work, as
|
||||
## amis use keys for auth. i think it's just a matter of not passing the
|
||||
## password to ssh_exec. So maybe the thing to do is have a ssh_key_exec
|
||||
## function in vm_driver.rb that does the right thing.
|
||||
|
||||
script_rand_name = rand(10000)
|
||||
|
||||
if @os == "windows"
|
||||
local_tempfile_path = "/tmp/lab_script_#{script_rand_name}.bat"
|
||||
remote_tempfile_path = "C:\\\\lab_script_#{script_rand_name}.bat"
|
||||
remote_run_command = remote_tempfile_path
|
||||
else
|
||||
local_tempfile_path = "/tmp/lab_script_#{script_rand_name}.sh"
|
||||
remote_tempfile_path = "/tmp/lab_script_#{script_rand_name}.sh"
|
||||
remote_run_command = "/bin/sh #{remote_tempfile_path}"
|
||||
end
|
||||
|
||||
# write out our script locally
|
||||
File.open(local_tempfile_path, 'w') {|f| f.write(command) }
|
||||
|
||||
# since we can't copy easily w/o tools, let's just run it directly :/
|
||||
if @os == "linux"
|
||||
output_file = "/tmp/lab_command_output_#{rand(1000000)}"
|
||||
|
||||
scp_to(local_tempfile_path, remote_tempfile_path)
|
||||
ssh_exec(remote_run_command + "> #{output_file}")
|
||||
scp_from(output_file, output_file)
|
||||
ssh_exec("rm #{output_file}")
|
||||
ssh_exec("rm #{remote_tempfile_path}")
|
||||
|
||||
# Ghettohack!
|
||||
string = File.open(output_file,"r").read
|
||||
`rm #{output_file}`
|
||||
|
||||
else
|
||||
raise "zomgwtfbbqnotools"
|
||||
end
|
||||
end
|
||||
|
||||
def copy_from(from, to)
|
||||
raise "unimplemented"
|
||||
end
|
||||
|
||||
def copy_to(from, to)
|
||||
raise "unimplemented"
|
||||
end
|
||||
|
||||
def check_file_exists(file)
|
||||
raise "unimplemented"
|
||||
end
|
||||
|
||||
def create_directory(directory)
|
||||
raise "unimplemented"
|
||||
end
|
||||
=end
|
||||
|
||||
def cleanup
|
||||
@fog_server.destroy
|
||||
end
|
||||
|
||||
def running?
|
||||
return true #TODO
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
|
@ -12,24 +12,15 @@ module Drivers
|
|||
|
||||
class RemoteEsxDriver < VmDriver
|
||||
|
||||
def initialize(vmid,os=nil, tools=false, user=nil, host=nil, credentials=nil)
|
||||
def initialize(config)
|
||||
|
||||
unless user then raise ArgumentError, "Must provide a username" end
|
||||
unless host then raise ArgumentError, "Must provide a hostname" end
|
||||
unless config['user'] then raise ArgumentError, "Must provide a username" end
|
||||
unless config['host'] then raise ArgumentError, "Must provide a hostname" end
|
||||
|
||||
@vmid = filter_command(vmid)
|
||||
@user = filter_command(user)
|
||||
@host = filter_command(host)
|
||||
@credentials = credentials # individually filtered
|
||||
@tools = tools # not used in command lines, no filter
|
||||
@os = os # not used in command lines, no filter
|
||||
super(config)
|
||||
|
||||
# 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
|
||||
@user = filter_command(config['user'])
|
||||
@host = filter_command(config['host'])
|
||||
end
|
||||
|
||||
def start
|
||||
|
@ -62,12 +53,14 @@ class RemoteEsxDriver < VmDriver
|
|||
#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\"")
|
||||
`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
|
||||
|
||||
|
@ -87,11 +80,19 @@ class RemoteEsxDriver < VmDriver
|
|||
end
|
||||
|
||||
def copy_from(from, to)
|
||||
raise "Not Implemented"
|
||||
if @os == "linux"
|
||||
scp_from(from, to)
|
||||
else
|
||||
raise "Unimplemented"
|
||||
end
|
||||
end
|
||||
|
||||
def copy_to(from, to)
|
||||
raise "Not Implemented"
|
||||
if @os == "linux"
|
||||
scp_to(from, to)
|
||||
else
|
||||
raise "Unimplemented"
|
||||
end
|
||||
end
|
||||
|
||||
def check_file_exists(file)
|
||||
|
|
|
@ -11,26 +11,15 @@ class RemoteWorkstationDriver < VmDriver
|
|||
|
||||
attr_accessor :location # among other things
|
||||
|
||||
def initialize(vmid, location, os=nil, tools=false, user=nil, host=nil, credentials=nil)
|
||||
def initialize(config)
|
||||
|
||||
## TODO - Should proabably check file existence?
|
||||
unless user then raise ArgumentError, "Must provide a username" end
|
||||
unless host then raise ArgumentError, "Must provide a hostname" end
|
||||
unless config['user'] then raise ArgumentError, "Must provide a username" end
|
||||
unless config['host'] then raise ArgumentError, "Must provide a hostname" end
|
||||
|
||||
@vmid = filter_command(vmid)
|
||||
@location = filter_command(location)
|
||||
@user = filter_command(user)
|
||||
@host = filter_command(host)
|
||||
@credentials = credentials # individually filtered
|
||||
@tools = tools # not used in command lines, no filter
|
||||
@os = os # not used in command lines, no filter
|
||||
super(config)
|
||||
|
||||
# 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
|
||||
@user = filter_command(config['user'])
|
||||
@host = filter_command(config['host'])
|
||||
end
|
||||
|
||||
def start
|
||||
|
@ -183,7 +172,7 @@ class RemoteWorkstationDriver < VmDriver
|
|||
"createDirectoryInGuest \'#{@location}\' \'#{directory}\' nogui\""
|
||||
system_command(vmrunstr)
|
||||
else
|
||||
ssh_exec(command)
|
||||
raise "not implemented"
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -10,12 +10,10 @@ module Drivers
|
|||
|
||||
attr_accessor :location
|
||||
|
||||
def initialize(vmid, location=nil, credentials=nil)
|
||||
def initialize(config)
|
||||
|
||||
@vmid = filter_command(vmid)
|
||||
@location = filter_command(location)
|
||||
super(config)
|
||||
|
||||
|
||||
## Check to see if we already know this vm, if not, go on location
|
||||
vmid_list = ::Lab::Controllers::VirtualBoxController::config_list
|
||||
unless vmid_list.include? @vmid
|
||||
|
@ -31,15 +29,11 @@ module Drivers
|
|||
|
||||
vmInfo = `VBoxManage showvminfo \"#{@vmid}\" --machinereadable`
|
||||
@location = vmInfo.scan(/CfgFile=\"(.*?)\"/).flatten[0].to_s
|
||||
|
||||
@credentials = credentials
|
||||
|
||||
# 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']) || "\'\'"
|
||||
if !File.exist?(@location)
|
||||
raise ArgumentError,"Couldn't find: " + @location
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
def register_and_return_vmid
|
||||
|
|
|
@ -5,13 +5,33 @@
|
|||
#
|
||||
# !!WARNING!! - All drivers are expected to filter input before running
|
||||
# anything based on it. This is particularly important in the case
|
||||
# of the drivers which wrap a command line program to provide
|
||||
# functionality.
|
||||
# of the drivers which wrap a command line to provide functionality.
|
||||
#
|
||||
|
||||
module Lab
|
||||
module Drivers
|
||||
class VmDriver
|
||||
|
||||
attr_accessor :vmid
|
||||
attr_accessor :location
|
||||
attr_accessor :os
|
||||
attr_accessor :tools
|
||||
attr_accessor :credentials
|
||||
|
||||
def initialize(basic_driver_config)
|
||||
@vmid = filter_command(basic_driver_config["vmid"])
|
||||
@location = filter_command(basic_driver_config["location"])
|
||||
@credentials = basic_driver_config["credentials"] || []
|
||||
@tools = filter_input(basic_driver_config["tools"])
|
||||
@os = filter_input(basic_driver_config["os"])
|
||||
|
||||
# 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 register # Must be implemented in a child *_driver class
|
||||
raise "Command not Implemented"
|
||||
|
@ -83,62 +103,33 @@ class VmDriver
|
|||
|
||||
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)
|
||||
gem 'net-ssh'
|
||||
require 'net/ssh'
|
||||
|
||||
gem 'net-scp'
|
||||
require 'net/scp'
|
||||
|
||||
#begin
|
||||
# upload a file to a remote server
|
||||
|
||||
Net::SCP.start(@vmid, @vm_user, :password => @vm_pass) do |scp|
|
||||
scp.upload!(from,to)
|
||||
end
|
||||
#rescue Exception => e
|
||||
# return false
|
||||
#end
|
||||
end
|
||||
|
||||
def scp_from(from,to)
|
||||
gem 'net-ssh'
|
||||
require 'net/ssh'
|
||||
|
||||
gem 'net-scp'
|
||||
require 'net/scp'
|
||||
|
||||
#begin
|
||||
|
||||
# download a file from a remote server
|
||||
Net::SCP.start(@vmid, @vm_user, :password => @vm_pass) do |scp|
|
||||
scp.download!(from,to)
|
||||
end
|
||||
#rescue Exception => e
|
||||
# return false
|
||||
#end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
def ssh_exec(command)
|
||||
gem 'net-ssh'
|
||||
require 'net/ssh'
|
||||
|
||||
#begin
|
||||
Net::SSH.start(@vmid, @vm_user, :password => @vm_pass) do |ssh|
|
||||
result = ssh.exec!(command)
|
||||
end
|
||||
#rescue Exception => e
|
||||
# return false
|
||||
#end
|
||||
|
||||
end
|
||||
|
||||
def filter_input(string)
|
||||
return "" unless string
|
||||
|
||||
return "" unless string # nil becomes empty string
|
||||
return unless string.class == String # Allow other types unmodified
|
||||
|
||||
if !(string =~ /^[0-9\w\s\[\]\{\}\/\\\.\-\"\(\):!]*$/)
|
||||
raise "WARNING! Invalid character in: #{string}"
|
||||
end
|
||||
|
@ -147,8 +138,9 @@ private
|
|||
end
|
||||
|
||||
def filter_command(string)
|
||||
return "" unless string
|
||||
|
||||
return "" unless string # nil becomes empty string
|
||||
return unless string.class == String # Allow other types unmodified
|
||||
|
||||
if !(string =~ /^[0-9\w\s\[\]\{\}\/\\\.\-\"\(\)]*$/)
|
||||
raise "WARNING! Invalid character in: #{string}"
|
||||
end
|
||||
|
@ -156,12 +148,11 @@ private
|
|||
string
|
||||
end
|
||||
|
||||
# The only reason we don't filter here is because we need
|
||||
# the ability to still run clean (controlled entirely by us)
|
||||
# command lines.
|
||||
def system_command(command)
|
||||
#begin
|
||||
system(command)
|
||||
#rescue Exception => e
|
||||
# return false
|
||||
# end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -9,25 +9,11 @@ module Drivers
|
|||
|
||||
class WorkstationDriver < VmDriver
|
||||
|
||||
attr_accessor :type
|
||||
attr_accessor :location
|
||||
|
||||
def initialize(vmid, location, os=nil, tools=false, credentials=nil)
|
||||
@vmid = filter_command(vmid)
|
||||
@location = filter_command(location)
|
||||
|
||||
def initialize(config)
|
||||
super(config)
|
||||
|
||||
if !File.exist?(@location)
|
||||
raise ArgumentError,"Couldn't find: " + @location
|
||||
end
|
||||
|
||||
@credentials = credentials
|
||||
@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']) || "\'\'"
|
||||
raise ArgumentError,"Couldn't find: #{@location}"
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -132,31 +118,49 @@ class WorkstationDriver < VmDriver
|
|||
def copy_from(from, to)
|
||||
from = filter_input(from)
|
||||
to = filter_input(to)
|
||||
vmrunstr = "vmrun -T ws -gu \'#{@vm_user}\' -gp \'#{@vm_pass}\' copyFileFromGuestToHost " +
|
||||
"\'#{@location}\' \'#{from}\' \'#{to}\'"
|
||||
if @tools
|
||||
vmrunstr = "vmrun -T ws -gu \'#{@vm_user}\' -gp \'#{@vm_pass}\' copyFileFromGuestToHost " +
|
||||
"\'#{@location}\' \'#{from}\' \'#{to}\'"
|
||||
else
|
||||
scp_from(from, to)
|
||||
end
|
||||
system_command(vmrunstr)
|
||||
end
|
||||
|
||||
def copy_to(from, to)
|
||||
from = filter_input(from)
|
||||
to = filter_input(to)
|
||||
vmrunstr = "vmrun -T ws -gu #{@vm_user} -gp #{@vm_pass} copyFileFromHostToGuest " +
|
||||
"\'#{@location}\' \'#{from}\' \'#{to}\'"
|
||||
system_command(vmrunstr)
|
||||
if @tools
|
||||
vmrunstr = "vmrun -T ws -gu #{@vm_user} -gp #{@vm_pass} copyFileFromHostToGuest " +
|
||||
"\'#{@location}\' \'#{from}\' \'#{to}\'"
|
||||
system_command(vmrunstr)
|
||||
else
|
||||
scp_to(from, to)
|
||||
end
|
||||
end
|
||||
|
||||
def check_file_exists(file)
|
||||
file = filter_input(file)
|
||||
vmrunstr = "vmrun -T ws -gu \'#{@vm_user}\' -gp \'#{@vm_pass}\' fileExistsInGuest " +
|
||||
if @tools
|
||||
vmrunstr = "vmrun -T ws -gu \'#{@vm_user}\' -gp \'#{@vm_pass}\' fileExistsInGuest " +
|
||||
"\'#{@location}\' \'#{file}\' "
|
||||
system_command(vmrunstr)
|
||||
system_command(vmrunstr)
|
||||
else
|
||||
raise "Unsupported"
|
||||
end
|
||||
end
|
||||
|
||||
def create_directory(directory)
|
||||
directory = filter_input(directory)
|
||||
vmrunstr = "vmrun -T ws -gu \'#{@vm_user}\' -gp \'#{@vm_pass}\' createDirectoryInGuest " +
|
||||
" \'#{@location}\' \'#{directory}\' "
|
||||
system_command(vmrunstr)
|
||||
if @tools
|
||||
vmrunstr = "vmrun -T ws -gu \'#{@vm_user}\' -gp \'#{@vm_pass}\' createDirectoryInGuest " +
|
||||
" \'#{@location}\' \'#{directory}\' "
|
||||
system_command(vmrunstr)
|
||||
else
|
||||
raise "Unsupported"
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
def cleanup
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
require 'driver/workstation_driver'
|
||||
require 'driver/workstation_vixr_driver'
|
||||
require 'driver/remote_workstation_driver'
|
||||
require 'driver/virtualbox_driver'
|
||||
require 'driver/fog_driver'
|
||||
require 'driver/dynagen_driver'
|
||||
require 'driver/remote_workstation_driver'
|
||||
require 'driver/remote_esx_driver'
|
||||
#require 'driver/qemu_driver'
|
||||
#require 'driver/qemudo_driver'
|
||||
#require 'driver/amazon_driver'
|
||||
#require 'driver/fog_driver'
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
module Lab
|
||||
module Modifier
|
||||
module Backtrack5
|
||||
|
||||
def nmap(options)
|
||||
run_command("nmap #{filter_input(options)}")
|
||||
end
|
||||
|
||||
def testssl(site)
|
||||
run_command("/pentest/scanners/testssl/testssl.sh #{filter_input(site)}")
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
$:.unshift(File.join(File.dirname(__FILE__), '..', '..'))
|
||||
|
||||
module Lab
|
||||
module Modifier
|
||||
module Meterpreter
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# This allows us to override the default way of running commands
|
||||
# Currently useful for the esx controller
|
||||
|
||||
module Lab
|
||||
class Vm
|
||||
|
||||
attr_accessor :framework
|
||||
attr_accessor :session
|
||||
attr_accessor :session_input
|
||||
attr_accessor :session_output
|
||||
|
||||
|
||||
def create_framework
|
||||
return if @framework
|
||||
@framework = Msf::Simple::Framework.create
|
||||
end
|
||||
|
||||
# perform the setup only once
|
||||
def setup_meterpreter
|
||||
return if @session
|
||||
|
||||
# require the framework (assumes this sits in lib/lab/modifiers)
|
||||
require 'msf/base'
|
||||
|
||||
create_framework
|
||||
|
||||
@session = nil
|
||||
@session_input = Rex::Ui::Text::Input::Buffer.new
|
||||
@session_output = Rex::Ui::Text::Output::Buffer.new
|
||||
|
||||
if @os == "windows"
|
||||
exploit_name = 'windows/smb/psexec'
|
||||
payload_name = 'windows/meterpreter/bind_tcp'
|
||||
options = { "RHOST" => @vmid,
|
||||
"SMBUser" => @vm_user,
|
||||
"SMBPass" => @vm_pass}
|
||||
|
||||
# Initialize the exploit instance
|
||||
exploit = @framework.exploits.create(exploit_name)
|
||||
|
||||
begin
|
||||
# Fire it off.
|
||||
@session = exploit.exploit_simple(
|
||||
'Payload' => payload_name,
|
||||
'Options' => options,
|
||||
'LocalInput' => @session_input,
|
||||
'LocalOutput' => @session_output)
|
||||
@session.load_stdapi
|
||||
rescue
|
||||
raise "Unable to exploit"
|
||||
end
|
||||
|
||||
else
|
||||
module_name = 'scanner/ssh/ssh_login'
|
||||
payload_name = 'linux/x86/meterpreter/bind_tcp'
|
||||
options = { "RHOSTS" => @vmid,
|
||||
"USERNAME" => @vm_user,
|
||||
"PASSWORD" => @vm_pass,
|
||||
"BLANK_PASSWORDS" => false,
|
||||
"USER_AS_PASS" => false,
|
||||
"VERBOSE" => false}
|
||||
|
||||
# Initialize the module instance
|
||||
aux = @framework.auxiliary.create(module_name)
|
||||
|
||||
begin
|
||||
# Fire it off.
|
||||
aux.run_simple(
|
||||
'Payload' => payload_name,
|
||||
'Options' => options,
|
||||
'LocalInput' => @session_input,
|
||||
'LocalOutput' => @session_output)
|
||||
|
||||
@session = @framework.sessions.first.last
|
||||
rescue
|
||||
raise "Unable to exploit"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def run_command(command, timeout=60)
|
||||
setup_meterpreter
|
||||
@session.shell_command_token(command, timeout)
|
||||
end
|
||||
|
||||
|
||||
# This isn't part of the normal API, but too good to pass up.
|
||||
def run_script(script, options)
|
||||
if @session.type == "meterpreter"
|
||||
@session.execute_script(script, options)
|
||||
else
|
||||
raise "Unsupported on #{@session.type}"
|
||||
end
|
||||
end
|
||||
|
||||
# For meterpreter API compatibility
|
||||
#def execute_file(script,options)
|
||||
# run_script(script,options)
|
||||
#end
|
||||
|
||||
def copy_to(from,to)
|
||||
setup_meterpreter
|
||||
if @session.type == "meterpreter"
|
||||
@session.run_cmd("upload #{from} #{to}")
|
||||
else
|
||||
@driver.copy_to(from,to)
|
||||
end
|
||||
end
|
||||
|
||||
def copy_from(from,to)
|
||||
setup_meterpreter
|
||||
if @session.type == "meterpreter"
|
||||
@session.run_cmd("download #{from} #{to}")
|
||||
else
|
||||
@driver.copy_from(from,to)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -4,6 +4,13 @@
|
|||
module Lab
|
||||
module Modifier
|
||||
module Test
|
||||
def dhclient
|
||||
run_command("sudo dhclient")
|
||||
end
|
||||
|
||||
def route
|
||||
run_command("route -n")
|
||||
end
|
||||
|
||||
def install_nmap
|
||||
run_command("sudo apt-get install nmap")
|
||||
|
@ -12,11 +19,6 @@ module Test
|
|||
def nmap(options)
|
||||
run_command("nmap #{filter_input(options)}")
|
||||
end
|
||||
|
||||
def test
|
||||
run_command("echo yo!")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -1 +1,3 @@
|
|||
require 'modifier/test_modifier'
|
||||
require 'modifier/backtrack_modifier'
|
||||
require 'modifier/meterpreter_modifier'
|
||||
|
|
|
@ -31,64 +31,70 @@ class Vm
|
|||
|
||||
def initialize(config = {})
|
||||
|
||||
# Mandatory
|
||||
# TODO - This is such a mess. clean up, and pass stuff down to drivers
|
||||
# and then rework the code that uses this api.
|
||||
@vmid = config['vmid']
|
||||
raise "Invalid VMID" unless @vmid
|
||||
|
||||
@driver = nil
|
||||
@driver_type = filter_input(config['driver'])
|
||||
@driver_type.downcase!
|
||||
|
||||
@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
|
||||
@os = config['os'] || nil
|
||||
@arch = config['arch'] || nil
|
||||
@location = filter_input(config['location'])
|
||||
@name = config['name'] || ""
|
||||
@description = config['description'] || ""
|
||||
@tools = config['tools'] || ""
|
||||
@os = config['os'] || ""
|
||||
@arch = config['arch'] || ""
|
||||
@type = filter_input(config['type']) || "unspecified"
|
||||
@credentials = config['credentials'] || []
|
||||
|
||||
# Load in a list of modifiers. These provide additional methods
|
||||
# TODO - currently it is up to the user to verify that
|
||||
# modifiers are properly used with the correct VM image. If not,
|
||||
# the results are likely to be disasterous.
|
||||
@modifiers = config['modifiers']
|
||||
|
||||
# Optional for virtualbox
|
||||
@location = filter_input(config['location'])
|
||||
|
||||
# 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
|
||||
|
||||
# Only applicable to remote systems
|
||||
@user = filter_input(config['user']) || 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 systems need this
|
||||
@platform = config['platform']
|
||||
|
||||
#Only fog system need this
|
||||
@fog_config = config['fog_config']
|
||||
|
||||
# Process the correct driver
|
||||
if @driver_type == "workstation"
|
||||
@driver = Lab::Drivers::WorkstationDriver.new(@vmid, @location, @os, @tools, @credentials)
|
||||
elsif @driver_type == "workstation_vixr"
|
||||
@driver = Lab::Drivers::WorkstationVixrDriver.new(@vmid, @location, @os, @tools, @user, @host, @credentials)
|
||||
elsif @driver_type == "remote_workstation"
|
||||
@driver = Lab::Drivers::RemoteWorkstationDriver.new(@vmid, @location, @os, @tools, @user, @host, @credentials)
|
||||
@driver = Lab::Drivers::WorkstationDriver.new(config)
|
||||
elsif @driver_type == "virtualbox"
|
||||
@driver = Lab::Drivers::VirtualBoxDriver.new(@vmid, @location, @credentials)
|
||||
@driver = Lab::Drivers::VirtualBoxDriver.new(config)
|
||||
elsif @driver_type == "fog"
|
||||
@driver = Lab::Drivers::FogDriver.new(config, config['fog_config'])
|
||||
elsif @driver_type == "dynagen"
|
||||
@driver = Lab::Drivers::DynagenDriver.new(@vmid, @location,@platform)
|
||||
@driver = Lab::Drivers::DynagenDriver.new(config, config['dynagen_config'])
|
||||
elsif @driver_type == "remote_esx"
|
||||
@driver = Lab::Drivers::RemoteEsxDriver.new(@vmid, @os, @tools, @user, @host, @credentials)
|
||||
@driver = Lab::Drivers::RemoteEsxDriver.new(config)
|
||||
elsif @driver_type == "remote_workstation"
|
||||
@driver = Lab::Drivers::RemoteWorkstationDriver.new(config)
|
||||
#elsif @driver_type == "qemu"
|
||||
# @driver = Lab::Drivers::QemuDriver.new
|
||||
#elsif @driver_type == "qemudo"
|
||||
# @driver = Lab::Drivers::QemudoDriver.new
|
||||
#elsif @driver_type == "fog"
|
||||
# @driver = Lab::Drivers::FogDriver.new
|
||||
else
|
||||
raise "Unknown Driver Type"
|
||||
end
|
||||
|
||||
|
||||
# Load in a list of modifiers. These provide additional methods
|
||||
# Currently it is up to the user to verify that
|
||||
# modifiers are properly used with the correct VM image.
|
||||
#
|
||||
# If not, the results are likely to be disasterous.
|
||||
@modifiers = config['modifiers']
|
||||
|
||||
if @modifiers
|
||||
@modifiers.each { |modifier| self.class.send(:include, eval("Lab::Modifier::#{modifier}"))}
|
||||
end
|
||||
|
@ -176,34 +182,48 @@ class Vm
|
|||
end
|
||||
|
||||
def to_s
|
||||
return "#{@vmid}: #{@location}"
|
||||
return "#{@vmid}"
|
||||
end
|
||||
|
||||
def to_yaml
|
||||
|
||||
# TODO - push this down to the drivers.
|
||||
|
||||
# Standard configuration options
|
||||
out = " - vmid: #{@vmid}\n"
|
||||
out += " driver: #{@driver_type}\n"
|
||||
out += " location: #{@driver.location}\n"
|
||||
out += " location: #{@location}\n"
|
||||
out += " type: #{@type}\n"
|
||||
out += " tools: #{@tools}\n"
|
||||
out += " os: #{@os}\n"
|
||||
out += " arch: #{@arch}\n"
|
||||
|
||||
if @user or @host # Remote vm/drivers only
|
||||
out += " user: #{@user}\n"
|
||||
out += " host: #{@host}\n"
|
||||
end
|
||||
|
||||
if @platform
|
||||
out += " platform: #{@platform}\n"
|
||||
end
|
||||
|
||||
if @fog_config
|
||||
out += @fog_config.to_yaml
|
||||
end
|
||||
|
||||
out += " credentials:\n"
|
||||
@credentials.each do |credential|
|
||||
out += " - user: #{credential['user']}\n"
|
||||
out += " pass: #{credential['pass']}\n"
|
||||
end
|
||||
|
||||
|
||||
return out
|
||||
end
|
||||
private
|
||||
|
||||
def filter_input(string)
|
||||
return unless string
|
||||
return "" unless string # nil becomes empty string
|
||||
return unless string.class == String # Allow other types
|
||||
|
||||
if !(string =~ /^[(!)\d*\w*\s*\[\]\{\}\/\\\.\-\"\(\)]*$/)
|
||||
raise "WARNING! Invalid character in: #{string}"
|
||||
|
|
|
@ -27,25 +27,20 @@ module Controllers
|
|||
|
||||
include Enumerable
|
||||
include Lab::Controllers::WorkstationController
|
||||
include Lab::Controllers::WorkstationVixrController
|
||||
include Lab::Controllers::RemoteWorkstationController
|
||||
include Lab::Controllers::VirtualBoxController
|
||||
include Lab::Controllers::FogController
|
||||
include Lab::Controllers::DynagenController
|
||||
include Lab::Controllers::RemoteEsxController
|
||||
include Lab::Controllers::RemoteWorkstationController
|
||||
#include Lab::Controllers::QemuController
|
||||
#include Lab::Controllers::QemudoController
|
||||
#include Lab::Controllers::AmazonController
|
||||
#include Lab::Controllers::FogController
|
||||
|
||||
|
||||
def initialize (labdef=nil)
|
||||
@vms = [] ## Start with an empty array of vms
|
||||
|
||||
## labdef is a big array of hashes, use yaml to store
|
||||
labdef = [] unless labdef
|
||||
|
||||
## Create vm objects from the lab definition
|
||||
load_vms(labdef)
|
||||
# Start with an empty array of vm objects
|
||||
@vms = []
|
||||
|
||||
# labdef is a just a big array of hashes
|
||||
load_vms(labdef) if labdef
|
||||
end
|
||||
|
||||
def clear!
|
||||
|
@ -53,7 +48,12 @@ module Controllers
|
|||
end
|
||||
|
||||
def [](x)
|
||||
find_by_vmid(x)
|
||||
# Support indexing by both names and number
|
||||
if x.class == String
|
||||
find_by_vmid(x)
|
||||
else
|
||||
return @vms[x]
|
||||
end
|
||||
end
|
||||
|
||||
def find_by_vmid(vmid)
|
||||
|
@ -65,8 +65,7 @@ module Controllers
|
|||
return nil
|
||||
end
|
||||
|
||||
def add_vm(vmid, type,location,credentials=nil,user=nil,host=nil)
|
||||
|
||||
def add_vm(vmid, location=nil, os=nil, tools=nil, credentials=nil, user=nil, host=nil)
|
||||
@vms << Vm.new( { 'vmid' => vmid,
|
||||
'driver' => type,
|
||||
'location' => location,
|
||||
|
@ -80,20 +79,13 @@ module Controllers
|
|||
end
|
||||
|
||||
def from_file(file)
|
||||
labdef = YAML::load_file(file)
|
||||
load_vms(labdef)
|
||||
load_vms(YAML::load_file(file))
|
||||
end
|
||||
|
||||
def load_vms(vms)
|
||||
vms.each do |item|
|
||||
begin
|
||||
vm = Vm.new(item)
|
||||
@vms << vm unless includes_vmid? vm.vmid
|
||||
rescue Exception => e
|
||||
# TODO - this needs to go into a logfile and be raised up to an interface.
|
||||
puts "Invalid VM definition"
|
||||
puts "Exception: #{e.to_s}"
|
||||
end
|
||||
vm = Vm.new(item)
|
||||
@vms << vm unless includes_vmid? vm.vmid
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -110,10 +102,10 @@ module Controllers
|
|||
end
|
||||
|
||||
def includes_vmid?(vmid)
|
||||
@vms.each do |vm|
|
||||
@vms.each do |vm|
|
||||
return true if (vm.vmid == vmid)
|
||||
end
|
||||
return false
|
||||
false
|
||||
end
|
||||
|
||||
def build_from_dir(driver_type, dir, clear=false)
|
||||
|
@ -124,18 +116,16 @@ module Controllers
|
|||
|
||||
if driver_type.downcase == "workstation"
|
||||
vm_list = ::Lab::Controllers::WorkstationController::dir_list(dir)
|
||||
elsif driver_type.downcase == "workstation_vixr"
|
||||
vm_list = ::Lab::Controllers::WorkstationVixrController::dir_list(dir)
|
||||
elsif driver_type.downcase == "remote_workstation"
|
||||
vm_list = ::Lab::Controllers::RemoteWorkstationController::dir_list(dir)
|
||||
elsif driver_type.downcase == "virtualbox"
|
||||
vm_list = ::Lab::Controllers::VirtualBoxController::dir_list(dir)
|
||||
elsif driver_type.downcase == "fog"
|
||||
vm_list = ::Lab::Controllers::FogController::dir_list(dir)
|
||||
elsif driver_type.downcase == "Dynagen"
|
||||
vm_list = ::Lab::Controllers::DynagenController::dir_list(dir)
|
||||
elsif driver_type.downcase == "remote_workstation"
|
||||
vm_list = ::Lab::Controllers::RemoteWorkstationController::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"
|
||||
# vm_list = ::Lab::Controllers::FogController::dir_list(dir)
|
||||
else
|
||||
raise TypeError, "Unsupported VM Type"
|
||||
end
|
||||
|
@ -168,6 +158,19 @@ module Controllers
|
|||
'host' => host } )
|
||||
end
|
||||
|
||||
|
||||
when :virtualbox
|
||||
vm_list = ::Lab::Controllers::VirtualBoxController::running_list
|
||||
vm_list.each do |item|
|
||||
## Add it to the vm list
|
||||
@vms << Vm.new( { 'vmid' => "#{item}",
|
||||
'driver' => driver_type,
|
||||
'location' => nil })
|
||||
end
|
||||
when :fog
|
||||
raise "Unsupported" # TODO - figure out a way to allow this
|
||||
when :dynagen
|
||||
raise "Unsupported"
|
||||
when :remote_workstation
|
||||
vm_list = ::Lab::Controllers::RemoteWorkstationController::running_list(user, host)
|
||||
|
||||
|
@ -183,21 +186,6 @@ module Controllers
|
|||
'user' => user,
|
||||
'host' => host } )
|
||||
end
|
||||
|
||||
when :virtualbox
|
||||
vm_list = ::Lab::Controllers::VirtualBoxController::running_list
|
||||
|
||||
# TODO - why are user and host specified here?
|
||||
|
||||
vm_list.each do |item|
|
||||
## Add it to the vm list
|
||||
@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)
|
||||
|
||||
|
@ -216,7 +204,6 @@ module Controllers
|
|||
end
|
||||
|
||||
def build_from_config(driver_type=nil, user=nil, host=nil, clear=false)
|
||||
|
||||
if clear
|
||||
@vms = []
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue