Class: Lab::Vm

Inherits:
Object
  • Object
show all
Defined in:
lib/lab/vm.rb,
lib/lab/modifier/meterpreter_modifier.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config = {}) ⇒ Vm

Initialize takes a vm configuration hash of the form

- vmid (unique id)
  hostname (unique name)
  description (describes the vm's contents)
  driver (vm driver)
  location (if applicable - local system)
  user (if applicable - remote system)
  host (if applicable - remote system)
  pass (if applicable - remote system) # DISCOURAGED - USE KEYS!
  tools (true if tools are installed)
  type ( qa / vulnerable / etc - freeform option)
  credentials (of the form [ {'user'=>"user",'pass'=>"pass", 'admin' => false}, ... ])
  os (currently linux / windows / solaris / aix) - may be used in modifiers
  arch (currently 32 / 64)
  modifiers - can be anything in the modifiers directory
  tags - list of strings associated with this vm


39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/lab/vm.rb', line 39

def initialize(config = {})  

  # TODO - This is a mess. clean up, and pass stuff down to drivers
  # and then rework the code that uses this api. 
  @vmid = config['vmid'].to_s 
  raise "Invalid VMID" unless @vmid

  # Grab the hostname if specified, otherwise use the vmid
  # VMID will be different in the case of ESX
  @hostname = config['hostname']
  if !@hostname
    @hostname = @vmid
  end

  @driver_type = filter_input(config['driver'])
  @driver_type.downcase!

  @location = filter_input(config['location'])
  @description = config['description']
  @tools = config['tools']
  @os = config['os']
  @arch = config['arch']
  @type = filter_input(config['type']) || "unspecified"
  @credentials = config['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']) || "\'\'"
    @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
  @port = filter_input(config['port']) || nil
  @pass = filter_input(config['pass']) || nil # DISCORAGED, use keys!

  # Only dynagen systems need this
  @platform = config['platform']

  # Only fog systems need this
  @fog_config = config['fog_config']

  # Process the correct driver
  if @driver_type == "workstation"
    @driver = Lab::Drivers::WorkstationDriver.new(config)
  elsif @driver_type == "remote_workstation"
    @driver = Lab::Drivers::RemoteWorkstationDriver.new(config)
  elsif @driver_type == "virtualbox"
    @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(config, config['dynagen_config'])  
  elsif @driver_type == "remote_esxi"
    @driver = Lab::Drivers::RemoteEsxiDriver.new(config)
  elsif @driver_type == "vsphere"
    @driver = Lab::Drivers::VsphereDriver.new(config)
  #elsif @driver_type == "qemu"
  #  @driver = Lab::Drivers::QemuDriver.new
  #elsif @driver_type == "qemudo"
  #  @driver = Lab::Drivers::QemudoDriver.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  
    begin
       @modifiers.each { |modifier|  self.class.send(:include, eval("Lab::Modifier::#{modifier}"))}
    rescue Exception => e
      # modifier likely didn't exist
    end
  end
  
  #
  # Grab a tags array
  #
  @tags = config['tags']
  
end

Instance Attribute Details

#archObject

Returns the value of attribute arch.



19
20
21
# File 'lib/lab/vm.rb', line 19

def arch
  @arch
end

#credentialsObject

Returns the value of attribute credentials.



15
16
17
# File 'lib/lab/vm.rb', line 15

def credentials
  @credentials
end

#descriptionObject

Returns the value of attribute description.



10
11
12
# File 'lib/lab/vm.rb', line 10

def description
  @description
end

#driverObject

Returns the value of attribute driver.



14
15
16
# File 'lib/lab/vm.rb', line 14

def driver
  @driver
end

#frameworkObject

Returns the value of attribute framework.



18
19
20
# File 'lib/lab/modifier/meterpreter_modifier.rb', line 18

def framework
  @framework
end

#hostObject

Returns the value of attribute host.



12
13
14
# File 'lib/lab/vm.rb', line 12

def host
  @host
end

#hostnameObject

Returns the value of attribute hostname.



9
10
11
# File 'lib/lab/vm.rb', line 9

def hostname
  @hostname
end

#locationObject

Returns the value of attribute location.



13
14
15
# File 'lib/lab/vm.rb', line 13

def location
  @location
end

#osObject

Returns the value of attribute os.



18
19
20
# File 'lib/lab/vm.rb', line 18

def os
  @os
end

#sessionObject

Returns the value of attribute session.



19
20
21
# File 'lib/lab/modifier/meterpreter_modifier.rb', line 19

def session
  @session
end

#session_inputObject

Returns the value of attribute session_input.



20
21
22
# File 'lib/lab/modifier/meterpreter_modifier.rb', line 20

def session_input
  @session_input
end

#session_outputObject

Returns the value of attribute session_output.



21
22
23
# File 'lib/lab/modifier/meterpreter_modifier.rb', line 21

def session_output
  @session_output
end

#tagsObject

Returns the value of attribute tags.



20
21
22
# File 'lib/lab/vm.rb', line 20

def tags
  @tags
end

#toolsObject

Returns the value of attribute tools.



16
17
18
# File 'lib/lab/vm.rb', line 16

def tools
  @tools
end

#typeObject

