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
@@ -0,0 +1,126 @@
1
+ require 'vm_driver'
2
+ ##
3
+ ## $Id$
4
+ ##
5
+
6
+ # This requires rhythmx's vixr driver from https://github.com/rhythmx/vixr
7
+ # and below that, the VIX api from vmware http://www.vmware.com/support/developer/vix-api/
8
+
9
+ module Lab
10
+ module Drivers
11
+
12
+ class WorkstationVixrDriver < VmDriver
13
+
14
+ attr_accessor :type
15
+ attr_accessor :location
16
+
17
+ def initialize(vmid, location, os=nil, tools=false, credentials=nil)
18
+
19
+ # We have to treat this differently, as it's not in the same tree
20
+ begin
21
+ require 'vixr'
22
+ rescue LoadError
23
+ puts "WARNING: Library pro_vixr not found. To resolve this error, please\n" +
24
+ " install the vixr gem. Latest is available here:\n" +
25
+ "https://github.com/rhythmx/vixr ."
26
+ raise "Unable to create vixr driver"
27
+ end
28
+
29
+ @vmid = filter_command(vmid)
30
+ @location = filter_command(location)
31
+
32
+ if !File.exist?(@location)
33
+ raise ArgumentError,"Couldn't find: " + location
34
+ end
35
+
36
+ @credentials = credentials
37
+ @tools = tools # not used in command lines, no filter
38
+ @os = os # not used in command lines, no filter
39
+
40
+ # TODO - Currently only implemented for the first set
41
+ if @credentials.count > 0
42
+ @vm_user = filter_input(@credentials[0]['user']) || "\'\'"
43
+ @vm_pass = filter_input(@credentials[0]['pass']) || "\'\'"
44
+ end
45
+
46
+ host = VixR.connect()
47
+ vm = host.open_vmx(@location)
48
+
49
+ end
50
+
51
+ def start
52
+ vm.power_on
53
+ end
54
+
55
+ def stop
56
+ vm.power_off
57
+ end
58
+
59
+ def suspend
60
+ vm.suspend
61
+ end
62
+
63
+ def pause
64
+ vm.pause
65
+ end
66
+
67
+ def reset
68
+ vm.reset
69
+ end
70
+
71
+ def create_snapshot(snapshot)
72
+ snapshot = filter_input(snapshot)
73
+ system_command("ssh #{@user}@#{@host} vmrun -T ws snapshot \\\'#{@location}\\\' #{snapshot} nogui")
74
+ end
75
+
76
+ def revert_snapshot(snapshot)
77
+ snapshot = filter_input(snapshot)
78
+ system_command("ssh #{@user}@#{@host} vmrun -T ws revertToSnapshot \\\'#{@location}\\\' #{snapshot} nogui")
79
+ end
80
+
81
+ def delete_snapshot(snapshot)
82
+ snapshot = filter_input(snapshot)
83
+ system_command("ssh #{@user}@#{@host} vmrun -T ws deleteSnapshot \\\'#{@location}\\\' #{snapshot} nogui" )
84
+ end
85
+
86
+
87
+ def run_command(command)
88
+ command = filter_input(command)
89
+ if vm.login(@vm_user,@vm_pass)
90
+ vm.run_prog(command)
91
+ end
92
+ end
93
+
94
+ def copy_from(from, to)
95
+ from = filter_input(from)
96
+ to = filter_input(to)
97
+ cp_from_host(from,to)
98
+ end
99
+
100
+ def copy_to(from, to)
101
+ from = filter_input(from)
102
+ to = filter_input(to)
103
+ vm.cp_to_guest(from,to)
104
+ end
105
+
106
+ def check_file_exists(file)
107
+ file = filter_input(file)
108
+ file_exists?(file)
109
+ end
110
+
111
+ def create_directory(directory)
112
+ directory = filter_input(directory)
113
+ end
114
+
115
+ def cleanup
116
+
117
+ end
118
+
119
+ def running?
120
+ vm.running?
121
+ end
122
+
123
+ end
124
+
125
+ end
126
+ end
@@ -0,0 +1,9 @@
1
+ require 'driver/workstation_driver'
2
+ require 'driver/virtualbox_driver'
3
+ require 'driver/fog_driver'
4
+ require 'driver/dynagen_driver'
5
+ require 'driver/remote_workstation_driver'
6
+ require 'driver/remote_esxi_driver'
7
+ require 'driver/vsphere_driver'
8
+ #require 'driver/qemu_driver'
9
+ #require 'driver/qemudo_driver'
@@ -0,0 +1,16 @@
1
+ module Lab
2
+ module Modifier
3
+ module Backtrack5
4
+
5
+ def nmap(options)
6
+ run_command("nmap #{filter_input(options)}")
7
+ end
8
+
9
+ def testssl(site)
10
+ run_command("/pentest/scanners/testssl/testssl.sh #{filter_input(site)}")
11
+ end
12
+
13
+ end
14
+ end
15
+ end
16
+
@@ -0,0 +1,14 @@
1
+ # This assumes you're on a recent ubuntu
2
+ # TODO - enforce this, or split it out...
3
+
4
+ module Lab
5
+ module Modifier
6
+ module Dos
7
+
8
+ def ping(target)
9
+ run_command("ping #{filter_input(target)}")
10
+ end
11
+
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,16 @@
1
+ # This assumes you're on a recent ubuntu
2
+ # TODO - enforce this, or split it out...
3
+
4
+ module Lab
5
+ module Modifier
6
+ module Test
7
+ def install_nmap
8
+ run_command("sudo apt-get install nmap")
9
+ end
10
+
11
+ def nmap(options)
12
+ run_command("nmap #{filter_input(options)}")
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,3 @@
1
+ require 'modifier/test_modifier'
2
+ require 'modifier/backtrack5_modifier'
3
+ require 'modifier/dos_modifier'
@@ -0,0 +1,3 @@
1
+ module Lab
2
+ VERSION = "0.2.0"
3
+ end
data/src/lib/lab/vm.rb ADDED
@@ -0,0 +1,269 @@
1
+ #
2
+ module Lab
3
+
4
+ #
5
+ # This class encapsulates a vm, provides functionality on that vm, and contains a single driver.
6
+ #
7
+ class Vm
8
+
9
+ attr_accessor :vmid
10
+ attr_accessor :hostname
11
+ attr_accessor :description
12
+ attr_accessor :user
13
+ attr_accessor :host
14
+ attr_accessor :location
15
+ attr_accessor :driver
16
+ attr_accessor :credentials
17
+ attr_accessor :tools
18
+ attr_accessor :type
19
+ attr_accessor :os
20
+ attr_accessor :arch
21
+ attr_accessor :tags
22
+
23
+ ## Initialize takes a vm configuration hash of the form
24
+ ## - vmid (unique id)
25
+ ## hostname (unique name)
26
+ ## description (describes the vm's contents)
27
+ ## driver (vm driver)
28
+ ## location (if applicable - local system)
29
+ ## user (if applicable - remote system)
30
+ ## host (if applicable - remote system)
31
+ ## pass (if applicable - remote system) # DISCOURAGED - USE KEYS!
32
+ ## tools (true if tools are installed)
33
+ ## type ( qa / vulnerable / etc - freeform option)
34
+ ## credentials (of the form [ {'user'=>"user",'pass'=>"pass", 'admin' => false}, ... ])
35
+ ## os (currently linux / windows / solaris / aix) - may be used in modifiers
36
+ ## arch (currently 32 / 64)
37
+ ## modifiers - array of strings, can be anything in the modifiers directory
38
+ ## tags - array of strings associated with this vm
39
+
40
+ def initialize(config = {})
41
+
42
+ # TODO - This is a mess. clean up, and pass stuff down to drivers
43
+ # and then rework the code that uses this api.
44
+ @vmid = config['vmid'].to_s
45
+ raise "Invalid VMID" unless @vmid
46
+
47
+ # Grab the hostname if specified, otherwise use the vmid
48
+ # VMID will be different in the case of ESX
49
+ @hostname = config['hostname']
50
+ if !@hostname
51
+ @hostname = @vmid
52
+ end
53
+
54
+ @driver_type = filter_input(config['driver'])
55
+ @driver_type.downcase!
56
+
57
+ @location = filter_input(config['location'])
58
+ @description = config['description']
59
+ @tools = config['tools']
60
+ @os = config['os']
61
+ @arch = config['arch']
62
+ @type = filter_input(config['type']) || "unspecified"
63
+ @credentials = config['credentials'] || []
64
+
65
+ # TODO - Currently only implemented for the first set
66
+ if @credentials.count > 0
67
+ @vm_user = filter_input(@credentials[0]['user']) || "\'\'"
68
+ @vm_pass = filter_input(@credentials[0]['pass']) || "\'\'"
69
+ @vm_keyfile = filter_input(@credentials[0]['keyfile'])
70
+ end
71
+
72
+ # Only applicable to remote systems
73
+ @user = filter_input(config['user']) || nil
74
+ @host = filter_input(config['host']) || nil
75
+ @port = filter_input(config['port']) || nil
76
+ @pass = filter_input(config['pass']) || nil # DISCORAGED, use keys!
77
+
78
+ # Only dynagen systems need this
79
+ @platform = config['platform']
80
+
81
+ # Only fog systems need this
82
+ @fog_config = config['fog_config']
83
+
84
+ # Process the correct driver
85
+ if @driver_type == "workstation"
86
+ @driver = Lab::Drivers::WorkstationDriver.new(config)
87
+ elsif @driver_type == "remote_workstation"
88
+ @driver = Lab::Drivers::RemoteWorkstationDriver.new(config)
89
+ elsif @driver_type == "virtualbox"
90
+ @driver = Lab::Drivers::VirtualBoxDriver.new(config)
91
+ elsif @driver_type == "fog"
92
+ @driver = Lab::Drivers::FogDriver.new(config, config['fog_config'])
93
+ elsif @driver_type == "dynagen"
94
+ @driver = Lab::Drivers::DynagenDriver.new(config, config['dynagen_config'])
95
+ elsif @driver_type == "remote_esxi"
96
+ @driver = Lab::Drivers::RemoteEsxiDriver.new(config)
97
+ elsif @driver_type == "vsphere"
98
+ @driver = Lab::Drivers::VsphereDriver.new(config)
99
+ #elsif @driver_type == "qemu"
100
+ # @driver = Lab::Drivers::QemuDriver.new
101
+ #elsif @driver_type == "qemudo"
102
+ # @driver = Lab::Drivers::QemudoDriver.new
103
+ else
104
+ raise "Unknown Driver Type"
105
+ end
106
+
107
+ # Load in a list of modifiers. These provide additional methods
108
+ # Currently it is up to the user to verify that
109
+ # modifiers are properly used with the correct VM image.
110
+ #
111
+ # If not, the results are likely to be disasterous.
112
+ @modifiers = config['modifiers']
113
+
114
+ if @modifiers
115
+ begin
116
+ @modifiers.each { |modifier| self.class.send(:include, eval("Lab::Modifier::#{modifier}"))}
117
+ rescue Exception => e
118
+ # modifier likely didn't exist
119
+ end
120
+ end
121
+
122
+ #
123
+ # Grab a tags array
124
+ #
125
+ @tags = config['tags']
126
+
127
+ end
128
+
129
+ def running?
130
+ @driver.running?
131
+ end
132
+
133
+ def location
134
+ @driver.location
135
+ end
136
+
137
+ def start
138
+ @driver.start
139
+ end
140
+
141
+ def stop
142
+ @driver.stop
143
+ end
144
+
145
+ def pause
146
+ @driver.pause
147
+ end
148
+
149
+ def suspend
150
+ @driver.suspend
151
+ end
152
+
153
+ def reset
154
+ @driver.reset
155
+ end
156
+
157
+ def resume
158
+ @driver.resume
159
+ end
160
+
161
+ def create_snapshot(snapshot)
162
+ @driver.create_snapshot(snapshot)
163
+ end
164
+
165
+ def revert_snapshot(snapshot)
166
+ @driver.revert_snapshot(snapshot)
167
+ end
168
+
169
+ def delete_snapshot(snapshot)
170
+ @driver.delete_snapshot(snapshot)
171
+ end
172
+
173
+ def revert_and_start(snapshot)
174
+ @driver.revert_snapshot(snapshot)
175
+ @driver.start
176
+ end
177
+
178
+ def copy_to(from,to)
179
+ @driver.copy_to(from,to)
180
+ end
181
+
182
+ def copy_from(from,to)
183
+ @driver.copy_from(from,to)
184
+ end
185
+
186
+ def run_command(command)
187
+ @driver.run_command(command)
188
+ end
189
+
190
+ def check_file_exists(file)
191
+ @driver.check_file_exists(file)
192
+ end
193
+
194
+ def create_directory(directory)
195
+ @driver.create_directory(directory)
196
+ end
197
+
198
+ def open_uri(uri)
199
+ # we don't filter the uri, as it's getting tossed into a script
200
+ # by the driver
201
+ if @os == "windows"
202
+ command = "\"C:\\program files\\internet explorer\\iexplore.exe\" #{uri}"
203
+ else
204
+ command = "firefox #{uri}"
205
+ end
206
+
207
+ @driver.run_command(command)
208
+ end
209
+
210
+ def to_s
211
+ return "#{@hostname}"
212
+ end
213
+
214
+ def to_yaml
215
+
216
+ # TODO - push this down to the drivers.
217
+
218
+ # Standard configuration options
219
+ out = " - vmid: #{@vmid}\n"
220
+ out += " hostname: #{@hostname}\n"
221
+ out += " driver: #{@driver_type}\n"
222
+ out += " description: |\n #{@description}\n"
223
+ out += " location: #{@location}\n"
224
+ out += " type: #{@type}\n"
225
+ out += " tools: #{@tools}\n"
226
+ out += " os: #{@os}\n"
227
+ out += " arch: #{@arch}\n"
228
+
229
+ if @user or @host # Remote vm/drivers only
230
+ out += " user: #{@user}\n"
231
+ out += " host: #{@host}\n"
232
+ out += " port: #{@port}\n"
233
+ out += " pass: #{@pass}\n"
234
+ end
235
+
236
+ if @platform
237
+ out += " platform: #{@platform}\n"
238
+ end
239
+
240
+ if @fog_config
241
+ out += @fog_config.to_yaml
242
+ end
243
+
244
+ if @dynagen_config
245
+ out += @dynagen_config.to_yaml
246
+ end
247
+
248
+ out += " credentials:\n"
249
+ @credentials.each do |credential|
250
+ out += " - user: #{credential['user']}\n"
251
+ out += " pass: #{credential['pass']}\n"
252
+ end
253
+
254
+ return out
255
+ end
256
+ private
257
+
258
+ def filter_input(string)
259
+ return "" unless string # nil becomes empty string
260
+ return unless string.class == String # Allow other types
261
+
262
+ unless /^[(!)\d*\w*\s*\[\]\{\}\/\\\.\-\"\(\)]*$/.match string
263
+ raise "WARNING! Invalid character in: #{string}"
264
+ end
265
+
266
+ string
267
+ end
268
+ end
269
+ end