lab 0.1.5 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +4 -0
- data/config/test_lab.yml +11 -0
- data/config/test_targets.yml +21 -0
- data/lib/lab/controller/dynagen_controller.rb +6 -6
- data/lib/lab/controller/remote_esx_controller.rb +51 -51
- data/lib/lab/controller/remote_esxi_controller.rb +62 -0
- data/lib/lab/controller/remote_workstation_controller.rb +12 -12
- data/lib/lab/controller/virtualbox_controller.rb +16 -16
- data/lib/lab/controller/workstation_controller.rb +9 -9
- data/lib/lab/controller/workstation_vixr_controller.rb +9 -9
- data/lib/lab/controllers.rb +1 -3
- data/lib/lab/driver/dynagen_driver.rb +32 -32
- data/lib/lab/driver/fog_driver.rb +144 -144
- data/lib/lab/driver/remote_esxi_driver.rb +177 -0
- data/lib/lab/driver/remote_workstation_driver.rb +181 -181
- data/lib/lab/driver/virtualbox_driver.rb +132 -132
- data/lib/lab/driver/vm_driver.rb +177 -177
- data/lib/lab/driver/workstation_driver.rb +218 -218
- data/lib/lab/driver/workstation_vixr_driver.rb +108 -108
- data/lib/lab/drivers.rb +1 -1
- data/lib/lab/modifier/backtrack5_modifier.rb +8 -8
- data/lib/lab/modifier/dos_modifier.rb +3 -3
- data/lib/lab/modifier/test_modifier.rb +6 -6
- data/lib/lab/version.rb +1 -1
- data/lib/lab/vm.rb +242 -242
- data/lib/lab/vm_controller.rb +217 -211
- data/src/Gemfile +4 -0
- data/src/README.md +80 -0
- data/src/Rakefile +1 -0
- data/src/TODO +15 -0
- data/src/config/test_lab.yml +11 -0
- data/src/config/test_targets.yml +21 -0
- data/src/lab.gemspec +35 -0
- data/src/lib/lab.rb +2 -0
- data/src/lib/lab/controller/dynagen_controller.rb +14 -0
- data/src/lib/lab/controller/fog_controller.rb +6 -0
- data/src/lib/lab/controller/remote_esxi_controller.rb +62 -0
- data/src/lib/lab/controller/remote_workstation_controller.rb +22 -0
- data/src/lib/lab/controller/virtualbox_controller.rb +25 -0
- data/src/lib/lab/controller/vsphere_controller.rb +18 -0
- data/src/lib/lab/controller/workstation_controller.rb +17 -0
- data/src/lib/lab/controller/workstation_vixr_controller.rb +19 -0
- data/src/lib/lab/controllers.rb +9 -0
- data/src/lib/lab/driver/dynagen_driver.rb +47 -0
- data/src/lib/lab/driver/fog_driver.rb +104 -0
- data/src/lib/lab/driver/remote_esxi_driver.rb +177 -0
- data/src/lib/lab/driver/remote_workstation_driver.rb +197 -0
- data/src/lib/lab/driver/virtualbox_driver.rb +142 -0
- data/src/lib/lab/driver/vm_driver.rb +195 -0
- data/src/lib/lab/driver/vsphere_driver.rb +120 -0
- data/src/lib/lab/driver/workstation_driver.rb +234 -0
- data/src/lib/lab/driver/workstation_vixr_driver.rb +126 -0
- data/src/lib/lab/drivers.rb +9 -0
- data/src/lib/lab/modifier/backtrack5_modifier.rb +16 -0
- data/src/lib/lab/modifier/dos_modifier.rb +14 -0
- data/src/lib/lab/modifier/test_modifier.rb +16 -0
- data/src/lib/lab/modifiers.rb +3 -0
- data/src/lib/lab/version.rb +3 -0
- data/src/lib/lab/vm.rb +269 -0
- data/src/lib/lab/vm_controller.rb +275 -0
- data/src/test/.gitkeep +0 -0
- metadata +51 -12
- data/lib/lab/driver/remote_esx_driver.rb +0 -177
data/src/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/src/TODO
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
This is a list of basic priorities for the lab code...
|
2
|
+
|
3
|
+
* Implement more technologies
|
4
|
+
|
5
|
+
a) finish amazon ec2 (via fog)
|
6
|
+
b) qemu
|
7
|
+
c) qemudo
|
8
|
+
d) kvm
|
9
|
+
e) other cloud technologies (newservers, slicehost/rackspace,etc)
|
10
|
+
|
11
|
+
* Implement a cloning function on each controller
|
12
|
+
|
13
|
+
* 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.
|
14
|
+
|
15
|
+
* 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.
|
@@ -0,0 +1,21 @@
|
|
1
|
+
- vmid: metasploitable
|
2
|
+
driver: workstation
|
3
|
+
location: /opt/vm/lab/user/Metasploitable/Metasploitable.vmx
|
4
|
+
tools: false
|
5
|
+
credentials:
|
6
|
+
- user: msfadmin
|
7
|
+
pass: msfadmin
|
8
|
+
- vmid: windows2000_target
|
9
|
+
driver: workstation
|
10
|
+
location: /opt/vm/lab/vuln/msf_Win2000SP4/Windows 2000 AS.vmx
|
11
|
+
tools: true
|
12
|
+
credentials:
|
13
|
+
- vmid: windowsxp_target
|
14
|
+
driver: remote_workstation
|
15
|
+
host: vmhost
|
16
|
+
user: root
|
17
|
+
location: /opt/vm/lab/vuln/msf_WinXPSP1/Windows XP Professional.vmx
|
18
|
+
tools: true
|
19
|
+
credentials:
|
20
|
+
- user: administrator
|
21
|
+
pass: administrator
|
data/src/lab.gemspec
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib/', __FILE__)
|
3
|
+
$:.unshift lib unless $:.include?(lib)
|
4
|
+
require 'lab/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "lab"
|
8
|
+
s.version = Lab::VERSION
|
9
|
+
s.authors = ["Jonathan Cran"]
|
10
|
+
s.email = ["jcran@rapid7.com"]
|
11
|
+
s.homepage = "http://www.github.com/rapid7/lab/wiki"
|
12
|
+
s.summary = %q{Manage VMs like a boss}
|
13
|
+
s.description = %q{Start/Stop/Revert and do other cool stuff w/ Vmware, Virtualbox, and ESXi vms. This gem wraps common CLI utilities and other gems to create a common inteface for vms. }
|
14
|
+
|
15
|
+
s.rubyforge_project = "lab"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
|
22
|
+
# specify any dependencies here; for example:
|
23
|
+
# s.add_development_dependency "rspec"
|
24
|
+
|
25
|
+
# ??
|
26
|
+
s.add_runtime_dependency "nokogiri"
|
27
|
+
|
28
|
+
# Multiple things - fallback execute / copy
|
29
|
+
s.add_runtime_dependency "net-ssh"
|
30
|
+
s.add_runtime_dependency "net-scp"
|
31
|
+
|
32
|
+
# Vmware ESX driver
|
33
|
+
s.add_runtime_dependency "rbvmomi"
|
34
|
+
|
35
|
+
end
|
data/src/lib/lab.rb
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
# This controller was built against:
|
2
|
+
# VMware ESX Host Agent 4.1.0 build-348481
|
3
|
+
|
4
|
+
module Lab
|
5
|
+
module Controllers
|
6
|
+
module RemoteEsxiController
|
7
|
+
|
8
|
+
# Note that 3.5 was different (vmware-vim-cmd)
|
9
|
+
VIM_CMD = 'vim-cmd'.freeze
|
10
|
+
|
11
|
+
def self.dir_list(basepath=nil)
|
12
|
+
# Does this method really even make sense for esxi?
|
13
|
+
return "Unsupported :("
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.running_list(user, host)
|
17
|
+
user.gsub!(/(\W)*/, '')
|
18
|
+
host.gsub!(/(\W)*/, '')
|
19
|
+
|
20
|
+
# first get all registered vms
|
21
|
+
registered_vms = self.get_vms(user, host) || []
|
22
|
+
running_vms = []
|
23
|
+
|
24
|
+
# now let's see which ones are running
|
25
|
+
# TODO: this is ghetto, would be better not to connect repeatedly
|
26
|
+
registered_vms.each do |vm|
|
27
|
+
remote_cmd = "ssh #{user}@#{host} \"#{VIM_CMD} vmsvc/power.getstate #{vm[:id]}\""
|
28
|
+
raw = `#{remote_cmd}`
|
29
|
+
running_vms << vm if raw =~ /Powered on/
|
30
|
+
end
|
31
|
+
|
32
|
+
return running_vms
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def self.get_vms(user, host)
|
38
|
+
user.gsub!(/(\W)*/, '')
|
39
|
+
host.gsub!(/(\W)*/, '')
|
40
|
+
|
41
|
+
vms = [] # array of VM hashes
|
42
|
+
remote_cmd = "ssh #{user}@#{host} \"#{VIM_CMD} vmsvc/getallvms | grep ^[0-9] | sed 's/[[:blank:]]\\{3,\\}/ /g'\""
|
43
|
+
raw = `#{remote_cmd}`.split("\n")
|
44
|
+
|
45
|
+
raw.each do |line|
|
46
|
+
# So effing ghetto
|
47
|
+
id_and_name = line.split('[datastore').first
|
48
|
+
id = id_and_name.split(' ').first
|
49
|
+
|
50
|
+
## TODO - there's surely a better way to do this.
|
51
|
+
name_array = id_and_name.split(' ')
|
52
|
+
name_array.shift
|
53
|
+
name = name_array.join(' ')
|
54
|
+
vms << {:id => id, :name => name}
|
55
|
+
end
|
56
|
+
|
57
|
+
return vms
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Lab
|
2
|
+
module Controllers
|
3
|
+
module RemoteWorkstationController
|
4
|
+
|
5
|
+
def self.running_list(user, host)
|
6
|
+
user.gsub!(/(\W)*/, '')
|
7
|
+
host.gsub!(/(\W)*/, '')
|
8
|
+
|
9
|
+
remote_cmd = "ssh #{user}@#{host} \"vmrun list nogui\""
|
10
|
+
vm_list = `#{remote_cmd}`.split("\n")
|
11
|
+
vm_list.shift
|
12
|
+
|
13
|
+
return vm_list
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.dir_list(basepath=nil)
|
17
|
+
vm_list = Find.find(basepath).select { |f| f =~ /\.vmx$/ }
|
18
|
+
return vm_list
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Lab
|
2
|
+
module Controllers
|
3
|
+
module VirtualBoxController
|
4
|
+
|
5
|
+
def self.running_list
|
6
|
+
vm_names_and_uuids = `VBoxManage list runningvms`
|
7
|
+
return vm_names_and_uuids.scan(/\"(.*)\" {.*}/).flatten
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.config_list
|
11
|
+
vm_names_and_uuids = `VBoxManage list vms`
|
12
|
+
return vm_names_and_uuids.scan(/\"(.*)\" {.*}/).flatten
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.config_list_uuid
|
16
|
+
vm_names_and_uuids = `VBoxManage list vms`
|
17
|
+
return vm_names_and_uuids.scan(/\".*\" {(.*)}/).flatten
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.dir_list(basepath=nil)
|
21
|
+
vm_list = Find.find(basepath).select { |f| f =~ /\.xml$/ }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# This controller was built against:
|
2
|
+
# VMware ESX Host Agent 4.1.0 build-348481
|
3
|
+
|
4
|
+
module Lab
|
5
|
+
module Controllers
|
6
|
+
module VsphereController
|
7
|
+
|
8
|
+
def self.dir_list(basepath=nil)
|
9
|
+
return "Unimplemented"
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.running_list(user, host)
|
13
|
+
return "Unimplemented"
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Lab
|
2
|
+
module Controllers
|
3
|
+
module WorkstationController
|
4
|
+
|
5
|
+
def self.running_list
|
6
|
+
vm_list = `vmrun list`.split("\n")
|
7
|
+
vm_list.shift
|
8
|
+
return vm_list
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.dir_list(basepath=nil)
|
12
|
+
vm_list = Find.find(basepath).select { |f| f =~ /\.vmx$/ }
|
13
|
+
return vm_list
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Lab
|
2
|
+
module Controllers
|
3
|
+
module WorkstationVixrController
|
4
|
+
|
5
|
+
def self.running_list
|
6
|
+
vm_list = `vmrun list`.split("\n")
|
7
|
+
vm_list.shift
|
8
|
+
|
9
|
+
return vm_list
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.dir_list(basepath=nil)
|
13
|
+
vm_list = Find.find(basepath).select { |f| f =~ /\.vmx$/ }
|
14
|
+
|
15
|
+
return vm_list
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
require 'controller/workstation_controller'
|
2
|
+
require 'controller/virtualbox_controller'
|
3
|
+
require 'controller/fog_controller'
|
4
|
+
require 'controller/dynagen_controller'
|
5
|
+
require 'controller/remote_workstation_controller'
|
6
|
+
require 'controller/remote_esxi_controller'
|
7
|
+
require 'controller/vsphere_controller'
|
8
|
+
#require 'controller/qemu_controller'
|
9
|
+
#require 'controller/qemudo_controller'
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'vm_driver'
|
2
|
+
|
3
|
+
#
|
4
|
+
# $Id$
|
5
|
+
#
|
6
|
+
|
7
|
+
#
|
8
|
+
# To use this driver, you have to have a lab which is preconfigured. The best / easiest
|
9
|
+
# way i've found to to set up a lab is GNS3
|
10
|
+
#
|
11
|
+
|
12
|
+
module Lab
|
13
|
+
module Drivers
|
14
|
+
class DynagenDriver < VmDriver
|
15
|
+
def initialize(config,dynagen_config)
|
16
|
+
super(config)
|
17
|
+
@running = false
|
18
|
+
@dynagen_platform = filter_command(dynagen_config['dynagen_platform'])
|
19
|
+
end
|
20
|
+
|
21
|
+
def start
|
22
|
+
# TODO - write the location-file to a temp-file
|
23
|
+
# and set the autostart property
|
24
|
+
|
25
|
+
## start background dynamips process
|
26
|
+
system_command("dynamips -H #{@dynagen_platform} &")
|
27
|
+
system_command("dynagen #{@location}")
|
28
|
+
@running = true
|
29
|
+
end
|
30
|
+
|
31
|
+
def stop
|
32
|
+
system_command("killall dynagen")
|
33
|
+
@running = false
|
34
|
+
end
|
35
|
+
|
36
|
+
def cleanup
|
37
|
+
`killall dynagen`
|
38
|
+
`killall dynamips`
|
39
|
+
@running = false
|
40
|
+
end
|
41
|
+
|
42
|
+
def running?
|
43
|
+
return @running
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
require 'vm_driver'
|
2
|
+
|
3
|
+
##
|
4
|
+
## $Id$
|
5
|
+
##
|
6
|
+
|
7
|
+
module Lab
|
8
|
+
module Drivers
|
9
|
+
class FogDriver < VmDriver
|
10
|
+
|
11
|
+
def initialize(config,fog_config)
|
12
|
+
|
13
|
+
super(config)
|
14
|
+
@fog_config = fog_config
|
15
|
+
|
16
|
+
# Soft dependency
|
17
|
+
begin
|
18
|
+
require 'fog'
|
19
|
+
rescue LoadError
|
20
|
+
raise "WARNING: Library fog not found. Could not create driver"
|
21
|
+
end
|
22
|
+
|
23
|
+
if @fog_config['fog_type'] == "ec2"
|
24
|
+
|
25
|
+
# AWS / EC2 Base Credential Configuration
|
26
|
+
@aws_cert_file = IO.read(fog_config['fog_aws_cert_file']).chomp if fog_config['fog_aws_cert_file']
|
27
|
+
@aws_private_key_file = IO.read(fog_config['fog_aws_private_key_file']).chomp if fog_config['fog_aws_private_key_file']
|
28
|
+
@ec2_access_key_file = IO.read(fog_config['fog_ec2_access_key_file']).chomp if fog_config['fog_ec2_access_key_file']
|
29
|
+
@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']
|
30
|
+
|
31
|
+
# Instance Keys
|
32
|
+
@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']
|
33
|
+
@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']
|
34
|
+
|
35
|
+
# Instance Details
|
36
|
+
@ec2_base_ami = fog_config['fog_ec2_base_ami']
|
37
|
+
@ec2_flavor = fog_config['fog_ec2_flavor']
|
38
|
+
@ec2_user = fog_config['fog_ec2_user']
|
39
|
+
@ec2_region = fog_config['fog_ec2_region']
|
40
|
+
|
41
|
+
# Set up a connection
|
42
|
+
@compute = Fog::Compute.new(
|
43
|
+
:provider => "Aws",
|
44
|
+
:aws_access_key_id => @aws_access_key_file,
|
45
|
+
:aws_secret_access_key => @aws_secret_access_key_file )
|
46
|
+
else
|
47
|
+
raise "Unsupported fog type"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def start
|
52
|
+
ec2_settings = {
|
53
|
+
:image_id => @ec2_base_ami,
|
54
|
+
:flavor_id => @ec2_flavor,
|
55
|
+
:public_key_path => @ec2_instance_public_key_file,
|
56
|
+
:private_key_path => @ec2_instance_private_key_file,
|
57
|
+
:username => @ec2_user}
|
58
|
+
begin
|
59
|
+
@fog_server = @compute.servers.bootstrap(ec2_settings)
|
60
|
+
rescue Fog::Compute::AWS::Error => e
|
61
|
+
raise "Couldn't authenticate to AWS - did you place keys in the creds/ directory?"
|
62
|
+
exit
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def stop
|
67
|
+
@fog_server.destroy
|
68
|
+
end
|
69
|
+
|
70
|
+
def suspend
|
71
|
+
raise "unimplemented"
|
72
|
+
end
|
73
|
+
|
74
|
+
def pause
|
75
|
+
raise "unimplemented"
|
76
|
+
end
|
77
|
+
|
78
|
+
def reset
|
79
|
+
raise "unimplemented"
|
80
|
+
end
|
81
|
+
|
82
|
+
def create_snapshot(snapshot)
|
83
|
+
raise "unimplemented"
|
84
|
+
end
|
85
|
+
|
86
|
+
def revert_snapshot(snapshot)
|
87
|
+
raise "unimplemented"
|
88
|
+
end
|
89
|
+
|
90
|
+
def delete_snapshot(snapshot)
|
91
|
+
raise "unimplemented"
|
92
|
+
end
|
93
|
+
|
94
|
+
def cleanup
|
95
|
+
@fog_server.destroy
|
96
|
+
end
|
97
|
+
|
98
|
+
def running?
|
99
|
+
return true #TODO
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|