adds a method for running remote commands and fixes a slew of bugs with the esx driver

git-svn-id: file:///home/svn/framework3/trunk@14136 4d416f70-5f16-0410-b530-b9f4589650da
This commit is contained in:
Jonathan Cran 2011-11-01 16:15:51 +00:00
parent b809f00979
commit 402ffb3cfa
7 changed files with 181 additions and 110 deletions

View File

@ -1,20 +1,15 @@
This is a list of basic priorities for the lab code...
This is a list of the priorities for the lab code...
1) Implement more technologies
* Implement more technologies
a) finish amazon ec2 (via fog)
b) qemu
c) qemudo
d) kvm
e) other cloud technologies (newservers, slicehost/rackspace,etc)
2) Implement a cloning function on each controller
* Implement a cloning function on each controller
3) Support Windows as a host platform. Currently all the code assumes a linux host is running it. The same applies for the remote_* drivers -- they've not been tested on windows.
* Support Windows as a host platform. Currently all the code assumes a linux host is running it. The same applies for the remote_* drivers -- they've not been tested on windows.
4)
* Consolidate the remote_system_command code & provide a filter. Create an unsafe_system_command and unsafe_remote_system_command function call for when we control the entire string.

View File

@ -20,39 +20,37 @@ class RemoteEsxDriver < VmDriver
@user = filter_command(config['user'])
@host = filter_command(config['host'])
@port = config['port']
end
def start
system_command("ssh #{@user}@#{@host} \"vim-cmd vmsvc/power.on #{@vmid}\"")
remote_system_command("vim-cmd vmsvc/power.on #{@vmid}")
end
def stop
system_command("ssh #{@user}@#{@host} \"vim-cmd vmsvc/power.off #{@vmid}\"")
remote_system_command("vim-cmd vmsvc/power.off #{@vmid}")
end
def suspend
system_command("ssh #{@user}@#{@host} \"vim-cmd vmsvc/power.suspend #{@vmid}\"")
remote_system_command("vim-cmd vmsvc/power.suspend #{@vmid}")
end
def pause # no concept of pause?
system_command("ssh #{@user}@#{@host} \"vim-cmd vmsvc/power.suspend #{@vmid}\"")
def pause
remote_system_command("vim-cmd vmsvc/power.suspend #{@vmid}")
end
def resume
system_command("ssh #{@user}@#{@host} \"vim-cmd vmsvc/power.suspendResume #{@vmid}\"")
remote_system_command("vim-cmd vmsvc/power.suspendResume #{@vmid}")
end
def reset
system_command("ssh #{@user}@#{@host} \"vim-cmd vmsvc/power.reset #{@vmid}\"")
remote_system_command("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]
`ssh #{@user}@#{@host} \"vim-cmd vmsvc/snapshot.create #{@vmid} #{snapshot} \'lab created snapshot\' 1 true\""`
remote_system_command("vim-cmd vmsvc/snapshot.create #{@vmid} #{snapshot} \'lab created snapshot\' 1 true")
end
def revert_snapshot(snapshot)
@ -61,9 +59,14 @@ class RemoteEsxDriver < VmDriver
# Look through our snapshot list, choose the right one based on display_name
snapshots.each do |snapshot_obj|
#puts "DEBUG: checking #{snapshot_obj}"
if snapshot_obj[:display_name].downcase == snapshot.downcase
snapshot_number = snapshot_obj[:name].join(" ")
system_command("ssh #{@user}@#{@host} \"vim-cmd vmsvc/snapshot.revert #{@vmid} #{snapshot_number}\"")
snapshot_identifier = snapshot_obj[:name].join(" ")
#puts "DEBUG: I would revert to #{snapshot_obj}"
remote_system_command("vim-cmd vmsvc/snapshot.revert #{@vmid} 0 #{snapshot_identifier}")
return true
end
end
@ -71,15 +74,30 @@ class RemoteEsxDriver < VmDriver
# If we got here, the snapshot didn't exist
raise "Invalid Snapshot Name"
end
def delete_snapshot(snapshot, remove_children=false)
snapshots = get_snapshots
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\"")
# Look through our snapshot list, choose the right one based on display_name
snapshots.each do |snapshot_obj|
#puts "DEBUG: checking #{snapshot_obj}"
if snapshot_obj[:display_name].downcase == snapshot.downcase
snapshot_identifier = snapshot_obj[:name].join(" ")
remote_system_command("vim-cmd vmsvc/snapshot.remove #{@vmid} #{remove_children} #{snapshot_identifier}")
return true
end
end
# If we got here, the snapshot didn't exist
raise "Invalid Snapshot Name"
end
def delete_all_snapshots
remote_system_command("vim-cmd vmsvc/snapshot.removeall #{@vmid}")
end
def run_command(command)
raise "Not Implemented"
end
@ -116,9 +134,7 @@ class RemoteEsxDriver < VmDriver
power_status_string = `ssh #{@user}@#{@host} \"vim-cmd vmsvc/power.getstate #{@vmid}\"`
return true if power_status_string =~ /Powered on/
false
end
private
end
def get_snapshots
# Command take the format:
@ -141,12 +157,12 @@ private
output_lines.each do |line|
if line.include?("|") # this is a new snapshot
if line.include?("ROOT") # it's a root
current_tree = current_tree + 1 # new tree
snapshots << { :name => [current_tree,current_num], :display_name => output_lines[count+1].split(":").last.strip }
current_num = 0
current_tree = current_tree + 1 # new tree
snapshots << { :name => [current_num, current_tree], :display_name => output_lines[count+1].split(":").last.strip }
else
current_num = current_num + 1 # new snapshot in current tree
snapshots << { :name => [current_tree,current_num], :display_name => output_lines[count+1].split(":").last.strip }
snapshots << { :name => [current_num, current_tree], :display_name => output_lines[count+1].split(":").last.strip }
end
end
count = count+1

