From 7cfde8317a1a508d1eee292498312c01a6337a6e Mon Sep 17 00:00:00 2001 From: thomashaw Date: Thu, 5 Oct 2017 14:24:56 +0100 Subject: [PATCH] Rework WIP: Testing changes so far. Still need to rework network-ranges passthrough hack with something more flexible. --- Gemfile.lock | 8 ++--- lib/objects/system.rb | 8 ++++- lib/readers/system_reader.rb | 15 ++++++-- lib/templates/Vagrantfile.erb | 27 +++++++++----- .../debian_puppet_32/secgen_metadata.xml | 3 +- .../random/random_word/secgen_local/local.rb | 3 +- scenarios/labs/1_integrity_protection.xml | 6 ++-- scenarios/labs/2_integrity_detection.xml | 6 ++-- secgen.rb | 35 ++++++++++++++----- 9 files changed, 80 insertions(+), 31 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 5b6393103..f5dedb021 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -9,9 +9,9 @@ GEM specs: CFPropertyList (2.2.8) chunky_png (1.3.8) + cinch (2.3.3) credy (0.2.1) thor (~> 0.19.1) - cinch (2.3.3) facter (2.4.6) CFPropertyList (~> 2.2.6) faker (1.6.6) @@ -42,8 +42,8 @@ GEM nokogiri (1.6.8) mini_portile2 (~> 2.1.0) pkg-config (~> 1.1.7) - pg (0.21.0) nori (2.6.0) + pg (0.21.0) pkg-config (1.1.7) puppet (4.5.1) CFPropertyList (~> 2.2.6) @@ -77,16 +77,16 @@ PLATFORMS ruby DEPENDENCIES - credy cinch + credy faker forgery librarian-puppet mini_exiftool_vendored minitest nokogiri - pg nori + pg programr! puppet rake diff --git a/lib/objects/system.rb b/lib/objects/system.rb index 2686e23ed..85ce9a969 100644 --- a/lib/objects/system.rb +++ b/lib/objects/system.rb @@ -9,18 +9,20 @@ class System attr_accessor :module_selections # (after resolution) attr_accessor :num_actioned_module_conflicts attr_accessor :system_networks + attr_accessor :network_ranges # populated when provided via command line options # Initalizes System object # @param [Object] name of the system # @param [Object] attributes such as base box selection # @param [Object] module_selectors these are modules that define filters for selecting the actual modules to use - def initialize(name, attributes, module_selectors) + def initialize(name, attributes, module_selectors, network_ranges) self.name = name self.attributes = attributes self.module_selectors = module_selectors self.module_selections = [] self.num_actioned_module_conflicts = 0 self.system_networks = [] + self.network_ranges = network_ranges end # selects from the available modules, based on the selection filters that have been specified @@ -105,6 +107,10 @@ class System Print.verbose "Filtering to remove non-unique #{$datastore[write_module_path_to_datastore]} ~= (n=#{search_list.size})" end + # check if we have a network range + if self.network_ranges != nil && ($datastore['network'] == nil or $datastore['network'].empty?) + $datastore['network_override'] = network_ranges + end if search_list.length == 0 raise 'failed' diff --git a/lib/readers/system_reader.rb b/lib/readers/system_reader.rb index dfc5c299d..07c169c28 100644 --- a/lib/readers/system_reader.rb +++ b/lib/readers/system_reader.rb @@ -10,7 +10,7 @@ class SystemReader # This includes module filters, which are module objects that contain filters for selecting # from the actual modules that are available # @return [Array] Array containing Systems objects - def self.read_scenario(scenario_file) + def self.read_scenario(scenario_file, network_ranges) systems = [] Print.verbose "Reading scenario file: #{scenario_file}" doc, xsd = nil @@ -38,6 +38,17 @@ class SystemReader # remove xml namespaces for ease of processing doc.remove_namespaces! + # hack for networks -- TODO: Remove me ASAP DO NOT MERGE TO MASTER + ranges = [] + network_ranges.each { |range| + doc.xpath('/scenario/system').size.times { |count| + range_array = range.split('.') + range_array[-1] = count+2 + ranges << range_array.join('.') + } + } + network_ranges = ranges + doc.xpath('/scenario/system').each_with_index do |system_node, system_index| module_selectors = [] system_attributes = {} @@ -146,7 +157,7 @@ class SystemReader end end - systems << System.new(system_name, system_attributes, module_selectors) + systems << System.new(system_name, system_attributes, module_selectors, network_ranges) end return systems diff --git a/lib/templates/Vagrantfile.erb b/lib/templates/Vagrantfile.erb index e53dd7a67..8e2d7e658 100644 --- a/lib/templates/Vagrantfile.erb +++ b/lib/templates/Vagrantfile.erb @@ -7,7 +7,8 @@ <% require 'json' require 'base64' require 'securerandom' -%> -<% prefix = @options[:prefix] ? @options[:prefix] + '_' : ''-%> +<% scenario_name = @scenario.split('/').last.split('.').first + prefix = @options[:prefix] ? (@options[:prefix] + '-' + scenario_name) : ('SecGen-' + scenario_name) -%> VAGRANTFILE_API_VERSION = "2" @@ -16,6 +17,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| <% system.module_selections.each do |selected_module| if selected_module.module_type == 'base' @base_type = selected_module.attributes['type'] + @ovirt_template = selected_module.attributes['ovirt_template'] @cpu_word_size = selected_module.attributes['cpu_word_size'].first.downcase if (@options.has_key? :ovirtuser) && (@options.has_key? :ovirtpass) @ovirt_base_template = selected_module.attributes['ovirt_template'].first @@ -50,7 +52,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| <%= if @options.has_key? :cpu_cores " ovirt.cpu_cores = #{@options[:cpu_cores]}\n" end -%> - ovirt.console = 'vnc' + ovirt.console = 'SPICE' ovirt.insecure = true ovirt.filtered_api = true ovirt.debug = true @@ -92,6 +94,11 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| end -%> end <% end %> + <% # Adds line that stops cloud-init from attempting to grab meta-data as eth0 is overwritten with provided networks. + # TODO: Remove when mutli-network vagrant-plugin issue is resolved + if (@options.has_key? :ovirtuser) && (@options.has_key? :ovirtpass) -%> + <%= system.name %>.vm.provision 'shell', inline: "echo 'datasource_list: [ None ] '> /etc/cloud/cloud.cfg.d/90_dpkg.cfg" + <% end -%> # Optimise package caching (re-use downloaded .deb, ruby gems, etc) # if Vagrant.has_plugin?("vagrant-cachier") @@ -110,7 +117,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| <% case selected_module.module_type when 'base' -%> <% if (@options.has_key? :ovirtuser) && (@options.has_key? :ovirtpass) %> # TODO - <%= system.name %>.vm.hostname = '<%= "#{prefix}SecGen-#{system.name}-#{Time.new.strftime("%Y%m%d-%H%M")}".tr('_', '-') %>' + <%= system.name %>.vm.hostname = '<%= "#{prefix}#{system.name}".tr('_', '-') %>' <%= system.name %>.vm.box = 'ovirt4' <%= system.name %>.vm.box_url = 'https://github.com/myoung34/vagrant-ovirt4/blob/master/example_box/dummy.box?raw=true' <% else %> @@ -125,18 +132,22 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| <% end %> <% when 'network' -%> <% if selected_module.attributes['range'].first.nil? || selected_module.attributes['range'].first == "dhcp" -%> -<<<<<<< HEAD <% if (@options.has_key? :ovirtnetwork) && (@options.has_key? :ovirtuser) && (@options.has_key? :ovirtpass) %> <%= system.name %>.vm.network :<%= selected_module.attributes['type'].first %>, type: "dhcp", :ovirt__network_name => '<%= "#{@options[:ovirtnetwork]}" %>' <% else %> - <%= system.name %>.vm.network :<%= selected_module.attributes['type'].first %>, type: "dhcp" + <%= system.name %>.vm.network :<%= selected_module.attributes['type'].first %>, type: "dhcp", auto_config: false <% end %> -======= - <%= system.name %>.vm.network :<%= selected_module.attributes['type'].first %>, type: "dhcp", auto_config: false ->>>>>>> IRI_labs <% else -%> <% if (@options.has_key? :ovirtuser) && (@options.has_key? :ovirtpass) %> + <% if @ovirt_template and @ovirt_template.include? 'kali_linux_msf' %> + <%= system.name %>.vm.provision 'shell', inline: "echo \"auto lo\niface lo inet loopback\n\nauto eth0\niface eth0 inet static\n\taddress <%= resolve_network(selected_module.attributes['range'].first)%>\" > /etc/network/interfaces" + <%= system.name %>.vm.provision 'shell', inline: "echo '' > /etc/environment" + <% elsif @ovirt_template and @ovirt_template.include? 'debian_desktop_kde' %> + <%= system.name %>.vm.provision 'shell', inline: "echo \"\nauto eth1\niface eth1 inet static\n\taddress <%= resolve_network(selected_module.attributes['range'].first)%>\" >> /etc/network/interfaces" + <%= system.name %>.vm.provision 'shell', inline: "echo '' > /etc/environment" + <% else %> <%= system.name %>.vm.network :<%= selected_module.attributes['type'].first %>, :ovirt__ip => "<%= resolve_network(selected_module.attributes['range'].first)%>", :ovirt__network_name => '<%= "#{@options[:ovirtnetwork]}" %>' + <% end %> <% else %> <%= system.name %>.vm.network :<%= selected_module.attributes['type'].first %>, ip: "<%= resolve_network(selected_module.attributes['range'].first)%>" <% end %> diff --git a/modules/bases/debian_puppet_32/secgen_metadata.xml b/modules/bases/debian_puppet_32/secgen_metadata.xml index 81577c7ef..171d99ba9 100644 --- a/modules/bases/debian_puppet_32/secgen_metadata.xml +++ b/modules/bases/debian_puppet_32/secgen_metadata.xml @@ -16,9 +16,8 @@ unix Debian 7.8 (wheezy) 32-bit (i386) https://app.vagrantup.com/secgen/boxes/debian_wheezy_puppet/versions/1.0.0/providers/virtualbox.box + debian_server https://atlas.hashicorp.com/puppetlabs various - - debian_server diff --git a/modules/generators/random/random_word/secgen_local/local.rb b/modules/generators/random/random_word/secgen_local/local.rb index f9510f298..b8ca70452 100644 --- a/modules/generators/random/random_word/secgen_local/local.rb +++ b/modules/generators/random/random_word/secgen_local/local.rb @@ -23,7 +23,8 @@ class WordGenerator < StringGenerator end def generate - self.outputs << File.readlines("#{WORDLISTS_DIR}/#{self.wordlist.sample.chomp}").sample.chomp + word = File.readlines("#{WORDLISTS_DIR}/#{self.wordlist.sample.chomp}").sample.chomp + self.outputs << word.gsub(/[^\w]/, '') end end diff --git a/scenarios/labs/1_integrity_protection.xml b/scenarios/labs/1_integrity_protection.xml index d3a0b8644..e9eb0fad9 100644 --- a/scenarios/labs/1_integrity_protection.xml +++ b/scenarios/labs/1_integrity_protection.xml @@ -129,13 +129,15 @@ Diner's Club 3000 0000 0000 04 true - http://172.16.0.3 + + network_override - 172.16.0.3 + + network_override accounts diff --git a/scenarios/labs/2_integrity_detection.xml b/scenarios/labs/2_integrity_detection.xml index d3a0b8644..8d9a9455d 100644 --- a/scenarios/labs/2_integrity_detection.xml +++ b/scenarios/labs/2_integrity_detection.xml @@ -129,13 +129,15 @@ Diner's Club 3000 0000 0000 04 true - http://172.16.0.3 + + network_override - 172.16.0.3 + + network_override accounts diff --git a/secgen.rb b/secgen.rb index 5ab9c5a62..905359b87 100644 --- a/secgen.rb +++ b/secgen.rb @@ -63,7 +63,7 @@ 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) + systems = SystemReader.read_scenario(scenario, options[:ip_ranges]) Print.std "#{systems.size} system(s) specified" Print.info 'Reading available base modules...' @@ -132,14 +132,31 @@ def build_vms(project_dir, options) if options.has_key? :reload command = '--provision reload' end - if GemExec.exe('vagrant', project_dir, "#{command} #{system}") - Print.info 'VMs created.' - if options[:shutdown] - GemExec.exe('vagrant', project_dir, 'halt') + + retry_count = (options[:ovirtuser] and options[:ovirtpass]) ? 5 : 0 + successful_creation = false + + while retry_count and !successful_creation + if GemExec.exe('vagrant', project_dir, "#{command} #{system}") + Print.info 'VMs created.' + successful_creation = true + if options[:shutdown] + Print.info 'Shutting down VMs.' + if options[:ovirtuser] and options[:ovirtpass] + sleep(30) + end + GemExec.exe('vagrant', project_dir, 'halt') + end + else + if retry_count > 0 + Print.err 'Error creating VMs, retrying...' + GemExec.exe('vagrant', project_dir, 'halt') + else + Print.err 'Error creating VMs, exiting SecGen.' + exit 1 + end end - else - Print.err 'Error creating VMs, Exiting SecGen.' - exit 1 + retry_count -= 1 end end @@ -149,7 +166,7 @@ end # # @author Jason Keighley # @return [Void] -def create_ewf_image(drive_path ,image_output_location) +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:'