forked from cliffe/SecGen
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsecgen.rb
341 lines (290 loc) · 11.2 KB
/
secgen.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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
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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
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
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
require 'getoptlong'
require 'fileutils'
require_relative 'lib/helpers/constants.rb'
require_relative 'lib/helpers/print.rb'
require_relative 'lib/helpers/gem_exec.rb'
require_relative 'lib/readers/system_reader.rb'
require_relative 'lib/readers/module_reader.rb'
require_relative 'lib/output/project_files_creator.rb'
# Displays secgen usage data
def usage
Print.std "Usage:
#{$0} [--options] <command>
OPTIONS:
--scenario [xml file], -s [xml file]: Set the scenario to use
(defaults to #{SCENARIO_XML})
--project [output dir], -p [output dir]: Directory for the generated project
(output will default to #{default_project_dir})
--help, -h: Shows this usage information
--gui-output', '-g' gui output
--nopae: disable PAE support
--hwvirtex: enable HW virtex support
--vtxvpid: enable VTX support
--forensic-image-type [image type]: Forensic image format of generated image (raw, ewf)
COMMANDS:
run, r: Builds project and then builds the VMs
build-project, p: Builds project (vagrant and puppet config), but does not build VMs
build-vms [/project/dir], v [project #]: Builds VMs from a previously generated project
(use in combination with --project [dir])
create-forensic-image [/project/dir], v [project #]: Builds forensic images from a previously generated project
(can be used in combination with --project [dir])
list-scenarios: Lists all scenarios that can be used with the --scenario option
list-projects: Lists all projects that can be used with the --project option
delete-all-projects: Deletes all current projects in the projects directory
"
exit
end
# Builds the vagrant configuration file based on a scenario file
# @return build_number [Integer] Current project's build number
def build_config(scenario, out_dir, options)
Print.info 'Reading configuration file for virtual machines you want to create...'
# read the scenario file describing the systems, which contain vulnerabilities, services, etc
# this returns an array/hashes structure
systems = SystemReader.read_scenario(scenario)
Print.std "#{systems.size} system(s) specified"
Print.info 'Reading available base modules...'
all_available_bases = ModuleReader.read_bases
Print.std "#{all_available_bases.size} base modules loaded"
Print.info 'Reading available build modules...'
all_available_builds = ModuleReader.read_builds
Print.std "#{all_available_builds.size} build modules loaded"
Print.info 'Reading available vulnerability modules...'
all_available_vulnerabilties = ModuleReader.read_vulnerabilities
Print.std "#{all_available_vulnerabilties.size} vulnerability modules loaded"
Print.info 'Reading available service modules...'
all_available_services = ModuleReader.read_services
Print.std "#{all_available_services.size} service modules loaded"
Print.info 'Reading available utility modules...'
all_available_utilities = ModuleReader.read_utilities
Print.std "#{all_available_utilities.size} utility modules loaded"
Print.info 'Reading available generator modules...'
all_available_generators = ModuleReader.read_generators
Print.std "#{all_available_generators.size} generator modules loaded"
Print.info 'Reading available encoder modules...'
all_available_encoders = ModuleReader.read_encoders
Print.std "#{all_available_encoders.size} encoder modules loaded"
Print.info 'Reading available network modules...'
all_available_networks = ModuleReader.read_networks
Print.std "#{all_available_networks.size} network modules loaded"
Print.info 'Resolving systems: randomising scenario...'
# for each system, select modules
all_available_modules = all_available_bases + all_available_builds + all_available_vulnerabilties +
all_available_services + all_available_utilities + all_available_generators + all_available_encoders + all_available_networks
# update systems with module selections
systems.map! {|system|
system.module_selections = system.resolve_module_selection(all_available_modules)
system
}
Print.info "Creating project: #{out_dir}..."
# create's vagrant file / report a starts the vagrant installation'
creator = ProjectFilesCreator.new(systems, out_dir, scenario, options)
creator.write_files
Print.info 'Project files created.'
return systems
end
# Builds the vm via the vagrant file in the project dir
# @param project_dir
def build_vms(project_dir)
Print.info "Building project: #{project_dir}"
GemExec.exe('vagrant', project_dir, 'up')
Print.info 'VMs created.'
end
# Make forensic image helper methods
#################################################
# Create an EWF forensic image
#
# @author Jason Keighley
# @return [Void]
def create_ewf_image(drive_path ,image_output_location)
## Make E01 image
Print.info "Creating E01 image with path #{image_output_location}.E01"
Print.info 'This may take a while:'
Print.info "E01 image #{image_output_location}.E01 created" if system "ftkimager '#{drive_path}' '#{image_output_location}' --e01"
end
# Create an DD forensic image
#
# @author Jason Keighley
# @return [Void]
def create_dd_image(drive_path, image_output_location)
## Make DD image
Print.info "Creating dd image with path #{image_output_location}.raw"
Print.info 'This may take a while:'
Print.info "Raw image #{image_output_location}.raw created" if system "VBoxManage clonemedium disk '#{drive_path}' '#{image_output_location}.raw' --format RAW"
end
# Delete virtualbox virtual machine
#
# @author Jason Keighley
# @param [String] vm_name Virtual machine name in VirtualBox
# @return [Void]
def delete_virtualbox_vm(vm_name)
Print.info "Deleting VirtualBox VM #{vm_name}"
Print.info "VirtualBox VM #{vm_name} deleted" if system "VBoxManage unregistervm #{vm_name} --delete"
end
# Make forensic image helper methods \end
#################################################
def make_forensic_image(project_dir, image_output_location, image_type)
drive_path = %x(VBoxManage list hdds | grep '#{project_dir.split('/').last}').sub(/\ALocation:\s*/, '').sub(/\n/, '')
drive_name = drive_path.split('/').last
image_output_location = "#{project_dir}/#{drive_name}".sub(/.vmdk|.vdi/, '') unless image_output_location
## Ensure all vms are shutdown
system "cd '#{project_dir}' && vagrant halt"
case image_type.downcase
when 'raw', 'dd'
create_dd_image(drive_path, image_output_location)
when 'ewf', 'e01'
create_ewf_image(drive_path, image_output_location)
else
Print.info "The image type [#{image_type}] is not recognised."
end
end
# Runs methods to run and configure a new vm from the configuration file
def run(scenario, project_dir, options)
build_config(scenario, project_dir, options)
build_vms(project_dir)
end
def default_project_dir
"#{PROJECTS_DIR}/SecGen#{Time.new.strftime("%Y%m%d_%H%M")}"
end
def list_scenarios
Print.std "Full paths to scenario files are displayed below"
Dir["#{ROOT_DIR}/scenarios/**/*"].select{ |file| !File.directory? file}.each_with_index do |scenario_name, scenario_number|
Print.std "#{scenario_number}) #{scenario_name}"
end
end
def list_projects
Print.std "Full paths to project directories are displayed below"
Dir["#{PROJECTS_DIR}/*"].select{ |file| !File.file? file}.each_with_index do |scenario_name, scenario_number|
Print.std "#{scenario_number}) #{scenario_name}"
end
end
# Delete all current project directories
#
# @author Jason Keighley
# @return [Void]
def delete_all_projects
FileUtils.rm_r(Dir.glob("#{PROJECTS_DIR}/*"))
end
# end of method declarations
# start of program execution
Print.std '~'*47
Print.std 'SecGen - Creates virtualised security scenarios'
Print.std ' Licensed GPLv3 2014-17'
Print.std '~'*47
# Get command line arguments
opts = GetoptLong.new(
[ '--help', '-h', GetoptLong::NO_ARGUMENT ],
[ '--project', '-p', GetoptLong::REQUIRED_ARGUMENT ],
[ '--scenario', '-s', GetoptLong::REQUIRED_ARGUMENT ],
[ '--gui-output', '-g', GetoptLong::NO_ARGUMENT],
[ '--nopae', GetoptLong::NO_ARGUMENT],
[ '--hwvirtex', GetoptLong::NO_ARGUMENT],
[ '--vtxvpid', GetoptLong::NO_ARGUMENT],
[ '--memory-per-vm', GetoptLong::REQUIRED_ARGUMENT],
[ '--total-memory', GetoptLong::REQUIRED_ARGUMENT],
[ '--max-cpu-cores', GetoptLong::REQUIRED_ARGUMENT],
[ '--max-cpu-usage', GetoptLong::REQUIRED_ARGUMENT],
[ '--forensic-image-type', GetoptLong::REQUIRED_ARGUMENT],
)
scenario = SCENARIO_XML
project_dir = nil
options = {}
# process option arguments
opts.each do |opt, arg|
case opt
# Main options
when '--help'
usage
when '--scenario'
scenario = arg;
when '--project'
project_dir = arg;
# Additional options
when '--gui-output'
Print.info "Gui output set (virtual machines will be spawned)"
options[:gui_output] = true
when '--nopae'
Print.info "no pae"
options[:nopae] = true
when '--hwvirtex'
Print.info "with HW virtualisation"
options[:hwvirtex] = true
when '--vtxvpid'
Print.info "with VT support"
options[:vtxvpid] = true
when '--memory-per-vm'
if options.has_key? :total_memory
Print.info 'Total memory option specified before memory per vm option, defaulting to total memory value'
else
Print.info "Memory per vm set to #{arg}"
options[:memory_per_vm] = arg
end
when '--total-memory'
if options.has_key? :memory_per_vm
Print.info 'Memory per vm option specified before total memory option, defaulting to memory per vm value'
else
Print.info "Total memory to be used set to #{arg}"
options[:total_memory] = arg
end
when '--max-cpu-cores'
Print.info "Number of cpus to be used set to #{arg}"
options[:max_cpu_cores] = arg
when '--max-cpu-usage'
Print.info "Max CPU usage set to #{arg}"
options[:max_cpu_usage] = arg
when '--forensic-image-type'
Print.info "Image output type set to #{arg}"
options[:forensic_image_type] = arg
else
Print.err "Argument not valid: #{arg}"
usage
exit
end
end
# at least one command
if ARGV.length < 1
Print.err 'Missing command'
usage
exit
end
# process command
case ARGV[0]
when 'run', 'r'
project_dir = default_project_dir unless project_dir
run(scenario, project_dir, options)
when 'build-project', 'p'
project_dir = default_project_dir unless project_dir
build_config(scenario, project_dir, options)
when 'build-vms', 'v'
if project_dir
build_vms(project_dir)
else
Print.err 'Please specify project directory to read'
usage
exit
end
when 'create-forensic-image'
image_type = options.has_key?(:forensic_image_type)?options[:forensic_image_type]:'raw';
if project_dir
build_vms(project_dir)
make_forensic_image(project_dir, nil, image_type)
else
project_dir = default_project_dir unless project_dir
build_config(scenario, project_dir, options)
build_vms(project_dir)
make_forensic_image(project_dir, nil, image_type)
end
when 'list-scenarios'
list_scenarios
exit 0
when 'list-projects'
list_projects
exit 0
when 'delete-all-projects'
delete_all_projects
Print.std 'All projects deleted'
exit 0
else
Print.err "Command not valid: #{ARGV[0]}"
usage
exit
end