lab 0.0.3 → 0.0.4

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.
@@ -0,0 +1,8 @@
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_esx_driver'
7
+ #require 'driver/qemu_driver'
8
+ #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,167 @@
1
+ $:.unshift(File.join(File.dirname(__FILE__), '..', '..'))
2
+
3
+ module Lab
4
+ module Modifier
5
+ module Meterpreter
6
+
7
+ end
8
+ end
9
+ end
10
+
11
+
12
+ # This allows us to override the default way of running commands
13
+ # Currently useful for the esx controller
14
+
15
+ module Lab
16
+ class Vm
17
+
18
+ attr_accessor :framework
19
+ attr_accessor :session
20
+ attr_accessor :session_input
21
+ attr_accessor :session_output
22
+
23
+ def create_framework
24
+ return if @framework
25
+ @framework = Msf::Simple::Framework.create
26
+ end
27
+
28
+ # perform the setup only once
29
+ def setup_session
30
+ return if @session
31
+
32
+ # require the framework (assumes this sits in lib/lab/modifiers)
33
+ require 'msf/base'
34
+
35
+ create_framework ## TODO - this should use a single framework
36
+ ## for all hosts, not one-per-host
37
+
38
+ @session = nil
39
+ @session_input = Rex::Ui::Text::Input::Buffer.new
40
+ @session_output = Rex::Ui::Text::Output::Buffer.new
41
+
42
+ if @os == "windows"
43
+ exploit_name = 'windows/smb/psexec'
44
+
45
+ # TODO - check for x86, choose the appropriate payload
46
+
47
+ payload_name = 'windows/meterpreter/bind_tcp'
48
+ options = { "RHOST" => @hostname,
49
+ "SMBUser" => @vm_user,
50
+ "SMBPass" => @vm_pass}
51
+
52
+ puts "DEBUG: using options #{options}"
53
+
54
+ # Initialize the exploit instance
55
+ exploit = @framework.exploits.create(exploit_name)
56
+
57
+ begin
58
+ # Fire it off.
59
+ @session = exploit.exploit_simple(
60
+ 'Payload' => payload_name,
61
+ 'Options' => options,
62
+ 'LocalInput' => @session_input,
63
+ 'LocalOutput' => @session_output)
64
+ @session.load_stdapi
65
+
66
+ puts "DEBUG: Generated session: #{@session}"
67
+
68
+ rescue Exception => e
69
+ puts "DEBUG: Unable to exploit"
70
+ puts e.to_s
71
+ end
72
+
73
+ else
74
+ module_name = 'scanner/ssh/ssh_login'
75
+
76
+ # TODO - check for x86, choose the appropriate payload
77
+
78
+ payload_name = 'linux/x86/shell_bind_tcp'
79
+ options = { "RHOSTS" => @hostname,
80
+ "USERNAME" => @vm_user,
81
+ "PASSWORD" => @vm_pass,
82
+ "BLANK_PASSWORDS" => false,
83
+ "USER_AS_PASS" => false,
84
+ "VERBOSE" => false}
85
+
86
+ puts "DEBUG: using options #{options}"
87
+
88
+ # Initialize the module instance
89
+ aux = @framework.auxiliary.create(module_name)
90
+
91
+ puts "DEBUG: created module: #{aux}"
92
+
93
+ begin
94
+ # Fire it off.
95
+ aux.run_simple(
96
+ 'Payload' => payload_name,
97
+ 'Options' => options,
98
+ 'LocalInput' => @session_input,
99
+ 'LocalOutput' => @session_output)
100
+
101
+ @session = @framework.sessions.first.last
102
+ puts "DEBUG: Generated session: #{@session}"
103
+ rescue Exception => e
104
+ puts "DEBUG: Unable to exploit"
105
+ puts e.to_s
106
+ end
107
+ end
108
+
109
+
110
+
111
+ end
112
+
113
+ def run_command(command, timeout=60)
114
+
115
+ setup_session
116
+ puts "Using session #{@session}"
117
+
118
+ # TODO: pass the timeout down
119
+
120
+ if @session
121
+ if @session.type == "shell"
122
+ puts "Running command via shell: #{command}"
123
+ @session.shell_command_token(command, timeout)
124
+ elsif @session.type == "meterpreter"
125
+ puts "Running command via meterpreter: #{command}"
126
+ @session.shell_command(command) #, timeout)
127
+ end
128
+ else
129
+ raise "No session"
130
+ end
131
+ end
132
+
133
+
134
+ # This isn't part of the normal API, but too good to pass up.
135
+ def run_script(script, options)
136
+ if @session.type == "meterpreter"
137
+ @session.execute_script(script, options)
138
+ else
139
+ raise "Unsupported on #{@session.type}"
140
+ end
141
+ end
142
+
143
+ # For meterpreter API compatibility
144
+ #def execute_file(script,options)
145
+ # run_script(script,options)
146
+ #end
147
+
148
+ def copy_to(local,remote)
149
+ setup_session
150
+ if @session.type == "meterpreter"
151
+ @session.run_cmd("upload #{local} #{remote}")
152
+ else
153
+ @driver.copy_to(local,remote)
154
+ end
155
+ end
156
+
157
+ def copy_from(local, remote)
158
+ setup_session
159
+ if @session.type == "meterpreter"
160
+ @session.run_cmd("download #{local} #{remote}")
161
+ else
162
+ @driver.copy_from(local,remote)
163
+ end
164
+ end
165
+
166
+ end
167
+ 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,4 @@
1
+ require 'modifier/test_modifier'
2
+ require 'modifier/backtrack5_modifier'
3
+ require 'modifier/meterpreter_modifier'
4
+ require 'modifier/dos_modifier'
@@ -0,0 +1,3 @@
1
+ module Lab
2
+ VERSION = "0.0.4"
3
+ end
@@ -0,0 +1,253 @@
1
+ ##
2
+ ## $Id$
3
+ ##
4
+
5
+ module Lab
6
+ class Vm
7
+
8
+ attr_accessor :vmid
9
+ attr_accessor :hostname
10
+ attr_accessor :name
11
+ attr_accessor :description
12
+ attr_accessor :location
13
+ attr_accessor :driver
14
+ attr_accessor :credentials
15
+ attr_accessor :tools
16
+ attr_accessor :type
17
+ attr_accessor :user
18
+ attr_accessor :host
19
+ attr_accessor :os
20
+ attr_accessor :arch
21
+
22
+ ## Initialize takes a vm configuration hash of the form
23
+ ## - vmid (unique identifier)
24
+ ## driver (vm technology)
25
+ ## user (if applicable - remote system)
26
+ ## host (if applicable - remote system)
27
+ ## pass (if applicable - remote system)
28
+ ## location (file / uri)
29
+ ## credentials (of the form [ {'user'=>"user",'pass'=>"pass", 'admin' => false}, ... ])
30
+ ## os (currently only linux / windows)
31
+ ## arch (currently only 32 / 64
32
+
33
+ def initialize(config = {})
34
+
35
+ # TODO - This is a mess. clean up, and pass stuff down to drivers
36
+ # and then rework the code that uses this api.
37
+ @vmid = config['vmid'].to_s
38
+ raise "Invalid VMID" unless @vmid
39
+
40
+ # Grab the hostname if specified, otherwise use the vmid
41
+ # VMID will be different in the case of ESX
42
+ @hostname = config['hostname']
43
+ if !@hostname
44
+ @hostname = @vmid
45
+ end
46
+
47
+ @driver_type = filter_input(config['driver'])
48
+ @driver_type.downcase!
49
+
50
+ @location = filter_input(config['location'])
51
+ #@name = config['name'] || ""
52
+ @description = config['description'] || ""
53
+ @tools = config['tools'] || ""
54
+ @os = config['os'] || ""
55
+ @arch = config['arch'] || ""
56
+ @type = filter_input(config['type']) || "unspecified"
57
+ @credentials = config['credentials'] || []
58
+
59
+ # TODO - Currently only implemented for the first set
60
+ if @credentials.count > 0
61
+ @vm_user = filter_input(@credentials[0]['user']) || "\'\'"
62
+ @vm_pass = filter_input(@credentials[0]['pass']) || "\'\'"
63
+ @vm_keyfile = filter_input(@credentials[0]['keyfile'])
64
+ end
65
+
66
+ # Only applicable to remote systems
67
+ @user = filter_input(config['user']) || nil
68
+ @host = filter_input(config['host']) || nil
69
+ @port = filter_input(config['port']) || nil
70
+ @pass = filter_input(config['pass']) || nil
71
+
72
+ #Only dynagen systems need this
73
+ @platform = config['platform']
74
+
75
+ #Only fog systems need this
76
+ @fog_config = config['fog_config']
77
+
78
+ #puts "Passing driver config: #{config}"
79
+
80
+ # Process the correct driver
81
+ if @driver_type == "workstation"
82
+ @driver = Lab::Drivers::WorkstationDriver.new(config)
83
+ elsif @driver_type == "virtualbox"
84
+ @driver = Lab::Drivers::VirtualBoxDriver.new(config)
85
+ elsif @driver_type == "fog"
86
+ @driver = Lab::Drivers::FogDriver.new(config, config['fog_config'])
87
+ elsif @driver_type == "dynagen"
88
+ @driver = Lab::Drivers::DynagenDriver.new(config, config['dynagen_config'])
89
+ elsif @driver_type == "remote_esx"
90
+ @driver = Lab::Drivers::RemoteEsxDriver.new(config)
91
+ elsif @driver_type == "remote_workstation"
92
+ @driver = Lab::Drivers::RemoteWorkstationDriver.new(config)
93
+ #elsif @driver_type == "qemu"
94
+ # @driver = Lab::Drivers::QemuDriver.new
95
+ #elsif @driver_type == "qemudo"
96
+ # @driver = Lab::Drivers::QemudoDriver.new
97
+ else
98
+ raise "Unknown Driver Type"
99
+ end
100
+
101
+ # Load in a list of modifiers. These provide additional methods
102
+ # Currently it is up to the user to verify that
103
+ # modifiers are properly used with the correct VM image.
104
+ #
105
+ # If not, the results are likely to be disasterous.
106
+ @modifiers = config['modifiers']
107
+
108
+ if @modifiers
109
+ begin
110
+ @modifiers.each { |modifier| self.class.send(:include, eval("Lab::Modifier::#{modifier}"))}
111
+ rescue Exception => e
112
+ # modifier likely didn't exist
113
+ end
114
+ end
115
+ end
116
+
117
+ def running?
118
+ @driver.running?
119
+ end
120
+
121
+ def location
122
+ @driver.location
123
+ end
124
+
125
+ def start
126
+ @driver.start
127
+ end
128
+
129
+ def stop
130
+ @driver.stop
131
+ end
132
+
133
+ def pause
134
+ @driver.pause
135
+ end
136
+
137
+ def suspend
138
+ @driver.suspend
139
+ end
140
+
141
+ def reset
142
+ @driver.reset
143
+ end
144
+
145
+ def resume
146
+ @driver.resume
147
+ end
148
+
149
+ def create_snapshot(snapshot)
150
+ @driver.create_snapshot(snapshot)
151
+ end
152
+
153
+ def revert_snapshot(snapshot)
154
+ @driver.revert_snapshot(snapshot)
155
+ end
156
+
157
+ def delete_snapshot(snapshot)
158
+ @driver.delete_snapshot(snapshot)
159
+ end
160
+
161
+ def revert_and_start(snapshot)
162
+ @driver.revert_snapshot(snapshot)
163
+ @driver.start
164
+ end
165
+
166
+ def copy_to(from,to)
167
+ @driver.copy_to(from,to)
168
+ end
169
+
170
+ def copy_from(from,to)
171
+ @driver.copy_from(from,to)
172
+ end
173
+
174
+ def run_command(command)
175
+ @driver.run_command(command)
176
+ end
177
+
178
+ def check_file_exists(file)
179
+ @driver.check_file_exists(file)
180
+ end
181
+
182
+ def create_directory(directory)
183
+ @driver.create_directory(directory)
184
+ end
185
+
186
+ def open_uri(uri)
187
+ # we don't filter the uri, as it's getting tossed into a script
188
+ # by the driver
189
+ if @os == "windows"
190
+ command = "\"C:\\program files\\internet explorer\\iexplore.exe\" #{uri}"
191
+ else
192
+ command = "firefox #{uri}"
193
+ end
194
+
195
+ @driver.run_command(command)
196
+ end
197
+
198
+ def to_s
199
+ return "#{@vmid}"
200
+ end
201
+
202
+ def to_yaml
203
+
204
+ # TODO - push this down to the drivers.
205
+
206
+ # Standard configuration options
207
+ out = " - vmid: #{@vmid}\n"
208
+ out += " driver: #{@driver_type}\n"
209
+ out += " location: #{@location}\n"
210
+ out += " type: #{@type}\n"
211
+ out += " tools: #{@tools}\n"
212
+ out += " os: #{@os}\n"
213
+ out += " arch: #{@arch}\n"
214
+
215
+ if @user or @host # Remote vm/drivers only
216
+ out += " user: #{@user}\n"
217
+ out += " host: #{@host}\n"
218
+ end
219
+
220
+ if @platform
221
+ out += " platform: #{@platform}\n"
222
+ end
223
+
224
+ if @fog_config
225
+ out += @fog_config.to_yaml
226
+ end
227
+
228
+ if @dynagen_config
229
+ out += @dynagen_config.to_yaml
230
+ end
231
+
232
+ out += " credentials:\n"
233
+ @credentials.each do |credential|
234
+ out += " - user: #{credential['user']}\n"
235
+ out += " pass: #{credential['pass']}\n"
236
+ end
237
+
238
+ return out
239
+ end
240
+ private
241
+
242
+ def filter_input(string)
243
+ return "" unless string # nil becomes empty string
244
+ return unless string.class == String # Allow other types
245
+
246
+ unless /^[(!)\d*\w*\s*\[\]\{\}\/\\\.\-\"\(\)]*$/.match string
247
+ raise "WARNING! Invalid character in: #{string}"
248
+ end
249
+
250
+ string
251
+ end
252
+ end
253
+ end