diff --git a/lib/lab/driver/remote_esx_driver.rb b/lib/lab/driver/remote_esx_driver.rb index b928f6c1cc..3beeb800f1 100644 --- a/lib/lab/driver/remote_esx_driver.rb +++ b/lib/lab/driver/remote_esx_driver.rb @@ -97,26 +97,6 @@ class RemoteEsxDriver < VmDriver def delete_all_snapshots remote_system_command("vim-cmd vmsvc/snapshot.removeall #{@vmid}") end - - def run_command(command) - raise "Not Implemented" - end - - def copy_from_guest(from, to) - if @os == "linux" - scp_from(from, to) - else - raise "Unimplemented" - end - end - - def copy_to_guest(from, to) - if @os == "linux" - scp_to(from, to) - else - raise "Unimplemented" - end - end def check_file_exists(file) raise "Not Implemented" @@ -126,16 +106,137 @@ class RemoteEsxDriver < VmDriver raise "Not Implemented" end - def cleanup + def run_command(command, timeout=60) + + 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) + end + else + raise "No session" + end + end + def copy_to_guest(local,remote) + setup_session + if @session.type == "meterpreter" + @session.run_cmd("upload #{local} #{remote}") + else + @driver.copy_to(local,remote) + end + end + + def copy_from_guest(local, remote) + setup_session + if @session.type == "meterpreter" + @session.run_cmd("download #{local} #{remote}") + else + @driver.copy_from(local,remote) + end + 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/ - true + power_status_string = `ssh #{@user}@#{@host} \"vim-cmd vmsvc/power.getstate #{@vmid}\"` + return true if power_status_string =~ /Powered on/ end +private + + def create_framework + return if @framework + @framework = Msf::Simple::Framework.create + end + + # perform the setup only once + def setup_session + return if @session + + # require the framework (assumes this sits in lib/lab/modifiers) + require 'msf/base' + + 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 + @session_output = Rex::Ui::Text::Output::Buffer.new + + 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} + + #puts "DEBUG: using options #{options}" + + # 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 + + #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' + + # TODO - check for x86, choose the appropriate payload + + payload_name = 'linux/x86/shell_bind_tcp' + options = { "RHOSTS" => @hostname, + "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) + + #puts "DEBUG: created module: #{aux}" + + begin + # Fire it off. + aux.run_simple( + 'Payload' => payload_name, + 'Options' => options, + 'LocalInput' => @session_input, + 'LocalOutput' => @session_output) + + @session = @framework.sessions.first.last + rescue Exception => e + #puts "DEBUG: Unable to exploit" + #puts e.to_s + end + end + end + def get_snapshots # Command take the format: # vmware-vim-cmd vmsvc/snapshot.revert [vmid: int] [snapshotlevel: int] [snapshotindex: int] @@ -147,7 +248,7 @@ class RemoteEsxDriver < VmDriver # ... snapshots = [] - # Use these to keep track of the parsing... + # Use these to keep track of the parsing... current_tree = -1 current_num = 0 count = 0 diff --git a/lib/lab/driver/vm_driver.rb b/lib/lab/driver/vm_driver.rb index c3610456c0..b25280ae3a 100644 --- a/lib/lab/driver/vm_driver.rb +++ b/lib/lab/driver/vm_driver.rb @@ -86,11 +86,11 @@ class VmDriver def run_command(command) raise "Command not Implemented" end - + def copy_from_guest(from, to) raise "Command not Implemented" end - + def copy_to_guest(from, to) raise "Command not Implemented" end @@ -117,7 +117,6 @@ private #::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 @@ -127,17 +126,13 @@ private #::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| result = ssh.exec!(command) end - `scp #{@vm_user}@#{@hostname} from to` end @@ -148,7 +143,6 @@ private unless /^[\d\w\s\[\]\{\}\/\\\.\-\"\(\):!]*$/.match string raise "WARNING! Invalid character in: #{string}" end - string end @@ -159,18 +153,17 @@ private unless /^[\d\w\s\[\]\{\}\/\\\.\-\"\(\)]*$/.match string raise "WARNING! Invalid character in: #{string}" end - 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) `#{command}` end - - + + def remote_system_command(command) system_command("ssh #{@user}@#{@host} \"#{command}\"") end diff --git a/lib/lab/modifier/meterpreter_modifier.rb b/lib/lab/modifier/meterpreter_modifier.rb index 3ccb8c535e..94d89f44a2 100644 --- a/lib/lab/modifier/meterpreter_modifier.rb +++ b/lib/lab/modifier/meterpreter_modifier.rb @@ -1,26 +1,73 @@ $:.unshift(File.join(File.dirname(__FILE__), '..', '..')) - - - - # This allows us to override the default way of running commands -# Currently useful for the esx controller +# Currently useful for the remote esx driver module Lab module Modifier module Meterpreter - + 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 + def meterpreter_run_command(command, timeout=60) + + 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 + def meterpreter_copy_to_guest(local,remote) + puts "DEBUG: Meterpreter" + setup_session + if @session.type == "meterpreter" + @session.run_cmd("upload #{local} #{remote}") + else + @driver.copy_to(local,remote) + end + end + + def meterpreter_copy_from_guest(local, remote) + puts "DEBUG: Meterpreter" + setup_session + if @session.type == "meterpreter" + @session.run_cmd("download #{local} #{remote}") + else + @driver.copy_from(local,remote) + end + end + + # This isn't part of the normal API, but too good to pass up. + def meterpreter_run_script(script, options) + if @session.type == "meterpreter" + @session.execute_script(script, options) + else + raise "Unsupported on #{@session.type}" + end + end + +private + + def create_framework + return if @framework + @framework = Msf::Simple::Framework.create + end + # perform the setup only once def setup_session return if @session @@ -28,12 +75,11 @@ module Meterpreter # require the framework (assumes this sits in lib/lab/modifiers) require 'msf/base' - create_framework ## TODO - this should use a single framework - ## for all hosts, not one-per-host + 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 - @session_output = Rex::Ui::Text::Output::Buffer.new + @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' @@ -41,11 +87,12 @@ module Meterpreter # 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}" + puts "DEBUG: using options #{options}" # Initialize the exploit instance exploit = @framework.exploits.create(exploit_name) @@ -79,7 +126,7 @@ module Meterpreter "USER_AS_PASS" => false, "VERBOSE" => false} - puts "DEBUG: using options #{options}" + puts "DEBUG: using options #{options}" # Initialize the module instance aux = @framework.auxiliary.create(module_name) @@ -101,64 +148,7 @@ module Meterpreter puts e.to_s end end - - - end - - def run_command(command, timeout=60) - - 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 - - - # 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_guest(local,remote) - setup_session - if @session.type == "meterpreter" - @session.run_cmd("upload #{local} #{remote}") - else - @driver.copy_to(local,remote) - end - end - - def copy_from_guest(local, remote) - setup_session - if @session.type == "meterpreter" - @session.run_cmd("download #{local} #{remote}") - else - @driver.copy_from(local,remote) - end - end - end end end diff --git a/lib/lab/vm.rb b/lib/lab/vm.rb index 789304037b..48f8018cf1 100644 --- a/lib/lab/vm.rb +++ b/lib/lab/vm.rb @@ -103,12 +103,15 @@ class Vm # modifiers are properly used with the correct VM image. @modifiers = config['modifiers'] - if @modifiers - begin - @modifiers.each { |modifier| self.class.send(:include, eval("Lab::Modifier::#{modifier}"))} - rescue Exception => e - # modifier likely didn't exist - end + if @modifiers + @modifiers.each do |modifier| + begin + self.class.send(:include, eval("Lab::Modifier::#{modifier}")) + rescue Exception => e + #puts "WARNING: Unable to load: #{modifier}" + #puts "Exception: #{e}" + end + end end # Consume all tags @@ -206,11 +209,9 @@ class Vm end def to_yaml - - # TODO - push this down to the drivers. - # Standard configuration options out = " - vmid: #{@vmid}\n" + out = " hostname: #{@hostname}\n" out += " driver: #{@driver_type}\n" out += " location: #{@location}\n" out += " type: #{@type}\n" diff --git a/lib/lab/vm_controller.rb b/lib/lab/vm_controller.rb index 4cfc4a5891..abc82b4293 100644 --- a/lib/lab/vm_controller.rb +++ b/lib/lab/vm_controller.rb @@ -158,12 +158,12 @@ module Controllers case driver_type.intern when :workstation vm_list = ::Lab::Controllers::WorkstationController::running_list - + vm_list.each do |item| - + ## Name the VM index = @vms.count + 1 - + ## Add it to the vm list @vms << Vm.new( { 'vmid' => "vm_#{index}", 'driver' => driver_type, @@ -171,8 +171,6 @@ module Controllers 'user' => user, 'host' => host } ) end - - when :virtualbox vm_list = ::Lab::Controllers::VirtualBoxController::running_list vm_list.each do |item| @@ -189,10 +187,10 @@ module Controllers vm_list = ::Lab::Controllers::RemoteWorkstationController::running_list(user, host) vm_list.each do |item| - + ## Name the VM index = @vms.count + 1 - + ## Add it to the vm list @vms << Vm.new( { 'vmid' => "vm_#{index}", 'driver' => driver_type, @@ -202,7 +200,6 @@ module Controllers 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]}", @@ -210,12 +207,11 @@ module Controllers 'user' => user, 'host' => host } ) end - else raise TypeError, "Unsupported VM Type" end - end + end def build_from_config(driver_type=nil, user=nil, host=nil, clear=false) if clear @@ -234,18 +230,17 @@ module Controllers 'user' => user, 'host' => host } ) end - else raise TypeError, "Unsupported VM Type" end - end + end def running?(vmid) if includes_vmid?(vmid) return self.find_by_hostname(vmid).running? end - return false + return false end end end diff --git a/plugins/lab.rb b/plugins/lab.rb index f3099d9fc2..18dab80373 100644 --- a/plugins/lab.rb +++ b/plugins/lab.rb @@ -384,8 +384,6 @@ class Plugin::Lab < Msf::Plugin local_path = args[args.count-2] vm_path = args[args.count-1] - print_line "Copying from #{local_path} to #{vm_path} on #{args[0]}" - if args[0] == "all" @controller.each do |vm| if vm.running? @@ -395,7 +393,7 @@ class Plugin::Lab < Msf::Plugin end else args[0..-2].each do |vmid_arg| - next unless @controller.includes_vmid? vmid_arg + next unless @controller.includes_hostname? vmid_arg if @controller[vmid_arg].running? print_line "Copying from #{local_path} to #{vm_path} on #{vmid_arg}" @controller[vmid_arg].copy_to_guest(local_path, vm_path)