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
  machine_tags - list of strings associated with the machine (not individual snapshots)
  snapshots - list of snapshots


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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/lab/vm.rb', line 42

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']
  @notes = config['notes']
  @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 list of snapshots & tags associated with this machine
  #
  #   machine_tags:
  #   - ie6
  #   - ie7
  #   - ie8
  #   - firefox
  #   snapshots:
  #   - ie6:
  #    - snapshot_tags:
  #     - ie6
  #   - ie7:
  #    - snapshot_tags:
  #     - ie7
  #     - ie8:
  #    - snapshot_tags:
  #     - ie8
  #   - bap:
  #    - snapshot_tags:
  #     - flash_10.2.153.1
  #     - reader_9.3.3
  #     - java_6u23
  #     - quicktime_player_7.6.9
  #
  @machine_tags = config['machine_tags']
  @snapshots = config['snapshots']

end

Instance Attribute Details

#archObject

Returns the value of attribute arch.



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

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

#machine_tagsObject

Returns the value of attribute machine_tags.



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

def machine_tags
  @machine_tags
end

#notesObject

Returns the value of attribute notes.



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

def notes
  @notes
end

#osObject

Returns the value of attribute os.



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

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

#snapshotsObject

Returns the value of attribute snapshots.



22
23
24
# File 'lib/lab/vm.rb', line 22

def snapshots
  @snapshots
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



220
221
222
# File 'lib/lab/vm.rb', line 220

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

#copy_from(local, remote) ⇒ Object



212
213
214
# File 'lib/lab/vm.rb', line 212

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



224
225
226
# File 'lib/lab/vm.rb', line 224

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



191
192
193
# File 'lib/lab/vm.rb', line 191

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

#delete_snapshot(snapshot) ⇒ Object



199
200
201
# File 'lib/lab/vm.rb', line 199

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

#open_uri(uri) ⇒ Object



228
229
230
231
232
233
234
235
236
237
238
# File 'lib/lab/vm.rb', line 228

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



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

def pause
  @driver.pause
end

#query_snapshotsObject



187
188
189
# File 'lib/lab/vm.rb', line 187

def query_snapshots
  @driver.query_snapshots
end

#resetObject



179
180
181
# File 'lib/lab/vm.rb', line 179

def reset
  @driver.reset
end

#resumeObject



183
184
185
# File 'lib/lab/vm.rb', line 183

def resume
  @driver.resume
end

#revert_and_start(snapshot) ⇒ Object



203
204
205
206
# File 'lib/lab/vm.rb', line 203

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

#revert_snapshot(snapshot) ⇒ Object



195
196
197
# File 'lib/lab/vm.rb', line 195

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

#run_command(command, timeout = 60) ⇒ Object



216
217
218
# File 'lib/lab/vm.rb', line 216

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)


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

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



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

def start
  @driver.start
end

#stopObject



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

def stop
  @driver.stop
end

#suspendObject



175
176
177
# File 'lib/lab/vm.rb', line 175

def suspend
  @driver.suspend
end

#to_sObject



240
241
242
# File 'lib/lab/vm.rb', line 240

def to_s
  return "#{@hostname}"
end

#to_yamlObject



244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
# File 'lib/lab/vm.rb', line 244

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