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.
Files changed (63) hide show
  1. data/.gitignore +4 -0
  2. data/config/test_lab.yml +11 -0
  3. data/config/test_targets.yml +21 -0
  4. data/lib/lab/controller/dynagen_controller.rb +6 -6
  5. data/lib/lab/controller/remote_esx_controller.rb +51 -51
  6. data/lib/lab/controller/remote_esxi_controller.rb +62 -0
  7. data/lib/lab/controller/remote_workstation_controller.rb +12 -12
  8. data/lib/lab/controller/virtualbox_controller.rb +16 -16
  9. data/lib/lab/controller/workstation_controller.rb +9 -9
  10. data/lib/lab/controller/workstation_vixr_controller.rb +9 -9
  11. data/lib/lab/controllers.rb +1 -3
  12. data/lib/lab/driver/dynagen_driver.rb +32 -32
  13. data/lib/lab/driver/fog_driver.rb +144 -144
  14. data/lib/lab/driver/remote_esxi_driver.rb +177 -0
  15. data/lib/lab/driver/remote_workstation_driver.rb +181 -181
  16. data/lib/lab/driver/virtualbox_driver.rb +132 -132
  17. data/lib/lab/driver/vm_driver.rb +177 -177
  18. data/lib/lab/driver/workstation_driver.rb +218 -218
  19. data/lib/lab/driver/workstation_vixr_driver.rb +108 -108
  20. data/lib/lab/drivers.rb +1 -1
  21. data/lib/lab/modifier/backtrack5_modifier.rb +8 -8
  22. data/lib/lab/modifier/dos_modifier.rb +3 -3
  23. data/lib/lab/modifier/test_modifier.rb +6 -6
  24. data/lib/lab/version.rb +1 -1
  25. data/lib/lab/vm.rb +242 -242
  26. data/lib/lab/vm_controller.rb +217 -211
  27. data/src/Gemfile +4 -0
  28. data/src/README.md +80 -0
  29. data/src/Rakefile +1 -0
  30. data/src/TODO +15 -0
  31. data/src/config/test_lab.yml +11 -0
  32. data/src/config/test_targets.yml +21 -0
  33. data/src/lab.gemspec +35 -0
  34. data/src/lib/lab.rb +2 -0
  35. data/src/lib/lab/controller/dynagen_controller.rb +14 -0
  36. data/src/lib/lab/controller/fog_controller.rb +6 -0
  37. data/src/lib/lab/controller/remote_esxi_controller.rb +62 -0
  38. data/src/lib/lab/controller/remote_workstation_controller.rb +22 -0
  39. data/src/lib/lab/controller/virtualbox_controller.rb +25 -0
  40. data/src/lib/lab/controller/vsphere_controller.rb +18 -0
  41. data/src/lib/lab/controller/workstation_controller.rb +17 -0
  42. data/src/lib/lab/controller/workstation_vixr_controller.rb +19 -0
  43. data/src/lib/lab/controllers.rb +9 -0
  44. data/src/lib/lab/driver/dynagen_driver.rb +47 -0
  45. data/src/lib/lab/driver/fog_driver.rb +104 -0
  46. data/src/lib/lab/driver/remote_esxi_driver.rb +177 -0
  47. data/src/lib/lab/driver/remote_workstation_driver.rb +197 -0
  48. data/src/lib/lab/driver/virtualbox_driver.rb +142 -0
  49. data/src/lib/lab/driver/vm_driver.rb +195 -0
  50. data/src/lib/lab/driver/vsphere_driver.rb +120 -0
  51. data/src/lib/lab/driver/workstation_driver.rb +234 -0
  52. data/src/lib/lab/driver/workstation_vixr_driver.rb +126 -0
  53. data/src/lib/lab/drivers.rb +9 -0
  54. data/src/lib/lab/modifier/backtrack5_modifier.rb +16 -0
  55. data/src/lib/lab/modifier/dos_modifier.rb +14 -0
  56. data/src/lib/lab/modifier/test_modifier.rb +16 -0
  57. data/src/lib/lab/modifiers.rb +3 -0
  58. data/src/lib/lab/version.rb +3 -0
  59. data/src/lib/lab/vm.rb +269 -0
  60. data/src/lib/lab/vm_controller.rb +275 -0
  61. data/src/test/.gitkeep +0 -0
  62. metadata +51 -12
  63. 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,11 @@
1
+ - vmid: backtrack
2
+ driver: workstation
3
+ location: /opt/vm/backtrack5/Backtrack5x64.vmx
4
+ modifiers:
5
+ - Test
6
+ credentials:
7
+ - user: root
8
+ pass: toor
9
+ os: linux
10
+ flavor: ubuntu
11
+ arch: 64
@@ -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,2 @@
1
+ require 'lab/vm_controller'
2
+ require 'lab/version'
@@ -0,0 +1,14 @@
1
+ module Lab
2
+ module Controllers
3
+ module DynagenController
4
+
5
+ def self.running_list
6
+ raise "Unsupported"
7
+ end
8
+
9
+ def self.dir_list(basepath=nil)
10
+ raise "Unsupported"
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,6 @@
1
+ module Lab
2
+ module Controllers
3
+ module FogController
4
+ end
5
+ end
6
+ end
@@ -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