View File

@ -23,38 +23,38 @@ class RemoteWorkstationDriver < VmDriver
end
def start
system_command("ssh #{@user}@#{@host} \"vmrun -T ws start \'#{@location}\' nogui\"")
remote_system_command("vmrun -T ws start \'#{@location}\' nogui")
end
def stop
system_command("ssh #{@user}@#{@host} \"vmrun -T ws stop \'#{@location}\' nogui\"")
remote_system_command("vmrun -T ws stop \'#{@location}\' nogui")
end
def suspend
system_command("ssh #{@user}@#{@host} \"vmrun -T ws suspend \'#{@location}\' nogui\"")
remote_system_command("vmrun -T ws suspend \'#{@location}\' nogui")
end
def pause
system_command("ssh #{@user}@#{@host} \"vmrun -T ws pause \'#{@location}\' nogui\"")
remote_system_command("vmrun -T ws pause \'#{@location}\' nogui")
end
def reset
system_command("ssh #{@user}@#{@host} \"vmrun -T ws reset \'#{@location}\' nogui\"")
remote_system_command("vmrun -T ws reset \'#{@location}\' nogui")
end
def create_snapshot(snapshot)
snapshot = filter_input(snapshot)
system_command("ssh #{@user}@#{@host} \"vmrun -T ws snapshot \'#{@location}\' #{snapshot} nogui\"")
remote_system_command("vmrun -T ws snapshot \'#{@location}\' #{snapshot} nogui")
end
def revert_snapshot(snapshot)
snapshot = filter_input(snapshot)
system_command("ssh #{@user}@#{@host} \"vmrun -T ws revertToSnapshot \'#{@location}\' #{snapshot} nogui\"")
remote_system_command("vmrun -T ws revertToSnapshot \'#{@location}\' #{snapshot} nogui")
end
def delete_snapshot(snapshot)
snapshot = filter_input(snapshot)
system_command("ssh #{@user}@#{@host} \"vmrun -T ws deleteSnapshot \'#{@location}\' #{snapshot} nogui\"" )
remote_system_command("vmrun -T ws deleteSnapshot \'#{@location}\' #{snapshot} nogui\"" )
end
def run_command(command)
@ -111,7 +111,7 @@ class RemoteWorkstationDriver < VmDriver
ssh_exec(remote_run_command)
ssh_exec("rm #{remote_tempfile_path}")
else
raise "zomgwtfbbqnotools"
raise "Not Implemented - Install VmWare Tools"
end
end
end
@ -126,9 +126,8 @@ class RemoteWorkstationDriver < VmDriver
if @tools
vmrunstr = "ssh #{@user}@#{@host} \"vmrun -T ws -gu #{@vm_user} -gp #{@vm_pass} " +
"copyFileFromGuestToHost \'#{@location}\' \'#{from}\' \'#{to}\' nogui\""
system_command(vmrunstr)
remote_system_command("ssh #{@user}@#{@host} \"vmrun -T ws -gu #{@vm_user} -gp #{@vm_pass} " +
"copyFileFromGuestToHost \'#{@location}\' \'#{from}\' \'#{to}\' nogui")
else
scp_to(from,to)
end
@ -144,9 +143,8 @@ class RemoteWorkstationDriver < VmDriver
system_command(remote_copy_command)
if @tools
vmrunstr = "ssh #{@user}@#{@host} \"vmrun -T ws -gu #{@vm_user} -gp #{@vm_pass} " +
"copyFileFromHostToGuest \'#{@location}\' \'#{from}\' \'#{to}\' nogui\""
system_command(vmrunstr)
remote_system_command("vmrun -T ws -gu #{@vm_user} -gp #{@vm_pass} " +
"copyFileFromHostToGuest \'#{@location}\' \'#{from}\' \'#{to}\' nogui")
else
scp_to(from,to)
end
@ -156,11 +154,10 @@ class RemoteWorkstationDriver < VmDriver
if @tools
file = filter_input(file)
vmrunstr = "\"ssh #{@user}@#{@host} vmrun -T ws -gu #{@vm_user} -gp #{@vm_pass} " +
"fileExistsInGuest \'#{@location}\' \'{file}\' nogui\""
system_command(vmrunstr)
remote_system_command("vmrun -T ws -gu #{@vm_user} -gp #{@vm_pass} " +
"fileExistsInGuest \'#{@location}\' \'{file}\' nogui")
else
raise "not implemented"
raise "Not Implemented - Install VmWare Tools"
end
end
@ -168,11 +165,11 @@ class RemoteWorkstationDriver < VmDriver
directory = filter_input(directory)
if @tools
vmrunstr = "\"ssh #{@user}@#{@host} vmrun -T ws -gu #{@vm_user} -gp #{@vm_pass} " +
"createDirectoryInGuest \'#{@location}\' \'#{directory}\' nogui\""
emote_system_command("ssh #{@user}@#{@host} vmrun -T ws -gu #{@vm_user} -gp #{@vm_pass} " +
"createDirectoryInGuest \'#{@location}\' \'#{directory}\' nogui")
system_command(vmrunstr)
else
raise "not implemented"
raise "Not Implemented - Install VmWare Tools"
end
end