Returns the value of attribute type.



17
18
19
# File 'lib/lab/vm.rb', line 17

def type
  @type
end

#userObject

Returns the value of attribute user.



11
12
13
# File 'lib/lab/vm.rb', line 11

def user
  @user
end

#vmidObject

Returns the value of attribute vmid.



8
9
10
# File 'lib/lab/vm.rb', line 8

def vmid
  @vmid
end

Instance Method Details

#check_file_exists(file) ⇒ Object



189
190
191
# File 'lib/lab/vm.rb', line 189

def check_file_exists(file)
  @driver.check_file_exists(file)
end

#copy_from(local, remote) ⇒ Object



181
182
183
# File 'lib/lab/vm.rb', line 181

def copy_from(from,to)
  @driver.copy_from(from,to)
end

#copy_to(local, remote) ⇒ Object

For meterpreter API compatibility def execute_file(script,options) run_script(script,options) end



148
149
150
# File 'lib/lab/modifier/meterpreter_modifier.rb', line 148

def copy_to(from,to)
  @driver.copy_to(from,to)
end

#create_directory(directory) ⇒ Object



193
194
195
# File 'lib/lab/vm.rb', line 193

def create_directory(directory)
  @driver.create_directory(directory)
end

#create_frameworkObject



23
24
25
26
# File 'lib/lab/modifier/meterpreter_modifier.rb', line 23

def create_framework
	return if @framework
	@framework    = Msf::Simple::Framework.create
end

#create_snapshot(snapshot) ⇒ Object



160
161
162
# File 'lib/lab/vm.rb', line 160

def create_snapshot(snapshot)
  @driver.create_snapshot(snapshot)
end

#delete_snapshot(snapshot) ⇒ Object



168
169
170
# File 'lib/lab/vm.rb', line 168

def delete_snapshot(snapshot)
  @driver.delete_snapshot(snapshot)
end

#open_uri(uri) ⇒ Object



197
198
199
200
201
202
203
204
205
206
207
# File 'lib/lab/vm.rb', line 197

def open_uri(uri)
  # we don't filter the uri, as it's getting tossed into a script 
  # by the driver
  if @os == "windows"
    command = "\"C:\\program files\\internet explorer\\iexplore.exe\" #{uri}"
  else
    command = "firefox #{uri}"
  end

  @driver.run_command(command)
end

#pauseObject



144
145
146
# File 'lib/lab/vm.rb', line 144

def pause
  @driver.pause
end

#resetObject



152
153
154
# File 'lib/lab/vm.rb', line 152

def reset
  @driver.reset
end

#resumeObject



156
157
158
# File 'lib/lab/vm.rb', line 156

def resume
  @driver.resume
end

#revert_and_start(snapshot) ⇒ Object



172
173
174
175
# File 'lib/lab/vm.rb', line 172

def revert_and_start(snapshot)
  @driver.revert_snapshot(snapshot)
  @driver.start
end

#revert_snapshot(snapshot) ⇒ Object



164
165
166
# File 'lib/lab/vm.rb', line 164

def revert_snapshot(snapshot)
  @driver.revert_snapshot(snapshot)
end

#run_command(command, timeout = 60) ⇒ Object



185
186
187
# File 'lib/lab/vm.rb', line 185

def run_command(command)
  @driver.run_command(command)
end

#run_script(script, options) ⇒ Object

This isn’t part of the normal API, but too good to pass up.



135
136
137
138
139
140
141
# File 'lib/lab/modifier/meterpreter_modifier.rb', line 135

def run_script(script, options)
	if @session.type == "meterpreter"
		@session.execute_script(script, options)
	else
		raise "Unsupported on #{@session.type}"
	end
end

#running?Boolean

Returns:

  • (Boolean)


128
129
130
# File 'lib/lab/vm.rb', line 128

def running?
  @driver.running?
end

#setup_sessionObject

perform the setup only once



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/lab/modifier/meterpreter_modifier.rb', line 29

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}

     			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(
				'Payload'     => payload_name,
				'Options'     => options,
				'LocalInput'  => @session_input,
				'LocalOutput' => @session_output)
			
			@session = @framework.sessions.first.last
			puts "DEBUG: Generated session: #{@session}"
		rescue Exception => e 
		  puts "DEBUG: Unable to exploit"
		  puts e.to_s
		end
	end
	

	
end

#startObject



136
137
138
# File 'lib/lab/vm.rb', line 136

def start
  @driver.start
end

#stopObject



140
141
142
# File 'lib/lab/vm.rb', line 140

def stop
  @driver.stop
end

#suspendObject



148
149
150
# File 'lib/lab/vm.rb', line 148

def suspend
  @driver.suspend
end

#to_sObject



209
210
211
# File 'lib/lab/vm.rb', line 209

def to_s
  return "#{@hostname}"
end

#to_yamlObject



213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
# File 'lib/lab/vm.rb', line 213

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 += "   description: |\n #{@description}\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"
    out += "   port: #{@port}\n"
    out += "   pass: #{@pass}\n"
  end

  if @platform
    out += "   platform: #{@platform}\n"
  end

  if @fog_config
    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"
    out += "       pass: #{credential['pass']}\n"
  end

   return out
end