View File

@ -25,6 +25,7 @@ class VmDriver
@credentials = config["credentials"] || []
@tools = filter_input(config["tools"])
@os = filter_input(config["os"])
@hostname = filter_input(config["hostname"]) || filter_input(config["vmid"].to_s)
# Currently only implemented for the first set
if @credentials.count > 0
@ -34,104 +35,116 @@ class VmDriver
end
end
def register # Must be implemented in a child *_driver class
## This interface must be implemented in a child driver class
## #########################################################
def register
raise "Command not Implemented"
end
def unregister # Must be implemented in a child *_driver class
def unregister
raise "Command not Implemented"
end
def start # Must be implemented in a child *_driver class
def start
raise "Command not Implemented"
end
def stop # Must be implemented in a child *_driver class
def stop
raise "Command not Implemented"
end
def suspend # Must be implemented in a child *_driver class
def suspend
raise "Command not Implemented"
end
def pause # Must be implemented in a child *_driver class
def pause
raise "Command not Implemented"
end
def resume # Must be implemented in a child *_driver class
def resume
raise "Command not Implemented"
end
def reset # Must be implemented in a child *_driver class
def reset
raise "Command not Implemented"
end
def create_snapshot(snapshot) # Must be implemented in a child *_driver class
def create_snapshot(snapshot)
raise "Command not Implemented"
end
def revert_snapshot(snapshot) # Must be implemented in a child *_driver class
def revert_snapshot(snapshot)
raise "Command not Implemented"
end
def delete_snapshot(snapshot) # Must be implemented in a child *_driver class
def delete_snapshot(snapshot)
raise "Command not Implemented"
end
def run_command(command) # Must be implemented in a child *_driver class
def run_command(command)
raise "Command not Implemented"
end
def copy_from(from, to) # Must be implemented in a child *_driver class
def copy_from(from, to)
raise "Command not Implemented"
end
def copy_to(from, to) # Must be implemented in a child *_driver class
def copy_to(from, to)
raise "Command not Implemented"
end
def check_file_exists(file) # Must be implemented in a child *_driver class
def check_file_exists(file)
raise "Command not Implemented"
end
def create_directory(directory) # Must be implemented in a child *_driver class
def create_directory(directory)
raise "Command not Implemented"
end
def cleanup # Must be implemented in a child *_driver class
def cleanup
raise "Command not Implemented"
end
## End Interface
## #########################################################
private
def scp_to(from,to)
require 'net/scp'
def scp_to(local,remote)
#require 'net/scp'
#::Net::SCP.start(@hostname, @vm_user, :password => @vm_pass) do |scp|
# scp.upload!(from,to)
#end
Net::SCP.start(@hostname, @vm_user, :password => @vm_pass) do |scp|
scp.upload!(from,to)
end
system_command("scp #{local} #{@vm_user}@#{@hostname}:#{remote}")
end
def scp_from(from,to)
require 'net/scp'
def scp_from(local,remote)
#require 'net/scp'
# download a file from a remote server
Net::SCP.start(@hostname, @vm_user, :password => @vm_pass) do |scp|
scp.download!(from,to)
end
#::Net::SCP.start(@hostname, @vm_user, :password => @vm_pass) do |scp|
# scp.download!(from,to)
#end
system_command("scp #{@vm_user}@#{@hostname}:#{remote} #{local}")
end
def ssh_exec(command)
Net::SSH.start(@hostname, @vm_user, :password => @vm_pass) do |ssh|
::Net::SSH.start(@hostname, @vm_user, :password => @vm_pass) do |ssh|
result = ssh.exec!(command)
end
`scp #{@vm_user}@#{@hostname} from to`
end
def filter_input(string)
return "" unless string # nil becomes empty string
return unless string.class == String # Allow other types unmodified
unless /^[\w\s\[\]\{\}\/\\\.\-\"\(\):!]*$/.match string
unless /^[\d\w\s\[\]\{\}\/\\\.\-\"\(\):!]*$/.match string
raise "WARNING! Invalid character in: #{string}"
end
@ -142,7 +155,7 @@ private
return "" unless string # nil becomes empty string
return unless string.class == String # Allow other types unmodified
unless /^[\w\s\[\]\{\}\/\\\.\-\"\(\)]*$/.match string
unless /^[\d\w\s\[\]\{\}\/\\\.\-\"\(\)]*$/.match string
raise "WARNING! Invalid character in: #{string}"
end
@ -153,8 +166,14 @@ private
# the ability to still run clean (controlled entirely by us)
# command lines.
def system_command(command)
#puts "DEBUG: system command #{command}"
system(command)
end
def remote_system_command(command)
system_command("ssh #{@user}@#{@host} \"#{command}\"")
end
end
end

View File

@ -1,6 +1,6 @@
require 'vm_driver'
##
## $Id: workstation_driver.rb 11753 2011-02-16 02:15:24Z jcran $
## $Id$
##
# This requires rhythmx's vixr driver from https://github.com/rhythmx/vixr

View File

@ -26,13 +26,14 @@ class Vm
end
# perform the setup only once
def setup_meterpreter
def setup_session
return if @session
# require the framework (assumes this sits in lib/lab/modifiers)
require 'msf/base'
create_framework
create_framework ## TODO - this should use a single framework
## for all hosts, not one-per-host
@session = nil
@session_input = Rex::Ui::Text::Input::Buffer.new
@ -40,29 +41,41 @@ class Vm
if @os == "windows"
exploit_name = 'windows/smb/psexec'
# TODO - check for x86, choose the appropriate payload
payload_name = 'windows/meterpreter/bind_tcp'
options = { "RHOST" => @hostname,
"SMBUser" => @vm_user,
"SMBPass" => @vm_pass}
options = { "RHOST" => @hostname,
"SMBUser" => @vm_user,
"SMBPass" => @vm_pass}
puts "DEBUG: using options #{options}"
# Initialize the exploit instance
exploit = @framework.exploits.create(exploit_name)
begin
begin
# Fire it off.
@session = exploit.exploit_simple(
'Payload' => payload_name,
'Options' => options,
'Options' => options,
'LocalInput' => @session_input,
'LocalOutput' => @session_output)
@session.load_stdapi
rescue
raise "Unable to exploit"
puts "DEBUG: Generated session: #{@session}"
rescue Exception => e
puts "DEBUG: Unable to exploit"
puts e.to_s
end
else
module_name = 'scanner/ssh/ssh_login'
payload_name = 'linux/x86/meterpreter/bind_tcp'
# TODO - check for x86, choose the appropriate payload
payload_name = 'linux/x86/shell_bind_tcp'
options = { "RHOSTS" => @hostname,
"USERNAME" => @vm_user,
"PASSWORD" => @vm_pass,
@ -70,9 +83,13 @@ class Vm
"USER_AS_PASS" => false,
"VERBOSE" => false}
puts "DEBUG: using options #{options}"
# Initialize the module instance
aux = @framework.auxiliary.create(module_name)
puts "DEBUG: created module: #{aux}"
begin
# Fire it off.
aux.run_simple(
@ -82,15 +99,35 @@ class Vm
'LocalOutput' => @session_output)
@session = @framework.sessions.first.last
rescue
raise "Unable to exploit"
puts "DEBUG: Generated session: #{@session}"
rescue Exception => e
puts "DEBUG: Unable to exploit"
puts e.to_s
end
end
end
def run_command(command, timeout=60)
setup_meterpreter
@session.shell_command_token(command, timeout)
setup_session
puts "Using session #{@session}"
# TODO: pass the timeout down
if @session
if @session.type == "shell"
puts "Running command via shell: #{command}"
@session.shell_command_token(command, timeout)
elsif @session.type == "meterpreter"
puts "Running command via meterpreter: #{command}"
@session.shell_command(command) #, timeout)
end
else
raise "No session"
end
end
@ -108,21 +145,21 @@ class Vm
# run_script(script,options)
#end
def copy_to(from,to)
setup_meterpreter
def copy_to(local,remote)
setup_session
if @session.type == "meterpreter"
@session.run_cmd("upload #{from} #{to}")
else
@driver.copy_to(from,to)
@driver.copy_to(local,remote)
end
end
def copy_from(from,to)
setup_meterpreter
def copy_from(local, remote)
setup_session
if @session.type == "meterpreter"
@session.run_cmd("download #{from} #{to}")
else
@driver.copy_from(from,to)
@driver.copy_from(local,remote)
end
end

View File

@ -65,14 +65,17 @@ class Vm
# Only applicable to remote systems
@user = filter_input(config['user']) || nil
@host = filter_input(config['host']) || nil
@port = filter_input(config['port']) || nil
@pass = filter_input(config['pass']) || nil
#Only dynagen systems need this
@platform = config['platform']
#Only fog system need this
#Only fog systems need this
@fog_config = config['fog_config']
#puts "Passing driver config: #{config}"
# Process the correct driver
if @driver_type == "workstation"
@driver = Lab::Drivers::WorkstationDriver.new(config)
@ -221,6 +224,10 @@ class Vm
out += @fog_config.to_yaml
end
if @dynagen_config
out += @dynagen_config.to_yaml
end
out += " credentials:\n"
@credentials.each do |credential|
out += " - user: #{credential['user']}\n"