diff --git a/.gitignore b/.gitignore index 48fc02156..9a4aeb302 100644 --- a/.gitignore +++ b/.gitignore @@ -12,4 +12,6 @@ modules/generators/challenges/exif/secgen_local/tmp.jpg modules/generators/challenges/compression/zip/tmp modules/generators/challenges/image/random_jpg/secgen_local/tmp.jpg secgen.conf -modules/encoders/compression/huffman/tmp \ No newline at end of file +modules/encoders/compression/huffman/tmp +.rakeTasks +modules/**/Gemfile.lock diff --git a/Gemfile b/Gemfile index bc9ba0183..2fdcc1b75 100644 --- a/Gemfile +++ b/Gemfile @@ -33,6 +33,8 @@ gem 'ruby-graphviz' gem 'rsa' gem 'gpgmeh' gem 'digest-sha3', :git => "http://github.com/izetex/digest-sha3-ruby" +gem 'net-ntp' +gem 'CFPropertyList' #development only gems go here group :test, :development do diff --git a/Gemfile.lock b/Gemfile.lock index 214c26f37..8b46ab9cb 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -19,17 +19,18 @@ GIT GEM remote: https://rubygems.org/ specs: + CFPropertyList (2.3.6) PriorityQueue (0.1.2) - activesupport (5.2.1) + activesupport (5.2.2) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 0.7, < 2) minitest (~> 5.1) tzinfo (~> 1.1) bases (1.0.2) bcrypt (3.1.12) - chunky_png (1.3.10) + chunky_png (1.3.11) cinch (2.3.4) - concurrent-ruby (1.0.5) + concurrent-ruby (1.1.4) credy (0.2.1) thor (~> 0.19.1) digest-simple (1.1.0) @@ -38,6 +39,7 @@ GEM digest-whirlpool (1.0.3) duplicate (1.1.1) facter (2.5.1) + CFPropertyList (~> 2.2) faker (1.9.1) i18n (>= 0.7) faraday (0.13.1) @@ -45,7 +47,7 @@ GEM faraday_middleware (0.12.2) faraday (>= 0.7.4, < 1.0) fast_gettext (1.1.2) - ffi (1.9.25) + ffi (1.10.0) ffi-compiler (1.0.1) ffi (>= 1.0.0) rake @@ -60,14 +62,14 @@ GEM gpgmeh (0.1.6) activesupport (>= 2.3) nio4r (~> 2.2) - hiera (3.4.5) + hiera (3.5.0) hocon (1.2.5) httpclient (2.8.3) huffman (0.0.1) PriorityQueue activesupport ruby-graphviz - i18n (1.1.0) + i18n (1.5.3) concurrent-ruby (~> 1.0) json (2.1.0) librarian-puppet (3.0.0) @@ -80,20 +82,22 @@ GEM mini_exiftool (2.9.0) mini_exiftool_vendored (9.2.7.v1) mini_exiftool (>= 1.6.0) - mini_portile2 (2.3.0) - minitar (0.6.1) + mini_portile2 (2.4.0) + minitar (0.8) minitest (5.11.3) multi_json (1.13.1) multipart-post (2.0.0) + net-ntp (2.1.3) nio4r (2.3.1) - nokogiri (1.8.4) - mini_portile2 (~> 2.3.0) + nokogiri (1.10.1) + mini_portile2 (~> 2.4.0) nori (2.6.0) - ovirt-engine-sdk (4.2.4) + ovirt-engine-sdk (4.3.0) json (>= 1, < 3) - pg (1.1.3) + pg (1.1.4) process_helper (0.1.2) - puppet (6.0.0) + puppet (6.2.0) + CFPropertyList (~> 2.2) facter (> 2.0.1, < 4) fast_gettext (~> 1.1.2) hiera (>= 3.2.1, < 4) @@ -102,7 +106,7 @@ GEM multi_json (~> 1.10) puppet-resource_api (~> 1.5) semantic_puppet (~> 1.0) - puppet-resource_api (1.5.0) + puppet-resource_api (1.6.2) hocon (>= 1.0) puppet_forge (2.2.9) faraday (>= 0.9.0, < 0.14.0) @@ -110,15 +114,15 @@ GEM gettext-setup (~> 0.11) minitar semantic_puppet (~> 1.0) - rake (12.3.1) - rdoc (6.0.4) + rake (12.3.2) + rdoc (6.1.1) redcarpet (3.4.0) rmagick (2.16.0) rqrcode (0.10.1) chunky_png (~> 1.0) rsa (0.1.4) rsync (1.0.9) - ruby-graphviz (1.2.3) + ruby-graphviz (1.2.4) rubyzip (1.2.2) scrypt (3.0.6) ffi-compiler (>= 1.0, < 2.0) @@ -134,7 +138,7 @@ GEM thread_safe (~> 0.1) wordlist (0.1.1) spidr (~> 0.2) - yard (0.9.16) + yard (0.9.18) zip-zip (0.3) rubyzip (>= 1.0.0) zipruby (0.3.6) @@ -143,6 +147,7 @@ PLATFORMS ruby DEPENDENCIES + CFPropertyList bases bcrypt braille! @@ -159,6 +164,7 @@ DEPENDENCIES librarian-puppet mini_exiftool_vendored minitest + net-ntp nokogiri nori ovirt-engine-sdk @@ -182,4 +188,4 @@ DEPENDENCIES zipruby BUNDLED WITH - 1.16.1 + 2.0.0.pre.2 diff --git a/lib/batch/batch_secgen.rb b/lib/batch/batch_secgen.rb index 461173043..9766c7157 100644 --- a/lib/batch/batch_secgen.rb +++ b/lib/batch/batch_secgen.rb @@ -304,8 +304,8 @@ end # Database interactions def insert_row(db_conn, prepared_statements, statement_id, secgen_args) statement = "insert_row_#{statement_id}" - # Add --shutdown and strip trailing whitespace - secgen_args = '--shutdown ' + secgen_args.strip + # Add --shutdown and --no-tests and strip trailing whitespace + secgen_args = '--shutdown --no-tests ' + secgen_args.strip Print.info "Adding to queue: '#{statement}' '#{secgen_args}' 'todo'" unless prepared_statements.include? statement db_conn.prepare(statement, 'insert into queue (secgen_args, status) values ($1, $2) returning id') diff --git a/lib/objects/post_provision_test.rb b/lib/objects/post_provision_test.rb new file mode 100644 index 000000000..f02030dae --- /dev/null +++ b/lib/objects/post_provision_test.rb @@ -0,0 +1,170 @@ +# Post Provision Testing +# +# This file will be copied into each project folder at creation time. +# It will be required from each of the modules/secgen_tests/module_name.rb test scripts +# +# Test classes must: require_relative '../../../../../lib/post_provision_test' + +require 'json' +require 'base64' +require 'socket' +require 'timeout' +require 'net/http' +require 'open3' + +class PostProvisionTest + attr_accessor :project_path + attr_accessor :system_ip + attr_accessor :module_name + attr_accessor :module_path + attr_accessor :json_inputs + attr_accessor :port + attr_accessor :outputs + attr_accessor :all_tests_passed + + def initialize + self.system_ip = get_system_ip + self.json_inputs = get_json_inputs + self.port = get_port + self.outputs = [] + self.all_tests_passed = true + end + + def run + test_module + puts self.outputs + exit(1) unless all_tests_passed + end + + def test_module + # Call super first in overriden methods + self.outputs << "Running tests for #{self.module_name}" + end + + ##################### + # Testing Functions # + ##################### + + # Test service is up (tcp) + def test_service_up + if is_port_open? system_ip, self.port + self.outputs << "PASSED: Port #{self.port} is open at #{get_system_ip} (#{get_system_name})!" + else + self.outputs << "FAILED: Port #{self.port} is closed at #{get_system_ip} (#{get_system_name})!" + self.all_tests_passed = false + end + end + + # example usage for page: /index.html + def test_html_returned_content(page, match_string, hide_content = false) + + begin + source = Net::HTTP.get(get_system_ip, page, self.port) + rescue SocketError, Errno::ECONNREFUSED + # do nothing + end + + if source and source.include? match_string + match_string = '' if hide_content + self.outputs << "PASSED: Content #{match_string} is contained within #{page} at #{get_system_ip}:#{self.port} (#{get_system_name})!" + else + self.outputs << "FAILED: Content #{match_string} is not contained within #{page} at #{get_system_ip}:#{self.port} (#{get_system_name})!" + self.all_tests_passed = false + end + end + + def test_local_command(test_output, local_command, match_string) + Dir.chdir(get_project_path) do + output = run_vagrant_ssh(local_command) + if output[:stdout].include? match_string or output[:stderr].include? match_string + self.outputs << "PASSED: #{test_output} local command (#{local_command}) matches with output (#{match_string}) on #{get_system_name}!" + else + self.outputs << "FAILED: #{test_output} local command (#{local_command}) matches with output (#{match_string}) on #{get_system_name}!" + self.outputs << output[:stderr] + self.all_tests_passed = false + end + end + end + + ################## + # Misc Functions # + ################## + + def run_vagrant_ssh(args) + stdout, stderr, status = Open3.capture3("/usr/bin/vagrant ssh #{get_system_name} -c '#{args}'") + {:stdout => stdout, :stderr => stderr, :exit_status => status} + end + + def get_system_ip + vagrant_file_path = "#{get_project_path}/Vagrantfile" + vagrantfile = File.read(vagrant_file_path) + ip_line = vagrantfile.split("\n").delete_if {|line| !line.include? "# ip_address_for_#{get_system_name}"}[0] + ip_address = ip_line.split('=')[-1] + if ip_address == "DHCP" + self.outputs << "FAILED: Cannot test against dynamic IPs" # TODO: fix this so that we grab dynamic IP address (maybe from vagrant?) + exit(1) + else + ip_address + end + end + + def get_json_inputs + json_inputs_path = "#{File.expand_path('../', self.module_path)}/secgen_functions/files/json_inputs/*" + json_inputs_files = Dir.glob(json_inputs_path) + json_inputs_files.delete_if {|path| !path.include?(self.module_name)} + if json_inputs_files.size > 0 + return JSON.parse(Base64.strict_decode64(File.read(json_inputs_files.first))) + end + {} + end + + def get_port + if get_json_inputs != {} and get_json_inputs['port'] != nil + get_json_inputs['port'][0].to_i + else + -1 + end + end + + # Pass __FILE__ in from subclasses + def get_module_path(file_path) + "#{File.expand_path('..', File.dirname(file_path))}" + end + + # Note: returns proftpd_testing + def get_system_name + get_system_path.match(/.*?([^\/]*)$/i).captures[0] + end + + # Note: returns /home/thomashaw/git/SecGen/projects/SecGen20190202_010552/puppet/proftpd_testing + def get_system_path + "#{File.expand_path('../../', self.module_path)}" + end + + # Note: returns /home/thomashaw/git/SecGen/projects/SecGen20190202_010552/ + def get_project_path + "#{File.expand_path('../../../../', self.module_path)}" + end + + def is_port_open?(ip, port) + retries = 5 + while retries > 0 + begin + Timeout::timeout(2) do + begin + s = TCPSocket.new(ip, port) + s.close + return true + rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH + # do nothing + end + end + rescue Timeout::Error + # ignored + end + retries -= 1 + end + false + end + +end \ No newline at end of file diff --git a/lib/output/project_files_creator.rb b/lib/output/project_files_creator.rb index 6f2e0a4b7..475e06abb 100644 --- a/lib/output/project_files_creator.rb +++ b/lib/output/project_files_creator.rb @@ -172,6 +172,10 @@ class ProjectFilesCreator abort end + # Copy the test superclass into the project/lib directory + Print.std "Copying post-provision testing class" + FileUtils.mkdir("#{@out_dir}/lib") + FileUtils.cp("#{ROOT_DIR}/lib/objects/post_provision_test.rb", "#{@out_dir}/lib/post_provision_test.rb") Print.std "VM(s) can be built using 'vagrant up' in #{@out_dir}" diff --git a/lib/templates/Vagrantfile.erb b/lib/templates/Vagrantfile.erb index 1babe9dfd..05aea1512 100644 --- a/lib/templates/Vagrantfile.erb +++ b/lib/templates/Vagrantfile.erb @@ -136,6 +136,8 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| <% else %> <%= system.name %>.vm.network :<%= selected_module.attributes['type'].first %>, type: "dhcp", auto_config: false <% end %> + <% # Below string is used within testing, do not delete. -%> + # ip_address_for_<%= system.name %>=DHCP <% # Static networking -%> <% else -%> <% # Static oVirt networking -%> @@ -147,9 +149,13 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| # use some shell scripting to identify the name of the network interface (eth0/ens3/...), and set the IP address statically <%= system.name %>.vm.provision 'shell', inline: "echo -e \"auto lo\niface lo inet loopback\n\nauto <%= interface %>\niface <%= interface %> inet static\n\taddress <%= resolve_network(selected_module)%>\" > /etc/network/interfaces" <%= system.name %>.vm.provision 'shell', inline: "echo '' > /etc/environment" -<% # Static Virtualbox networking -%> + <% # Below string is used within testing, do not delete. -%> + # ip_address_for_<%= system.name %>=<%= resolve_network(selected_module)%> + <% # Static Virtualbox networking -%> <% else -%> <%= system.name %>.vm.network :<%= selected_module.attributes['type'].first %>, ip: "<%= resolve_network(selected_module)%>" + <% # Below string is used within testing, do not delete. -%> + # ip_address_for_<%= system.name %>=<%= resolve_network(selected_module)%> <% end -%> <% end -%> <% when 'vulnerability', 'service', 'utility', 'build' -%> @@ -161,14 +167,14 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| b64_json_inputs = Base64.strict_encode64(json_inputs) # save the inputs in a randomly named file in the # project out directory of the secgen_functions module - rand = SecureRandom.hex().to_s + json_inputs_filename = "#{selected_module.module_path_end}_#{SecureRandom.hex(15).to_s}" dir = "#{@out_dir}/puppet/#{system.name}/modules/secgen_functions/files/json_inputs" FileUtils.mkdir_p(dir) unless File.exists?(dir) - Print.verbose "Writing #{selected_module.module_path_name} input to: #{dir}/#{rand}" - File.write("#{dir}/#{rand}", b64_json_inputs) + Print.verbose "Writing #{selected_module.module_path_name} input to: #{dir}/#{json_inputs_filename}" + File.write("#{dir}/#{json_inputs_filename}", b64_json_inputs) -%> <%= module_name%>.facter = { - "base64_inputs_file" => '<%= rand %>', + "base64_inputs_file" => '<%= json_inputs_filename %>', } <% end -%> <%=module_name%>.module_path = "<%="puppet/#{system.name}/modules"%>" diff --git a/modules/bases/debian_puppet_32/secgen_metadata.xml b/modules/bases/debian_puppet_32/secgen_metadata.xml index 171d99ba9..b8bf6196e 100644 --- a/modules/bases/debian_puppet_32/secgen_metadata.xml +++ b/modules/bases/debian_puppet_32/secgen_metadata.xml @@ -20,4 +20,5 @@ https://atlas.hashicorp.com/puppetlabs various + diff --git a/modules/bases/ubuntu_xenial_64/secgen_metadata.xml b/modules/bases/ubuntu_xenial_64/secgen_metadata.xml deleted file mode 100644 index f013c4cfb..000000000 --- a/modules/bases/ubuntu_xenial_64/secgen_metadata.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - Ubuntu Xenial 16.04 LTS 64-bit Server by puppetlabs - Thomas Shaw - GPLv3 - TODO - 64-bit - server - cli - - linux - unix - Ubuntu Xenial 16.04 LTS - https://app.vagrantup.com/puppetlabs/boxes/ubuntu-16.04-64-puppet/versions/1.0.0/providers/virtualbox.box - debian_server - - https://atlas.hashicorp.com/puppetlabs - various - diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/secgen_test/mysql_stretch_compatible.rb b/modules/services/unix/database/mysql_stretch_compatible/mysql/secgen_test/mysql_stretch_compatible.rb new file mode 100644 index 000000000..8b821b377 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/secgen_test/mysql_stretch_compatible.rb @@ -0,0 +1,16 @@ +require_relative '../../../../../lib/post_provision_test' + +class MySQLStretchTest < PostProvisionTest + def initialize + self.module_name = 'mysql_stretch_compatible' + self.module_path = get_module_path(__FILE__) + super + end + + def test_module + super + test_local_command('mysqld process running?', 'ps -ef | grep mysqld', '/usr/sbin/mysqld') + end +end + +MySQLStretchTest.new.run \ No newline at end of file diff --git a/modules/services/unix/database/mysql_wheezy_compatible/mysql/secgen_test/mysql_wheezy_compatible.rb b/modules/services/unix/database/mysql_wheezy_compatible/mysql/secgen_test/mysql_wheezy_compatible.rb new file mode 100644 index 000000000..4e07fd320 --- /dev/null +++ b/modules/services/unix/database/mysql_wheezy_compatible/mysql/secgen_test/mysql_wheezy_compatible.rb @@ -0,0 +1,17 @@ +require_relative '../../../../../lib/post_provision_test' + +class MySQLWheezyTest < PostProvisionTest + def initialize + self.module_name = 'mysql_wheezy_compatible' + self.module_path = get_module_path(__FILE__) + super + self.port = 3306 + end + + def test_module + super + test_local_command('mysqld process running?', 'ps -ef | grep mysqld', '/usr/bin/mysqld') + end +end + +MySQLWheezyTest.new.run \ No newline at end of file diff --git a/modules/services/unix/email/popa3d/secgen_test/popa3d.rb b/modules/services/unix/email/popa3d/secgen_test/popa3d.rb new file mode 100644 index 000000000..b32aeec5a --- /dev/null +++ b/modules/services/unix/email/popa3d/secgen_test/popa3d.rb @@ -0,0 +1,17 @@ +require_relative '../../../../../lib/post_provision_test' + +class Popa3dTest < PostProvisionTest + def initialize + self.module_name = 'popa3d' + self.module_path = get_module_path(__FILE__) + super + self.port = 110 + end + + def test_module + super + test_service_up + end +end + +Popa3dTest.new.run \ No newline at end of file diff --git a/modules/services/unix/ftp/proftpd/secgen_test/proftpd.rb b/modules/services/unix/ftp/proftpd/secgen_test/proftpd.rb new file mode 100644 index 000000000..01ad6df76 --- /dev/null +++ b/modules/services/unix/ftp/proftpd/secgen_test/proftpd.rb @@ -0,0 +1,16 @@ +require_relative '../../../../../lib/post_provision_test' + +class ProftpdTest < PostProvisionTest + def initialize + self.module_name = 'proftpd' + self.module_path = get_module_path(__FILE__) + super + end + + def test_module + super + test_service_up + end +end + +ProftpdTest.new.run \ No newline at end of file diff --git a/modules/services/unix/ftp/vsftpd/secgen_test/vsftpd.rb b/modules/services/unix/ftp/vsftpd/secgen_test/vsftpd.rb new file mode 100644 index 000000000..13115198a --- /dev/null +++ b/modules/services/unix/ftp/vsftpd/secgen_test/vsftpd.rb @@ -0,0 +1,16 @@ +require_relative '../../../../../lib/post_provision_test' + +class VsftpdTest < PostProvisionTest + def initialize + self.module_name = 'vsftpd' + self.module_path = get_module_path(__FILE__) + super + end + + def test_module + super + test_service_up + end +end + +VsftpdTest.new.run \ No newline at end of file diff --git a/modules/services/unix/http/apache_bash_cgi/secgen_test/apache_bash_cgi.rb b/modules/services/unix/http/apache_bash_cgi/secgen_test/apache_bash_cgi.rb new file mode 100644 index 000000000..9343efa95 --- /dev/null +++ b/modules/services/unix/http/apache_bash_cgi/secgen_test/apache_bash_cgi.rb @@ -0,0 +1,17 @@ +require_relative '../../../../../lib/post_provision_test' + +class ApacheBashCGITest < PostProvisionTest + def initialize + self.module_name = 'apache_bash_cgi' + self.module_path = get_module_path(__FILE__) + super + self.port = 80 + end + + def test_module + super + test_service_up + end +end + +ApacheBashCGITest.new.run \ No newline at end of file diff --git a/modules/services/unix/http/apache_stretch_compatible/apache/manifests/init.pp b/modules/services/unix/http/apache_stretch_compatible/apache/manifests/init.pp index e6349988c..1a6e6665d 100755 --- a/modules/services/unix/http/apache_stretch_compatible/apache/manifests/init.pp +++ b/modules/services/unix/http/apache_stretch_compatible/apache/manifests/init.pp @@ -34,7 +34,7 @@ class apache ( Boolean $service_manage = true, $service_ensure = 'running', $service_restart = undef, - $purge_configs = true, + $purge_configs = false, $purge_vhost_dir = undef, $purge_vdir = false, $serveradmin = 'root@localhost', @@ -90,7 +90,7 @@ class apache ( $error_log = $::apache::params::error_log, $scriptalias = $::apache::params::scriptalias, $access_log_file = $::apache::params::access_log_file, - $overwrite_ports = false, # TODO: Implement this as in wheezy apache + $overwrite_ports = true, # TODO: Implement this as in wheezy apache ) inherits ::apache::params { $valid_mpms_re = $apache_version ? { @@ -256,17 +256,19 @@ class apache ( $vhost_load_dir = $vhost_dir } - concat { $ports_file: - ensure => present, - owner => 'root', - group => $::apache::params::root_group, - mode => $::apache::file_mode, - notify => Class['Apache::Service'], - require => Package['httpd'], - } - concat::fragment { 'Apache ports header': - target => $ports_file, - content => template('apache/ports_header.erb'), + if $overwrite_ports { + concat { $ports_file: + ensure => present, + owner => 'root', + group => $::apache::params::root_group, + mode => $::apache::file_mode, + notify => Class['Apache::Service'], + require => Package['httpd'], + } + concat::fragment { 'Apache ports header': + target => $ports_file, + content => template('apache/ports_header.erb'), + } } if $::apache::conf_dir and $::apache::params::conf_file { @@ -332,7 +334,7 @@ class apache ( ensure => file, content => template($conf_template), notify => Class['Apache::Service'], - require => [Package['httpd'], Concat[$ports_file]], + require => [Package['httpd']], } # preserve back-wards compatibility to the times when default_mods was diff --git a/modules/services/unix/http/apache_stretch_compatible/apache/manifests/listen.pp b/modules/services/unix/http/apache_stretch_compatible/apache/manifests/listen.pp index 503ee8860..9730d3c75 100644 --- a/modules/services/unix/http/apache_stretch_compatible/apache/manifests/listen.pp +++ b/modules/services/unix/http/apache_stretch_compatible/apache/manifests/listen.pp @@ -1,9 +1,25 @@ -define apache::listen { +define apache::listen ($port='') { $listen_addr_port = $name - # Template uses: $listen_addr_port - concat::fragment { "Listen ${listen_addr_port}": - target => $::apache::ports_file, - content => template('apache/listen.erb'), + if defined(Concat[$::apache::ports_file]){ + # Template uses: $listen_addr_port + concat::fragment { "Listen ${listen_addr_port}": + target => $::apache::ports_file, + content => template('apache/listen.erb'), + } + } elsif $port != '80' { + # Create a temporary file + # join with cat $tmp_file >> $file + # remove tmp files + $ports_file = $::apache::ports_file + $tmp_file = "$ports_file-tmp_listen" + file { $tmp_file: + ensure => file, + content => template('apache/listen.erb'), + } + + exec { "apache::listen: cat $tmp_file with ports.conf": + command => "/bin/cat $tmp_file >> $ports_file;/bin/rm $tmp_file" + } } } diff --git a/modules/services/unix/http/apache_stretch_compatible/apache/manifests/mpm.pp b/modules/services/unix/http/apache_stretch_compatible/apache/manifests/mpm.pp index 119fedf57..ca342f3f0 100644 --- a/modules/services/unix/http/apache_stretch_compatible/apache/manifests/mpm.pp +++ b/modules/services/unix/http/apache_stretch_compatible/apache/manifests/mpm.pp @@ -29,20 +29,20 @@ define apache::mpm ( } } } else { - if versioncmp($apache_version, '2.4') >= 0 { - file { "${mod_dir}/${mpm}.load": - ensure => file, - path => "${mod_dir}/${mpm}.load", - content => "LoadModule ${_id} ${_path}\n", - require => [ - Package['httpd'], - Exec["mkdir ${mod_dir}"], - ], - before => File[$mod_dir], - notify => Class['apache::service'], - } + if versioncmp($apache_version, '2.4') >= 0 { + file { "${mod_dir}/${mpm}.load": + ensure => file, + path => "${mod_dir}/${mpm}.load", + content => "LoadModule ${_id} ${_path}\n", + require => [ + Package['httpd'], + Exec["mkdir ${mod_dir}"], + ], + before => File[$mod_dir], + notify => Class['apache::service'], } } + } case $::osfamily { 'debian': { @@ -73,22 +73,27 @@ define apache::mpm ( } } - if $mpm == 'itk' and $::operatingsystem == 'Ubuntu' and $::operatingsystemrelease == '14.04' { - # workaround https://bugs.launchpad.net/ubuntu/+source/mpm-itk/+bug/1286882 - exec { - '/usr/sbin/a2dismod mpm_event': - onlyif => '/usr/bin/test -e /etc/apache2/mods-enabled/mpm_event.load', - require => Package['httpd'], - before => Package['apache2-mpm-itk'], - } - } - - if $mpm == 'itk' and $::operatingsystem == 'Ubuntu' and $::operatingsystemrelease == '16.04' { + if $mpm == 'itk' and ( ( $::operatingsystem == 'Ubuntu' and $::operatingsystemrelease == '16.04' ) or ( $::operatingsystem == 'Debian' and versioncmp($::operatingsystemrelease, '9.0.0') >= 0 ) ) { $packagename = 'libapache2-mpm-itk' } else { $packagename = "apache2-mpm-${mpm}" } + $mod_enabled_dir = $::apache::mod_enable_dir + + if $mpm == 'prefork' and ( $::operatingsystem == 'Debian' and versioncmp($::operatingsystemrelease, '9.0.0') >= 0 ) { + exec { '/usr/sbin/a2dismod mpm_event': + onlyif => "/usr/bin/test -e ${mod_enabled_dir}/mpm_event.load", + } + } + + if $mpm == 'itk' and ( ( $::operatingsystem == 'Ubuntu' and $::operatingsystemrelease == '14.04' ) or ($::operatingsystem == 'Debian' and versioncmp($::operatingsystemrelease, '9.0.0') >= 0 ) ) { + # workaround https://bugs.launchpad.net/ubuntu/+source/mpm-itk/+bug/1286882 + exec { '/usr/sbin/a2dismod mpm_event': + onlyif => "/usr/bin/test -e ${mod_enabled_dir}/mpm_event.load", + } + } + if versioncmp($apache_version, '2.4') < 0 or $mpm == 'itk' { package { $packagename: ensure => present, diff --git a/modules/services/unix/http/apache_stretch_compatible/apache/manifests/namevirtualhost.pp b/modules/services/unix/http/apache_stretch_compatible/apache/manifests/namevirtualhost.pp index 4fa879518..d89cb0c5b 100644 --- a/modules/services/unix/http/apache_stretch_compatible/apache/manifests/namevirtualhost.pp +++ b/modules/services/unix/http/apache_stretch_compatible/apache/manifests/namevirtualhost.pp @@ -1,9 +1,31 @@ -define apache::namevirtualhost { +define apache::namevirtualhost ($port=''){ $addr_port = $name - # Template uses: $addr_port - concat::fragment { "NameVirtualHost ${addr_port}": - target => $::apache::ports_file, - content => template('apache/namevirtualhost.erb'), + if defined(Concat[$::apache::ports_file]){ + # Template uses: $addr_port + concat::fragment { "NameVirtualHost ${addr_port}": + target => $::apache::ports_file, + content => template('apache/namevirtualhost.erb'), + } + } elsif $port != '80' { # if a second vhost is declared off port 80 + # Create a temporary file + # join with cat $tmp_file >> $file + # remove tmp files + $ports_file = $::apache::ports_file + $tmp_file = "$ports_file-tmp_nvh" + file { $tmp_file: + ensure => file, + content => template('apache/namevirtualhost.erb'), + } + + exec { "apache::listen: cat $tmp_file with ports.conf": + command => "/bin/cat $tmp_file >> $ports_file;/bin/rm $tmp_file", + require => File[$tmp_file] + } + + } else { # if a second vhost is declared on port 80 + tidy { 'remove apache default site': + path =>'/etc/apache2/sites-enabled/000-default', + } } } diff --git a/modules/services/unix/http/apache_stretch_compatible/apache/manifests/vhost.pp b/modules/services/unix/http/apache_stretch_compatible/apache/manifests/vhost.pp index 0d58fa8a9..90912e92b 100644 --- a/modules/services/unix/http/apache_stretch_compatible/apache/manifests/vhost.pp +++ b/modules/services/unix/http/apache_stretch_compatible/apache/manifests/vhost.pp @@ -396,12 +396,12 @@ define apache::vhost( fail("Apache::Vhost[${name}]: Mixing IP and non-IP Listen directives is not possible; check the add_listen parameter of the apache::vhost define to disable this") } if $listen_addr_port and $ensure == 'present' { - ensure_resource('apache::listen', $listen_addr_port) + ensure_resource('apache::listen', $listen_addr_port, {'port'=> $port}) } } if ! $ip_based { if $ensure == 'present' and (versioncmp($apache_version, '2.4') < 0) { - ensure_resource('apache::namevirtualhost', $nvh_addr_port) + ensure_resource('::apache::namevirtualhost', $nvh_addr_port, {'port' => $port}) } } diff --git a/modules/services/unix/http/parameterised_website/manifests/apache.pp b/modules/services/unix/http/parameterised_website/manifests/apache.pp index 3235c139d..e5df7f40d 100644 --- a/modules/services/unix/http/parameterised_website/manifests/apache.pp +++ b/modules/services/unix/http/parameterised_website/manifests/apache.pp @@ -5,10 +5,14 @@ class parameterised_website::apache { class { '::apache': default_vhost => false, overwrite_ports => false, + mpm_module => 'prefork', } - apache::vhost { 'vhost.test.com': + apache::vhost { 'parameterised.website': port => $port, docroot => '/var/www/parameterised_website', + notify => Tidy['pws remove default site'], } + + ensure_resource('tidy','pws remove default site', {'path'=>'/etc/apache2/sites-enabled/000-default.conf'}) } \ No newline at end of file diff --git a/modules/services/unix/http/parameterised_website/secgen_test/parameterised_website.rb b/modules/services/unix/http/parameterised_website/secgen_test/parameterised_website.rb new file mode 100644 index 000000000..032c30b34 --- /dev/null +++ b/modules/services/unix/http/parameterised_website/secgen_test/parameterised_website.rb @@ -0,0 +1,75 @@ +require_relative '../../../../../lib/post_provision_test' +require 'json' + +class ParamWebsiteTest < PostProvisionTest + attr_accessor :organisation + + def initialize + self.module_name = 'parameterised_website' + self.module_path = get_module_path(__FILE__) + super + end + + def test_module + super + json_inputs = get_json_inputs + test_service_up + test_html_returned_content("/css/#{json_inputs['theme'][0]}", 'Bootswatch v4.0.0') + test_org_functionality(json_inputs) + test_additional_page(json_inputs) + test_security_audit_remit(json_inputs) + test_acceptable_use_policy(json_inputs) + end + + def get_organisation(json_inputs) + JSON.parse(json_inputs['organisation'][0]) + end + + def test_org_functionality(json_inputs) + if json_inputs['organisation'] and + json_inputs['organisation'][0] and + json_inputs['organisation'][0] != '' + + organisation = get_organisation(json_inputs) + employee_1 = organisation['employees'][0] + + test_html_returned_content('/index.html', organisation['business_name']) + test_html_returned_content('/contact.html', organisation['business_motto']) + test_html_returned_content('/contact.html', employee_1['name']) + end + end + + def test_security_audit_remit(json_inputs) + if json_inputs['security_audit'] and + json_inputs['security_audit'][0] and + json_inputs['security_audit'][0] != '' + test_html_returned_content('/security_audit_remit.html', "Security Audit Remit of #{get_organisation(json_inputs)['business_name']}") + end + end + + def test_acceptable_use_policy(json_inputs) + if json_inputs['host_acceptable_use_policy'] and + json_inputs['host_acceptable_use_policy'][0] and + json_inputs['host_acceptable_use_policy'][0] == 'true' + test_html_returned_content('/acceptable_use_policy.html', "Acceptable Use Policy") + test_html_returned_content('/acceptable_use_policy.html', get_organisation(json_inputs)['business_name']) + end + end + + def test_additional_page(json_inputs) + if json_inputs['additional_page_filenames'] and + json_inputs['additional_page_filenames'][0] and + json_inputs['additional_page_filenames'][0].include? 'html' and + json_inputs['additional_pages'] and + json_inputs['additional_pages'][0] + + page_name = json_inputs['additional_page_filenames'][0] + page_name = "/#{page_name}" if page_name.split[0] != '/' + + test_html_returned_content(page_name, json_inputs['additional_pages'][0], true) + end + end + +end + +ParamWebsiteTest.new.run \ No newline at end of file diff --git a/modules/services/unix/irc/irc2/secgen_test/irc2.rb b/modules/services/unix/irc/irc2/secgen_test/irc2.rb new file mode 100644 index 000000000..7761fac90 --- /dev/null +++ b/modules/services/unix/irc/irc2/secgen_test/irc2.rb @@ -0,0 +1,17 @@ +require_relative '../../../../../lib/post_provision_test' + +class IRC2Test < PostProvisionTest + def initialize + self.module_name = 'irc2' + self.module_path = get_module_path(__FILE__) + super + self.port = 6667 + end + + def test_module + super + test_service_up + end +end + +IRC2Test.new.run \ No newline at end of file diff --git a/modules/services/unix/irc/unrealirc/secgen_metadata.xml b/modules/services/unix/irc/unrealirc/secgen_metadata.xml index 0e30d7480..77bf56ce5 100644 --- a/modules/services/unix/irc/unrealirc/secgen_metadata.xml +++ b/modules/services/unix/irc/unrealirc/secgen_metadata.xml @@ -32,10 +32,6 @@ Kali.* - - .*Stretch.* - - update diff --git a/modules/services/unix/irc/unrealirc/secgen_test/unrealirc.rb b/modules/services/unix/irc/unrealirc/secgen_test/unrealirc.rb new file mode 100644 index 000000000..511d0860d --- /dev/null +++ b/modules/services/unix/irc/unrealirc/secgen_test/unrealirc.rb @@ -0,0 +1,16 @@ +require_relative '../../../../../lib/post_provision_test' + +class UnrealircTest < PostProvisionTest + def initialize + self.module_name = 'unrealirc' + self.module_path = get_module_path(__FILE__) + super + end + + def test_module + super + test_service_up + end +end + +UnrealircTest.new.run \ No newline at end of file diff --git a/modules/services/unix/nfs/nfs_share/secgen_test/nfs_share.rb b/modules/services/unix/nfs/nfs_share/secgen_test/nfs_share.rb new file mode 100644 index 000000000..a08e90b04 --- /dev/null +++ b/modules/services/unix/nfs/nfs_share/secgen_test/nfs_share.rb @@ -0,0 +1,17 @@ +require_relative '../../../../../lib/post_provision_test' + +class NFSShareTest < PostProvisionTest + def initialize + self.module_name = 'ntp' + self.module_path = get_module_path(__FILE__) + super + self.port = 2049 + end + + def test_module + super + test_service_up + end +end + +NFSShareTest.new.run \ No newline at end of file diff --git a/modules/services/unix/ntp/ntp/secgen_test/ntp.rb b/modules/services/unix/ntp/ntp/secgen_test/ntp.rb new file mode 100644 index 000000000..8a72f2117 --- /dev/null +++ b/modules/services/unix/ntp/ntp/secgen_test/ntp.rb @@ -0,0 +1,39 @@ +require_relative '../../../../../lib/post_provision_test' +require 'net/ntp' + +class NTPTest < PostProvisionTest + def initialize + self.module_name = 'ntp' + self.module_path = get_module_path(__FILE__) + super + self.port = 123 + end + + def test_module + super + test_ntp_query + end + + def test_ntp_query + time_response = '' + retries = 5 + while retries > 0 + begin + time_response = Net::NTP.get(system_ip, port).time + break + rescue Errno::ECONNREFUSED, Timeout::Error + # do nothing + end + sleep 2 + retries = -1 + end + if time_response != '' + self.outputs << "PASSED: NTP responded on UDP port #{port} with #{time_response}" + else + self.outputs << "FAILED: unable to connect to #{module_name} on UDP port #{port}" + self.all_tests_passed = false + end + end +end + +NTPTest.new.run \ No newline at end of file diff --git a/modules/services/unix/smb/samba/secgen_test/samba.rb b/modules/services/unix/smb/samba/secgen_test/samba.rb new file mode 100644 index 000000000..f406ebc26 --- /dev/null +++ b/modules/services/unix/smb/samba/secgen_test/samba.rb @@ -0,0 +1,17 @@ +require_relative '../../../../../lib/post_provision_test' + +class SambaTest < PostProvisionTest + def initialize + self.module_name = 'samba' + self.module_path = get_module_path(__FILE__) + super + self.port = 139 + end + + def test_module + super + test_service_up + end +end + +SambaTest.new.run \ No newline at end of file diff --git a/modules/utilities/unix/labtainers/files/labtainer.files/trunk/setup_scripts/install-docker-debian.sh b/modules/utilities/unix/labtainers/files/labtainer.files/trunk/setup_scripts/install-docker-debian.sh new file mode 100755 index 000000000..261e410ea --- /dev/null +++ b/modules/utilities/unix/labtainers/files/labtainer.files/trunk/setup_scripts/install-docker-debian.sh @@ -0,0 +1,90 @@ +#!/bin/bash +: <<'END' +This software was created by United States Government employees at +The Center for the Information Systems Studies and Research (CISR) +at the Naval Postgraduate School NPS. Please note that within the +United States, copyright protection is not available for any works +created by United States Government employees, pursuant to Title 17 +United States Code Section 105. This software is in the public +domain and is not subject to copyright. +END +# +#Install Docker on a Debian system, along with other packages required by Labtainers +# +type sudo >/dev/null 2>&1 || { echo >&2 "Please install sudo. Aborting."; exit 1; } +sudo -v || { echo >&2 "Please make sure user is sudoer. Aborting."; exit 1; } +#needed packages for Docker install +sudo apt-get update +sudo apt-get -y install apt-transport-https ca-certificates curl gnupg2 software-properties-common + +#adds Docker�s official GPG Key +curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add - + +#used to verify matching Key ID (optional) +#sudo apt-key fingerprint 0EBFCD88 + +#sets up stable repository +sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable" + +#installs Docker:Community Edition +sudo apt-get update +# SecGen change: repo is unauthenticated +sudo apt-get -y --allow-unauthenticated install docker-ce + +#gives user access to docker commands +sudo groupadd docker +sudo usermod -aG docker $USER + +#enables and starts docker +sudo systemctl start docker +sudo systemctl enable docker + +#additional packages needed for labtainers +sudo apt-get -y install python-pip +sudo pip install --upgrade pip +sudo pip install netaddr parse python-dateutil +sudo apt-get -y install openssh-server + +#---Checking if packages have been installed. If not, the system will not reboot and allow the user to investigate. +declare -a packagelist=("apt-transport-https" "ca-certificates" "curl" "gnupg2" "software-properties-common" "docker-ce" "python-pip" "openssh-server") +packagefail="false" + +for i in "${packagelist[@]}" +do +#echo $i +packagecheck=$(dpkg -s $i 2> /dev/null | grep Status) +#echo $packagecheck + if [ "$packagecheck" != "Status: install ok installed" ]; then + if [ $i = docker-ce ];then + echo "ERROR: '$i' package did not install properly. Please check the terminal output above for any errors related to the pacakge installation. Run the install script two more times. If the issue persists, go to docker docs and follow the instructions for installing docker. (Make sure the instructions is CE and is for your Linux distribution,e.g., Ubuntu and Fedora.)" + else + echo "ERROR: '$i' package did not install properly. Please check the terminal output above for any errors related to the pacakge installation. Try installing the '$i' package individually by executing this in the command line: 'sudo apt-get install $i" + fi + packagefail="true" + #echo $packagefail + fi +done + +pipcheck=$(pip list 2> /dev/null | grep -F netaddr) +#echo $pipcheck +if [ -z "$pipcheck" ]; then + echo "ERROR: 'netaddr' package did not install properly. Please check the terminal output for any errors related to the pacakge installation. Make sure 'python-pip' is installed and then try running this command: 'sudo -H pip install netaddr' " + packagefail="true" + #echo $packagefail +fi + +pipcheck=$(pip list 2> /dev/null | grep -F parse) +#echo $pipcheck +if [ -z "$pipcheck" ]; then + echo "ERROR: 'parse' package did not install properly. Please check the terminal output for any errors related to the package installation. Make sure 'python-pip' is installed and then try running this command: 'sudo -H pip install parse' " + packagefail="true" + #echo $packagefail +fi + +if [ $packagefail = "true" ]; then + exit 1 +fi + +exit 0 + +#Notes: The �-y� after each install means that the user doesn�t need to press �y� in between each package download. The install script is based on this page: https://docs.docker.com/engine/installation/linux/docker-ce/debian/ diff --git a/modules/utilities/unix/labtainers/manifests/config.pp b/modules/utilities/unix/labtainers/manifests/config.pp new file mode 100644 index 000000000..dfb24ddb1 --- /dev/null +++ b/modules/utilities/unix/labtainers/manifests/config.pp @@ -0,0 +1,12 @@ +class labtainers::config{ + require labtainers::install + + $secgen_parameters = secgen_functions::get_parameters($::base64_inputs_file) + $lab = $secgen_parameters['lab'][0] + + exec { 'start lab': + command => "/opt/labtainers/labtainer-student/labtainer $lab", + provider => shell, + } + +} diff --git a/modules/utilities/unix/labtainers/manifests/install.pp b/modules/utilities/unix/labtainers/manifests/install.pp new file mode 100644 index 000000000..c140d6ea6 --- /dev/null +++ b/modules/utilities/unix/labtainers/manifests/install.pp @@ -0,0 +1,27 @@ +class labtainers::install{ + # $json_inputs = base64('decode', $::base64_inputs) + # $secgen_parameters = parsejson($json_inputs) + # $server_ip = $secgen_parameters['server_ip'][0] + # $port = $secgen_parameters['port'][0] + + + # these are also installed by the install script, but good to use puppet where possible + package { ['apt-transport-https', 'ca-certificates', 'curl', 'gnupg2', 'software-properties-common', 'python-pip', 'openssh-server']: + ensure => 'installed', + } -> + + file { '/opt/labtainers': + ensure => directory, + recurse => true, + source => 'puppet:///modules/labtainers/labtainer.files', + mode => '0766', + owner => 'root', + group => 'root', + } -> + + exec { 'install script': + command => '/opt/labtainers/install-labtainer.sh', + provider => shell, + } + +} diff --git a/modules/utilities/unix/system/parameterised_accounts/secgen_test/parameterised_accounts.rb b/modules/utilities/unix/system/parameterised_accounts/secgen_test/parameterised_accounts.rb new file mode 100644 index 000000000..b869febd9 --- /dev/null +++ b/modules/utilities/unix/system/parameterised_accounts/secgen_test/parameterised_accounts.rb @@ -0,0 +1,24 @@ +require_relative '../../../../../lib/post_provision_test' + +class ParameterisedAccountsTest < PostProvisionTest + def initialize + self.module_name = 'parameterised_accounts' + self.module_path = get_module_path(__FILE__) + super + end + + def test_module + super + test_accounts_exist + end + + def test_accounts_exist + get_json_inputs['accounts'].each do |account| + account = JSON.parse(account) + username = account['username'] + test_local_command("#{username} account exists?", 'cat /etc/passwd', username) + end + end +end + +ParameterisedAccountsTest.new.run \ No newline at end of file diff --git a/modules/utilities/unix/update/apt_upgrade/manifests/apt.pp b/modules/utilities/unix/update/apt_upgrade/manifests/apt.pp index 654d0c6f0..3b406bb74 100644 --- a/modules/utilities/unix/update/apt_upgrade/manifests/apt.pp +++ b/modules/utilities/unix/update/apt_upgrade/manifests/apt.pp @@ -1,17 +1,33 @@ class apt_upgrade::apt { - case $operatingsystem { - 'Debian': { - exec { 'update': - command => "/usr/bin/apt-get upgrade", - tries => 5, - try_sleep => 30, + + notice("Running apt-upgrade module...") + + if defined('dirtycow::config') { + notice("vulnerabilities/unix/local/dirtycow included - skipping apt-get upgrade...") + } else { + case $operatingsystem { + 'Debian': { + # can't upgrade puppet agent mid-provision or it breaks on oVirt. + exec { 'hold puppet-agent': + command => '/usr/bin/apt-mark hold puppet-agent' + } + exec { 'update': + command => "/usr/bin/apt-get -y upgrade", + tries => 5, + try_sleep => 30, + timeout => 0, + logoutput => true, + require => Exec['hold puppet-agent'], + } } - } - 'Ubuntu': { - exec { 'update': - command => "/usr/bin/apt-get upgrade", - tries => 5, - try_sleep => 30, + 'Ubuntu': { + exec { 'update': + command => "/usr/bin/apt-get -y upgrade", + tries => 5, + try_sleep => 30, + timeout => 0, + logoutput => true, + } } } } diff --git a/modules/vulnerabilities/unix/access_control_misconfigurations/readable_shadow/manifests/config.pp b/modules/vulnerabilities/unix/access_control_misconfigurations/readable_shadow/manifests/config.pp index 0639445c9..58fe907a0 100644 --- a/modules/vulnerabilities/unix/access_control_misconfigurations/readable_shadow/manifests/config.pp +++ b/modules/vulnerabilities/unix/access_control_misconfigurations/readable_shadow/manifests/config.pp @@ -1,6 +1,6 @@ class readable_shadow::config { file { '/etc/shadow': ensure => present, - mode => '0622', + mode => '0644', } } diff --git a/modules/vulnerabilities/unix/access_control_misconfigurations/readable_shadow/secgen_metadata.xml b/modules/vulnerabilities/unix/access_control_misconfigurations/readable_shadow/secgen_metadata.xml index 48ed6a44e..8f3cbeece 100644 --- a/modules/vulnerabilities/unix/access_control_misconfigurations/readable_shadow/secgen_metadata.xml +++ b/modules/vulnerabilities/unix/access_control_misconfigurations/readable_shadow/secgen_metadata.xml @@ -6,7 +6,7 @@ Readable Shadow File Thomas Shaw MIT - Changes permissions on shadow file to 0622, reveals password hashes to local users. + Changes permissions on shadow file to 0611, reveals password hashes to local users. This is not a common misconfiguration, and not particularly subtle. access_control_misconfiguration diff --git a/modules/vulnerabilities/unix/access_control_misconfigurations/readable_shadow/secgen_test/readable_shadow.rb b/modules/vulnerabilities/unix/access_control_misconfigurations/readable_shadow/secgen_test/readable_shadow.rb new file mode 100644 index 000000000..1bb66fc01 --- /dev/null +++ b/modules/vulnerabilities/unix/access_control_misconfigurations/readable_shadow/secgen_test/readable_shadow.rb @@ -0,0 +1,18 @@ +require_relative '../../../../../lib/post_provision_test' + + +class ReadableShadowTest < PostProvisionTest + def initialize + self.module_name = 'readable_shadow' + self.module_path = get_module_path(__FILE__) + super + end + + def test_module + super + test_local_command('Shadow readable?','sudo ls -la /etc/shadow', '-rw-r--r--') + end + +end + +ReadableShadowTest.new.run \ No newline at end of file diff --git a/modules/vulnerabilities/unix/access_control_misconfigurations/suid_root_bash/manifests/config.pp b/modules/vulnerabilities/unix/access_control_misconfigurations/suid_root_bash/manifests/config.pp index 1931fcfab..87063f48a 100644 --- a/modules/vulnerabilities/unix/access_control_misconfigurations/suid_root_bash/manifests/config.pp +++ b/modules/vulnerabilities/unix/access_control_misconfigurations/suid_root_bash/manifests/config.pp @@ -1,4 +1,4 @@ -class uid_bash_root::config { +class suid_root_bash::config { file { '/bin/bash': ensure => present, mode => '4777', diff --git a/modules/vulnerabilities/unix/access_control_misconfigurations/suid_root_bash/secgen_metadata.xml b/modules/vulnerabilities/unix/access_control_misconfigurations/suid_root_bash/secgen_metadata.xml index 8e4f18057..718b2a5a6 100644 --- a/modules/vulnerabilities/unix/access_control_misconfigurations/suid_root_bash/secgen_metadata.xml +++ b/modules/vulnerabilities/unix/access_control_misconfigurations/suid_root_bash/secgen_metadata.xml @@ -15,4 +15,8 @@ Shell permission misconfiguration Bash shell running with root permissions due to suid bit set (try /bin/bash -cp "some_command") + + + .*shellshock.* + \ No newline at end of file diff --git a/modules/vulnerabilities/unix/access_control_misconfigurations/suid_root_bash/secgen_test/suid_root_bash.rb b/modules/vulnerabilities/unix/access_control_misconfigurations/suid_root_bash/secgen_test/suid_root_bash.rb new file mode 100644 index 000000000..df9d697cc --- /dev/null +++ b/modules/vulnerabilities/unix/access_control_misconfigurations/suid_root_bash/secgen_test/suid_root_bash.rb @@ -0,0 +1,19 @@ +require_relative '../../../../../lib/post_provision_test' + + +class SUIDBashTest < PostProvisionTest + def initialize + self.module_name = 'suid_root_bash' + self.module_path = get_module_path(__FILE__) + super + end + + def test_module + super + test_local_command('bash suid bit set?','sudo ls -la /bin/bash', '-rwsrwxrwx') + test_local_command('bash runs?','/bin/bash --version', 'GNU bash') + end + +end + +SUIDBashTest.new.run \ No newline at end of file diff --git a/modules/vulnerabilities/unix/access_control_misconfigurations/suid_root_less/manifests/change_uid_permissions.pp b/modules/vulnerabilities/unix/access_control_misconfigurations/suid_root_less/manifests/change_uid_permissions.pp index 91e2c793d..ee920c929 100644 --- a/modules/vulnerabilities/unix/access_control_misconfigurations/suid_root_less/manifests/change_uid_permissions.pp +++ b/modules/vulnerabilities/unix/access_control_misconfigurations/suid_root_less/manifests/change_uid_permissions.pp @@ -1,4 +1,4 @@ -class uid_less_root::change_uid_permissions ($file_input = [], $user = 'root') { +class suid_root_less::change_uid_permissions ($file_input = [], $user = 'root') { $file_input.each |$file, $permission_code| { file { $file: mode => $permission_code, diff --git a/modules/vulnerabilities/unix/access_control_misconfigurations/suid_root_less/secgen_test/suid_root_less.rb b/modules/vulnerabilities/unix/access_control_misconfigurations/suid_root_less/secgen_test/suid_root_less.rb new file mode 100644 index 000000000..66c962058 --- /dev/null +++ b/modules/vulnerabilities/unix/access_control_misconfigurations/suid_root_less/secgen_test/suid_root_less.rb @@ -0,0 +1,19 @@ +require_relative '../../../../../lib/post_provision_test' + + +class SUIDLessTest < PostProvisionTest + def initialize + self.module_name = 'suid_root_less' + self.module_path = get_module_path(__FILE__) + super + end + + def test_module + super + test_local_command('less suid bit set?','sudo ls -la /bin/less', '-rwsrwxrwx') + test_local_command('less runs?','/bin/less --help', 'Commands marked with * may be preceded by a number') + end + +end + +SUIDLessTest.new.run \ No newline at end of file diff --git a/modules/vulnerabilities/unix/access_control_misconfigurations/suid_root_less/suid_root_less.pp b/modules/vulnerabilities/unix/access_control_misconfigurations/suid_root_less/suid_root_less.pp index f7ac9d611..b678f0062 100644 --- a/modules/vulnerabilities/unix/access_control_misconfigurations/suid_root_less/suid_root_less.pp +++ b/modules/vulnerabilities/unix/access_control_misconfigurations/suid_root_less/suid_root_less.pp @@ -1,4 +1,4 @@ -class {'uid_less_root::change_uid_permissions': +class {'suid_root_less::change_uid_permissions': user => 'root', file_input => { '/bin/less' => '4777', diff --git a/modules/vulnerabilities/unix/access_control_misconfigurations/suid_root_nano/secgen_test/suid_root_nano.rb b/modules/vulnerabilities/unix/access_control_misconfigurations/suid_root_nano/secgen_test/suid_root_nano.rb new file mode 100644 index 000000000..e8f8c1589 --- /dev/null +++ b/modules/vulnerabilities/unix/access_control_misconfigurations/suid_root_nano/secgen_test/suid_root_nano.rb @@ -0,0 +1,19 @@ +require_relative '../../../../../lib/post_provision_test' + + +class SUIDNanoTest < PostProvisionTest + def initialize + self.module_name = 'suid_root_nano' + self.module_path = get_module_path(__FILE__) + super + end + + def test_module + super + test_local_command('nano suid bit set?','sudo ls -la /bin/nano', '-rwsrwxrwx') + test_local_command('nano runs?','/bin/nano --version', 'GNU nano') + end + +end + +SUIDNanoTest.new.run \ No newline at end of file diff --git a/modules/vulnerabilities/unix/access_control_misconfigurations/suid_root_vi/manifests/change_uid_permissions.pp b/modules/vulnerabilities/unix/access_control_misconfigurations/suid_root_vi/manifests/change_uid_permissions.pp index bd2ecc8a8..e41feba25 100644 --- a/modules/vulnerabilities/unix/access_control_misconfigurations/suid_root_vi/manifests/change_uid_permissions.pp +++ b/modules/vulnerabilities/unix/access_control_misconfigurations/suid_root_vi/manifests/change_uid_permissions.pp @@ -1,4 +1,4 @@ -class uid_vi_root::change_uid_permissions ($file_input = [],$user = 'root') { +class suid_root_vi::change_uid_permissions ($file_input = [],$user = 'root') { $file_input.each |String $file, String $permission_code| { file { $file: mode => $permission_code, diff --git a/modules/vulnerabilities/unix/access_control_misconfigurations/suid_root_vi/secgen_test/suid_root_vi.rb b/modules/vulnerabilities/unix/access_control_misconfigurations/suid_root_vi/secgen_test/suid_root_vi.rb new file mode 100644 index 000000000..31277d102 --- /dev/null +++ b/modules/vulnerabilities/unix/access_control_misconfigurations/suid_root_vi/secgen_test/suid_root_vi.rb @@ -0,0 +1,18 @@ +require_relative '../../../../../lib/post_provision_test' + + +class SUIDviTest < PostProvisionTest + def initialize + self.module_name = 'suid_root_vi' + self.module_path = get_module_path(__FILE__) + super + end + + def test_module + super + test_local_command('vi suid bit set?','sudo ls -la $(readlink -f `whereis vim`)', 'rwsrwxrwx') + end + +end + +SUIDviTest.new.run \ No newline at end of file diff --git a/modules/vulnerabilities/unix/access_control_misconfigurations/suid_root_vi/suid_root_vi.pp b/modules/vulnerabilities/unix/access_control_misconfigurations/suid_root_vi/suid_root_vi.pp index fcf899cc0..ca86b21fb 100644 --- a/modules/vulnerabilities/unix/access_control_misconfigurations/suid_root_vi/suid_root_vi.pp +++ b/modules/vulnerabilities/unix/access_control_misconfigurations/suid_root_vi/suid_root_vi.pp @@ -1,7 +1,8 @@ -class {'uid_vi_root::change_uid_permissions': +class {'suid_root_vi::change_uid_permissions': file_input => { - '/usr/bin/vi' => '4755', - '/etc/alternatives/vi' => '4755', - '/usr/bin/vim.tiny' => '4755', + '/usr/bin/vi' => '4777', + '/etc/alternatives/vi' => '4777', + '/usr/bin/vim.tiny' => '4777', + '/usr/bin/vim.basic' => '4777', } -} +} \ No newline at end of file diff --git a/modules/vulnerabilities/unix/access_control_misconfigurations/writable_groups/secgen_test/writable_groups.rb b/modules/vulnerabilities/unix/access_control_misconfigurations/writable_groups/secgen_test/writable_groups.rb new file mode 100644 index 000000000..92f7b6f92 --- /dev/null +++ b/modules/vulnerabilities/unix/access_control_misconfigurations/writable_groups/secgen_test/writable_groups.rb @@ -0,0 +1,18 @@ +require_relative '../../../../../lib/post_provision_test' + + +class WritableGroupsTest < PostProvisionTest + def initialize + self.module_name = 'writable_groups' + self.module_path = get_module_path(__FILE__) + super + end + + def test_module + super + test_local_command('writable groups?','sudo ls -la /etc/group', 'rwxrwxrwx') + end + +end + +WritableGroupsTest.new.run \ No newline at end of file diff --git a/modules/vulnerabilities/unix/access_control_misconfigurations/writable_passwd/secgen_test/writable_passwd.rb b/modules/vulnerabilities/unix/access_control_misconfigurations/writable_passwd/secgen_test/writable_passwd.rb new file mode 100644 index 000000000..0b2d12630 --- /dev/null +++ b/modules/vulnerabilities/unix/access_control_misconfigurations/writable_passwd/secgen_test/writable_passwd.rb @@ -0,0 +1,18 @@ +require_relative '../../../../../lib/post_provision_test' + + +class WritablePasswdTest < PostProvisionTest + def initialize + self.module_name = 'writable_passwd' + self.module_path = get_module_path(__FILE__) + super + end + + def test_module + super + test_local_command('writable /etc/passwd?','sudo ls -la /etc/passwd', 'rwxrwxrwx') + end + +end + +WritablePasswdTest.new.run \ No newline at end of file diff --git a/modules/vulnerabilities/unix/access_control_misconfigurations/writable_shadow/secgen_test/writable_shadow.rb b/modules/vulnerabilities/unix/access_control_misconfigurations/writable_shadow/secgen_test/writable_shadow.rb new file mode 100644 index 000000000..d1d41d3f0 --- /dev/null +++ b/modules/vulnerabilities/unix/access_control_misconfigurations/writable_shadow/secgen_test/writable_shadow.rb @@ -0,0 +1,18 @@ +require_relative '../../../../../lib/post_provision_test' + + +class WritableShadowTest < PostProvisionTest + def initialize + self.module_name = 'writable_shadow' + self.module_path = get_module_path(__FILE__) + super + end + + def test_module + super + test_local_command('writable /etc/shadow?','sudo ls -la /etc/shadow', 'rwxrwxrwx') + end + +end + +WritableShadowTest.new.run \ No newline at end of file diff --git a/modules/vulnerabilities/unix/bash/shellshock/secgen_test/shellshock.rb b/modules/vulnerabilities/unix/bash/shellshock/secgen_test/shellshock.rb new file mode 100644 index 000000000..7f506e288 --- /dev/null +++ b/modules/vulnerabilities/unix/bash/shellshock/secgen_test/shellshock.rb @@ -0,0 +1,18 @@ +require_relative '../../../../../lib/post_provision_test' + + +class ShellshockTest < PostProvisionTest + def initialize + self.module_name = 'shellshock' + self.module_path = get_module_path(__FILE__) + super + end + + def test_module + super + test_local_command('correct /bin/bash version?','/bin/bash --version', 'version 4.1') + end + +end + +ShellshockTest.new.run \ No newline at end of file diff --git a/modules/vulnerabilities/unix/ctf/defcon_quals_2016/dc16_amadhj/manifests/install.pp b/modules/vulnerabilities/unix/ctf/defcon_quals_2016/dc16_amadhj/manifests/install.pp deleted file mode 100644 index 5fb68ebc5..000000000 --- a/modules/vulnerabilities/unix/ctf/defcon_quals_2016/dc16_amadhj/manifests/install.pp +++ /dev/null @@ -1,39 +0,0 @@ -class dc16_amadhj::install { - $secgen_params = secgen_functions::get_parameters($::base64_inputs_file) - $group = $secgen_params['group'] - - if $secgen_params['account'][0] and $secgen_params['account'][0] != '' { - $account = parsejson($secgen_params['account'][0]) - } else { - $account = undef - } - - if $secgen_params['storage_directory'] and $secgen_params['storage_directory'][0] { - $storage_dir = $secgen_params['storage_directory'][0] - } else { - $storage_dir = undef - } - - if $group { - ::secgen_functions::install_setgid_binary { 'defcon16_amadhj_group': - source_module_name => $module_name, - challenge_name => $secgen_params['challenge_name'][0], - group => $group[0], - account => $account, - flag => $secgen_params['flag'][0], - flag_name => 'flag', - storage_dir => $storage_dir, - strings_to_leak => $secgen_params['strings_to_leak'], - } - } else { - ::secgen_functions::install_setuid_root_binary { 'defcon16_amadhj': - source_module_name => $module_name, - challenge_name => $secgen_params['challenge_name'][0], - account => $account, - flag => $secgen_params['flag'][0], - flag_name => 'flag', - storage_dir => $storage_dir, - strings_to_leak => $secgen_params['strings_to_leak'], - } - } -} diff --git a/modules/vulnerabilities/unix/ctf/example/python2_challenge_example/manifests/install.pp b/modules/vulnerabilities/unix/ctf/example/python2_challenge_example/manifests/install.pp deleted file mode 100644 index 747a9f5a8..000000000 --- a/modules/vulnerabilities/unix/ctf/example/python2_challenge_example/manifests/install.pp +++ /dev/null @@ -1,45 +0,0 @@ -class python2_challenge_example::install { - $secgen_params = secgen_functions::get_parameters($::base64_inputs_file) - $group = $secgen_params['group'] - $script_data = $secgen_params['script_data'] - - if $secgen_params['account'][0] and $secgen_params['account'][0] != '' { - $account = parsejson($secgen_params['account'][0]) - } else { - $account = undef - } - - if $secgen_params['storage_directory'] and $secgen_params['storage_directory'][0] { - $storage_dir = $secgen_params['storage_directory'][0] - } else { - $storage_dir = undef - } - - if $group { - ::secgen_functions::install_setgid_script { 'python2_challenge_example': - source_module_name => $module_name, - challenge_name => $secgen_params['challenge_name'][0], - script_name => 'test.py', - script_data => $script_data[0], - group => $group[0], - account => $account, - flag => $secgen_params['flag'][0], - flag_name => 'flag', - storage_dir => $storage_dir, - strings_to_leak => $secgen_params['strings_to_leak'], - } - } else { - ::secgen_functions::install_setuid_root_script { 'python2_challenge_example': - source_module_name => $module_name, - challenge_name => $secgen_params['challenge_name'][0], - script_name => 'test.py', - script_data => $script_data[0], - account => $account, - flag => $secgen_params['flag'][0], - flag_name => 'flag', - storage_dir => $storage_dir, - strings_to_leak => $secgen_params['strings_to_leak'], - } - } - -} diff --git a/modules/vulnerabilities/unix/ctf/example/python2_challenge_example/python2_challenge_example.pp b/modules/vulnerabilities/unix/ctf/example/python2_challenge_example/python2_challenge_example.pp deleted file mode 100644 index 99d16c5df..000000000 --- a/modules/vulnerabilities/unix/ctf/example/python2_challenge_example/python2_challenge_example.pp +++ /dev/null @@ -1 +0,0 @@ -include python2_challenge_example::install diff --git a/modules/vulnerabilities/unix/ctf/example/python2_challenge_example/secgen_metadata.xml b/modules/vulnerabilities/unix/ctf/example/python2_challenge_example/secgen_metadata.xml deleted file mode 100644 index 7f102f83e..000000000 --- a/modules/vulnerabilities/unix/ctf/example/python2_challenge_example/secgen_metadata.xml +++ /dev/null @@ -1,63 +0,0 @@ - - - - python2 Challenge Example - Thomas Shaw - MIT - python2 challenge example - - script_challenge - none - local - linux - - misc - example - - - challenge_name - script_data - account - flag - - storage_directory - - group - - python2_script_example - - - - - - - - challenges - - - password - - - - - - - - python2_script_example - - - - utilities/unix/system/accounts - - - - utilities/unix/system/binary_script_container - - - - utilities/unix/languages/python2/python - - - diff --git a/modules/vulnerabilities/unix/ctf/example/ruby_challenge_example/manifests/install.pp b/modules/vulnerabilities/unix/ctf/example/ruby_challenge_example/manifests/install.pp deleted file mode 100644 index f1bb96019..000000000 --- a/modules/vulnerabilities/unix/ctf/example/ruby_challenge_example/manifests/install.pp +++ /dev/null @@ -1,17 +0,0 @@ -class ruby_challenge_example::install { - $secgen_params = secgen_functions::get_parameters($::base64_inputs_file) - $challenge_name = $secgen_params['challenge_name'][0] - - ::secgen_functions::install_setgid_script { $challenge_name: - source_module_name => $module_name, - challenge_name => $challenge_name, - script_name => 'test.rb', - script_data => $secgen_params['script_data'][0], - group => $secgen_params['group'], - account => $secgen_params['account'], - flag => $secgen_params['flag'], - port => $secgen_params['port'], - storage_directory => $secgen_params['storage_directory'], - strings_to_leak => $secgen_params['strings_to_leak'], - } -} diff --git a/modules/vulnerabilities/unix/ctf/example/ruby_challenge_example/ruby_challenge_example.pp b/modules/vulnerabilities/unix/ctf/example/ruby_challenge_example/ruby_challenge_example.pp deleted file mode 100644 index 7bf010122..000000000 --- a/modules/vulnerabilities/unix/ctf/example/ruby_challenge_example/ruby_challenge_example.pp +++ /dev/null @@ -1 +0,0 @@ -include ruby_challenge_example::install diff --git a/modules/vulnerabilities/unix/ctf/example/ruby_challenge_example/secgen_metadata.xml b/modules/vulnerabilities/unix/ctf/example/ruby_challenge_example/secgen_metadata.xml deleted file mode 100644 index f64b75118..000000000 --- a/modules/vulnerabilities/unix/ctf/example/ruby_challenge_example/secgen_metadata.xml +++ /dev/null @@ -1,67 +0,0 @@ - - - - Ruby Challenge Example - Thomas Shaw - MIT - Ruby challenge example - - ctf_challenge - none - local - linux - - misc - example - - - challenge_name - script_data - account - flag - - group - - storage_directory - - port - - - ruby_challenge_example - - - - - - - - challenges - - - password - - - - - - - - - utilities/unix/system/accounts - - - - utilities/unix/system/binary_script_container - - - - utilities/unix/languages/ruby - - - - utilities/unix/system/xinetd - - - diff --git a/modules/vulnerabilities/unix/ctf/misc/hidden_file/manifests/install.pp b/modules/vulnerabilities/unix/ctf/misc/hidden_file/manifests/install.pp index f6939b0a8..e982a60f6 100644 --- a/modules/vulnerabilities/unix/ctf/misc/hidden_file/manifests/install.pp +++ b/modules/vulnerabilities/unix/ctf/misc/hidden_file/manifests/install.pp @@ -30,6 +30,7 @@ class hidden_file::install { storage_directory => $challenge_directory, strings_to_leak => $strings_to_leak, leaked_from => "$challenge_directory-hidden_file", + mode => '0644' } } diff --git a/modules/vulnerabilities/unix/ctf/reverse/java/java_decompile/manifests/install.pp b/modules/vulnerabilities/unix/ctf/reverse/java/java_decompile/manifests/install.pp index d33eae229..63fdba171 100644 --- a/modules/vulnerabilities/unix/ctf/reverse/java/java_decompile/manifests/install.pp +++ b/modules/vulnerabilities/unix/ctf/reverse/java/java_decompile/manifests/install.pp @@ -36,6 +36,7 @@ class java_decompile::install { leaked_filenames => $leaked_filenames, strings_to_leak => $strings_to_leak, leaked_from => "java_decompile_instructions", + mode => '0644' } # Run the template to generate a .java file diff --git a/modules/vulnerabilities/unix/ftp/proftpd_133c_backdoor/secgen_test/proftpd_133c_backdoor.rb b/modules/vulnerabilities/unix/ftp/proftpd_133c_backdoor/secgen_test/proftpd_133c_backdoor.rb new file mode 100644 index 000000000..2d22e586d --- /dev/null +++ b/modules/vulnerabilities/unix/ftp/proftpd_133c_backdoor/secgen_test/proftpd_133c_backdoor.rb @@ -0,0 +1,16 @@ +require_relative '../../../../../lib/post_provision_test' + +class Proftpd133cBackdoorTest < PostProvisionTest + def initialize + self.module_name = 'proftpd_133c_backdoor' + self.module_path = get_module_path(__FILE__) + super + end + + def test_module + super + test_service_up + end +end + +Proftpd133cBackdoorTest.new.run \ No newline at end of file diff --git a/modules/vulnerabilities/unix/ftp/vsftpd_234_backdoor/secgen_test/vsftpd_234_backdoor.rb b/modules/vulnerabilities/unix/ftp/vsftpd_234_backdoor/secgen_test/vsftpd_234_backdoor.rb new file mode 100644 index 000000000..176bcfb8b --- /dev/null +++ b/modules/vulnerabilities/unix/ftp/vsftpd_234_backdoor/secgen_test/vsftpd_234_backdoor.rb @@ -0,0 +1,16 @@ +require_relative '../../../../../lib/post_provision_test' + +class Vsftpd234BackdoorTest < PostProvisionTest + def initialize + self.module_name = 'vsftpd_234_backdoor' + self.module_path = get_module_path(__FILE__) + super + end + + def test_module + super + test_service_up + end +end + +Vsftpd234BackdoorTest.new.run \ No newline at end of file diff --git a/modules/vulnerabilities/unix/irc/unrealirc_3281_backdoor/secgen_metadata.xml b/modules/vulnerabilities/unix/irc/unrealirc_3281_backdoor/secgen_metadata.xml index c5ddf6fa2..fe04f8218 100644 --- a/modules/vulnerabilities/unix/irc/unrealirc_3281_backdoor/secgen_metadata.xml +++ b/modules/vulnerabilities/unix/irc/unrealirc_3281_backdoor/secgen_metadata.xml @@ -84,9 +84,9 @@ unrealircd MIT - - .*Stretch.* - + + + .*Kali.* diff --git a/modules/vulnerabilities/unix/irc/unrealirc_3281_backdoor/secgen_test/unrealirc_3281_backdoor.rb b/modules/vulnerabilities/unix/irc/unrealirc_3281_backdoor/secgen_test/unrealirc_3281_backdoor.rb new file mode 100644 index 000000000..f58b4c22e --- /dev/null +++ b/modules/vulnerabilities/unix/irc/unrealirc_3281_backdoor/secgen_test/unrealirc_3281_backdoor.rb @@ -0,0 +1,16 @@ +require_relative '../../../../../lib/post_provision_test' + +class Unrealirc3281BackdoorTest < PostProvisionTest + def initialize + self.module_name = 'unrealirc_3281_backdoor' + self.module_path = get_module_path(__FILE__) + super + end + + def test_module + super + test_service_up + end +end + +Unrealirc3281BackdoorTest.new.run \ No newline at end of file diff --git a/modules/vulnerabilities/unix/local/chkrootkit/manifests/install.pp b/modules/vulnerabilities/unix/local/chkrootkit/manifests/install.pp index 3cf0df123..0ceda4ac2 100644 --- a/modules/vulnerabilities/unix/local/chkrootkit/manifests/install.pp +++ b/modules/vulnerabilities/unix/local/chkrootkit/manifests/install.pp @@ -40,5 +40,6 @@ class chkrootkit::install { leaked_filenames => $leaked_filenames, strings_to_leak => $strings_to_leak, leaked_from => "chkrootkit_vuln", + mode => '0600' } } \ No newline at end of file diff --git a/modules/vulnerabilities/unix/local/chkrootkit/secgen_test/chkrootkit.rb b/modules/vulnerabilities/unix/local/chkrootkit/secgen_test/chkrootkit.rb new file mode 100644 index 000000000..452d4aa6b --- /dev/null +++ b/modules/vulnerabilities/unix/local/chkrootkit/secgen_test/chkrootkit.rb @@ -0,0 +1,17 @@ +require_relative '../../../../../lib/post_provision_test' + +class ChkrootkitVulnTest < PostProvisionTest + def initialize + self.module_name = 'chkrootkit' + self.module_path = get_module_path(__FILE__) + super + end + + def test_module + super + test_local_command('Chkrootkit binary exists?', 'sudo ls -la /usr/sbin/chkrootkit', 'chkrootkit-0.49') + test_local_command('Chkrootkit runs?', 'sudo /usr/sbin/chkrootkit -V', 'chkrootkit version 0.49') + end + +end +ChkrootkitVulnTest.new.run \ No newline at end of file diff --git a/modules/vulnerabilities/unix/local/dirtycow/dirtycow.pp b/modules/vulnerabilities/unix/local/dirtycow/dirtycow.pp new file mode 100644 index 000000000..f86b5785e --- /dev/null +++ b/modules/vulnerabilities/unix/local/dirtycow/dirtycow.pp @@ -0,0 +1 @@ +include dirtycow::config \ No newline at end of file diff --git a/modules/vulnerabilities/unix/local/dirtycow/manifests/config.pp b/modules/vulnerabilities/unix/local/dirtycow/manifests/config.pp new file mode 100644 index 000000000..5a22e775d --- /dev/null +++ b/modules/vulnerabilities/unix/local/dirtycow/manifests/config.pp @@ -0,0 +1,3 @@ +class dirtycow::config { + notice("dirtycow::config: Do nothing, the apt upgrade just checks if we're defined and blocks apt-get upgrade if so.") +} \ No newline at end of file diff --git a/modules/vulnerabilities/unix/local/dirtycow/secgen_metadata.xml b/modules/vulnerabilities/unix/local/dirtycow/secgen_metadata.xml new file mode 100644 index 000000000..90d6aaac1 --- /dev/null +++ b/modules/vulnerabilities/unix/local/dirtycow/secgen_metadata.xml @@ -0,0 +1,33 @@ + + + + DirtyCow privilege escalation + Thomas Shaw + MIT + DirtyCow local privilege escalation. Including this module prevents the default apt-get upgrade from + running which leaves the wheezy bases vulnerable. + + + unpatched_kernel + race_condition + root_rwx + local + linux + medium + + + .*Stretch.* + + + .*Kali.* + + + .*Windows.* + + + .*Ubuntu.* + + + \ No newline at end of file diff --git a/modules/vulnerabilities/unix/local/dirtycow/secgen_test/dirtycow.rb b/modules/vulnerabilities/unix/local/dirtycow/secgen_test/dirtycow.rb new file mode 100644 index 000000000..1433b43a4 --- /dev/null +++ b/modules/vulnerabilities/unix/local/dirtycow/secgen_test/dirtycow.rb @@ -0,0 +1,17 @@ +require_relative '../../../../../lib/post_provision_test' + +class DirtyCOWTest < PostProvisionTest + def initialize + self.module_name = 'dirtycow' + self.module_path = get_module_path(__FILE__) + super + end + + def test_module + super + test_local_command('apt-get upgrade not performed?', 'sudo apt-get -u upgrade --assume-no','linux-image-3.') + end + +end + +DirtyCOWTest.new.run \ No newline at end of file diff --git a/modules/vulnerabilities/unix/local/setuid_nmap/manifests/init.pp b/modules/vulnerabilities/unix/local/setuid_nmap/manifests/init.pp index 54f0aca52..56c685a09 100644 --- a/modules/vulnerabilities/unix/local/setuid_nmap/manifests/init.pp +++ b/modules/vulnerabilities/unix/local/setuid_nmap/manifests/init.pp @@ -14,5 +14,6 @@ class setuid_nmap::init { leaked_filenames => $leaked_filenames, strings_to_leak => $strings_to_leak, leaked_from => "setuid_nmap", + mode => '0600' } } \ No newline at end of file diff --git a/modules/vulnerabilities/unix/local/setuid_nmap/secgen_test/setuid_nmap.rb b/modules/vulnerabilities/unix/local/setuid_nmap/secgen_test/setuid_nmap.rb new file mode 100644 index 000000000..78e9506f0 --- /dev/null +++ b/modules/vulnerabilities/unix/local/setuid_nmap/secgen_test/setuid_nmap.rb @@ -0,0 +1,19 @@ +require_relative '../../../../../lib/post_provision_test' + + +class SetUIDNmapTest < PostProvisionTest + def initialize + self.module_name = 'setuid_nmap' + self.module_path = get_module_path(__FILE__) + super + end + + def test_module + super + test_local_command('nmap has setuid flag?', 'sudo ls -la /usr/bin/nmap', '-rwsr-xr-x') + test_local_command('nmap runs?', 'sudo /usr/bin/nmap --version', 'Nmap version') + end + +end + +SetUIDNmapTest.new.run \ No newline at end of file diff --git a/modules/vulnerabilities/unix/misc/distcc_exec/secgen_test/distcc_exec.rb b/modules/vulnerabilities/unix/misc/distcc_exec/secgen_test/distcc_exec.rb new file mode 100644 index 000000000..e3e3245e5 --- /dev/null +++ b/modules/vulnerabilities/unix/misc/distcc_exec/secgen_test/distcc_exec.rb @@ -0,0 +1,17 @@ +require_relative '../../../../../lib/post_provision_test' + +class DistCCExecTest < PostProvisionTest + def initialize + self.module_name = 'distcc_exec' + self.module_path = get_module_path(__FILE__) + super + self.port = 3632 + end + + def test_module + super + test_service_up + end +end + +DistCCExecTest.new.run \ No newline at end of file diff --git a/modules/vulnerabilities/unix/misc/nc_backdoor/secgen_test/nc_backdoor.rb b/modules/vulnerabilities/unix/misc/nc_backdoor/secgen_test/nc_backdoor.rb new file mode 100644 index 000000000..ad8664095 --- /dev/null +++ b/modules/vulnerabilities/unix/misc/nc_backdoor/secgen_test/nc_backdoor.rb @@ -0,0 +1,16 @@ +require_relative '../../../../../lib/post_provision_test' + +class NcBackdoorTest < PostProvisionTest + def initialize + self.module_name = 'nc_backdoor' + self.module_path = get_module_path(__FILE__) + super + end + + def test_module + super + test_service_up + end +end + +NcBackdoorTest.new.run \ No newline at end of file diff --git a/modules/vulnerabilities/unix/web_training/dvwa/files/DVWA-master/vulnerabilities/csp/help/help.php b/modules/vulnerabilities/unix/web_training/dvwa/files/DVWA-master/vulnerabilities/csp/help/help.php index 739b3f5b4..0d3797cad 100644 --- a/modules/vulnerabilities/unix/web_training/dvwa/files/DVWA-master/vulnerabilities/csp/help/help.php +++ b/modules/vulnerabilities/unix/web_training/dvwa/files/DVWA-master/vulnerabilities/csp/help/help.php @@ -1,52 +1,52 @@ -
-

Help - Content Security Policy (CSP) Bypass

- -
- - - - -
-

About

-

Content Security Policy (CSP) is used to define where scripts and other resources can be loaded or executed from. This module will walk you through ways to bypass the policy based on common mistakes made by developers.

-

None of the vulnerabilities are actual vulnerabilities in CSP, they are vulnerabilities in the way it has been implemented.

- -


- -

Objective

-

Bypass Content Security Policy (CSP) and execute JavaScript in the page.

- -


- -

Low Level

-

Examine the policy to find all the sources that can be used to host external script files.

-
Spoiler: Scripts can be included from Pastebin, try storing some JavaScript on there and then loading it in.
- -
- -

Medium Level

-

The CSP policy tries to use a nonce to prevent inline scripts from being added by attackers.

-
Spoiler: Examine the nonce and see how it varies (or doesn't).
- -
- -

High Level

-

The page makes a JSONP call to source/jsonp.php passing the name of the function to callback to, you need to modify the jsonp.php script to change the callback function.

-
Spoiler: The JavaScript on the page will execute whatever is returned by the page, changing this to your own code will execute that instead
- -
- -

Impossible Level

-

- This level is an update of the high level where the JSONP call has its callback function hardcoded and the CSP policy is locked down to only allow external scripts. -

-
- -
- -
- -

Reference:

-

Reference:

-

Reference:

-
+
+

Help - Content Security Policy (CSP) Bypass

+ +
+ + + + +
+

About

+

Content Security Policy (CSP) is used to define where scripts and other resources can be loaded or executed from. This module will walk you through ways to bypass the policy based on common mistakes made by developers.

+

None of the vulnerabilities are actual vulnerabilities in CSP, they are vulnerabilities in the way it has been implemented.

+ +


+ +

Objective

+

Bypass Content Security Policy (CSP) and execute JavaScript in the page.

+ +


+ +

Low Level

+

Examine the policy to find all the sources that can be used to host external script files.

+
Spoiler: Scripts can be included from Pastebin, try storing some JavaScript on there and then loading it in.
+ +
+ +

Medium Level

+

The CSP policy tries to use a nonce to prevent inline scripts from being added by attackers.

+
Spoiler: Examine the nonce and see how it varies (or doesn't).
+ +
+ +

High Level

+

The page makes a JSONP call to source/jsonp.php passing the name of the function to callback to, you need to modify the jsonp.php script to change the callback function.

+
Spoiler: The JavaScript on the page will execute whatever is returned by the page, changing this to your own code will execute that instead
+ +
+ +

Impossible Level

+

+ This level is an update of the high level where the JSONP call has its callback function hardcoded and the CSP policy is locked down to only allow external scripts. +

+
+ +
+ +
+ +

Reference:

+

Reference:

+

Reference:

+
diff --git a/modules/vulnerabilities/unix/web_training/dvwa/secgen_test/dvwa.rb b/modules/vulnerabilities/unix/web_training/dvwa/secgen_test/dvwa.rb new file mode 100644 index 000000000..04cc12715 --- /dev/null +++ b/modules/vulnerabilities/unix/web_training/dvwa/secgen_test/dvwa.rb @@ -0,0 +1,16 @@ +require_relative '../../../../../lib/post_provision_test' + +class DVWATest < PostProvisionTest + def initialize + self.module_name = 'dvwa' + self.module_path = get_module_path(__FILE__) + super + end + + def test_module + super + test_service_up + end +end + +DVWATest.new.run \ No newline at end of file diff --git a/modules/vulnerabilities/unix/webapp/gitlist_040/secgen_test/gitlist_040.rb b/modules/vulnerabilities/unix/webapp/gitlist_040/secgen_test/gitlist_040.rb new file mode 100644 index 000000000..5dceede60 --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/gitlist_040/secgen_test/gitlist_040.rb @@ -0,0 +1,17 @@ +require_relative '../../../../../lib/post_provision_test' + +class Gitlist040Test < PostProvisionTest + def initialize + self.module_name = 'gitlist_040' + self.module_path = get_module_path(__FILE__) + super + end + + def test_module + super + test_service_up + test_html_returned_content('/', 'GitList') + end +end + +Gitlist040Test.new.run \ No newline at end of file diff --git a/modules/vulnerabilities/unix/webapp/moinmoin_195/secgen_test/moinmoin_195.rb b/modules/vulnerabilities/unix/webapp/moinmoin_195/secgen_test/moinmoin_195.rb new file mode 100644 index 000000000..bd0de9206 --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/moinmoin_195/secgen_test/moinmoin_195.rb @@ -0,0 +1,17 @@ +require_relative '../../../../../lib/post_provision_test' + +class MoinMoin195Test < PostProvisionTest + def initialize + self.module_name = 'moinmoin_195' + self.module_path = get_module_path(__FILE__) + super + end + + def test_module + super + test_service_up + test_html_returned_content('/index.html','') + end +end + +MoinMoin195Test.new.run \ No newline at end of file diff --git a/modules/vulnerabilities/unix/webapp/onlinestore/manifests/apache.pp b/modules/vulnerabilities/unix/webapp/onlinestore/manifests/apache.pp index 66137d77d..30389c6e7 100644 --- a/modules/vulnerabilities/unix/webapp/onlinestore/manifests/apache.pp +++ b/modules/vulnerabilities/unix/webapp/onlinestore/manifests/apache.pp @@ -12,8 +12,11 @@ class onlinestore::apache { ::apache::vhost { 'onlinestore': port => $port, docroot => $docroot, + notify => Tidy['os remove default site'], } + ensure_resource('tidy','os remove default site', {'path'=>'/etc/apache2/sites-enabled/000-default.conf'}) + case $operatingsystemrelease { /^9.*/: { # do 9.x stretch stuff exec { 'a2enmod php5.6': diff --git a/modules/vulnerabilities/unix/webapp/onlinestore/secgen_test/onlinestore.rb b/modules/vulnerabilities/unix/webapp/onlinestore/secgen_test/onlinestore.rb new file mode 100644 index 000000000..aea0a06a0 --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/onlinestore/secgen_test/onlinestore.rb @@ -0,0 +1,18 @@ +require_relative '../../../../../lib/post_provision_test' + +class OnlineStoreTest < PostProvisionTest + def initialize + self.module_name = 'onlinestore' + self.module_path = get_module_path(__FILE__) + super + end + + def test_module + super + test_service_up + test_html_returned_content('/index.php', 'Welcome to furniture!') + test_local_command('Users table populated?',"mysql -u csecvm --password=#{json_inputs['db_password'][0]} -D csecvm -e \"SELECT * FROM users;\"", JSON.parse(json_inputs['accounts'][1])['name']) + end +end + +OnlineStoreTest.new.run \ No newline at end of file diff --git a/modules/vulnerabilities/unix/webapp/wordpress_1x/secgen_test/wordpress_1x.rb b/modules/vulnerabilities/unix/webapp/wordpress_1x/secgen_test/wordpress_1x.rb new file mode 100644 index 000000000..c7d022bcd --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/wordpress_1x/secgen_test/wordpress_1x.rb @@ -0,0 +1,16 @@ +require_relative '../../../../../lib/post_provision_test' + +class Wordpress1xTest < PostProvisionTest + def initialize + self.module_name = 'wordpress_1x' + self.module_path = get_module_path(__FILE__) + super + end + + def test_module + super + test_service_up + end +end + +Wordpress1xTest.new.run \ No newline at end of file diff --git a/modules/vulnerabilities/unix/webapp/wordpress_2x/secgen_test/wordpress_2x.rb b/modules/vulnerabilities/unix/webapp/wordpress_2x/secgen_test/wordpress_2x.rb new file mode 100644 index 000000000..15ec4cbba --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/wordpress_2x/secgen_test/wordpress_2x.rb @@ -0,0 +1,16 @@ +require_relative '../../../../../lib/post_provision_test' + +class Wordpress2xTest < PostProvisionTest + def initialize + self.module_name = 'wordpress_2x' + self.module_path = get_module_path(__FILE__) + super + end + + def test_module + super + test_service_up + end +end + +Wordpress2xTest.new.run \ No newline at end of file diff --git a/modules/vulnerabilities/unix/webapp/wordpress_3x/secgen_test/wordpress_3x.rb b/modules/vulnerabilities/unix/webapp/wordpress_3x/secgen_test/wordpress_3x.rb new file mode 100644 index 000000000..fdc3ec350 --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/wordpress_3x/secgen_test/wordpress_3x.rb @@ -0,0 +1,16 @@ +require_relative '../../../../../lib/post_provision_test' + +class Wordpress3xTest < PostProvisionTest + def initialize + self.module_name = 'wordpress_3x' + self.module_path = get_module_path(__FILE__) + super + end + + def test_module + super + test_service_up + end +end + +Wordpress3xTest.new.run \ No newline at end of file diff --git a/modules/vulnerabilities/unix/webapp/wordpress_4x/secgen_test/wordpress_4x.rb b/modules/vulnerabilities/unix/webapp/wordpress_4x/secgen_test/wordpress_4x.rb new file mode 100644 index 000000000..39fda4055 --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/wordpress_4x/secgen_test/wordpress_4x.rb @@ -0,0 +1,16 @@ +require_relative '../../../../../lib/post_provision_test' + +class Wordpress4xTest < PostProvisionTest + def initialize + self.module_name = 'wordpress_4x' + self.module_path = get_module_path(__FILE__) + super + end + + def test_module + super + test_service_up + end +end + +Wordpress4xTest.new.run \ No newline at end of file diff --git a/scenarios/ctf/basic_narrative.xml b/scenarios/ctf/basic_narrative.xml index 608438232..7a0e31bf6 100644 --- a/scenarios/ctf/basic_narrative.xml +++ b/scenarios/ctf/basic_narrative.xml @@ -16,7 +16,7 @@ target_server - + 172.10.0.2 @@ -437,11 +437,9 @@ - - - IP_addresses + IP_addresses @@ -455,10 +453,23 @@ attack_vm + + + + {"username":"root","password":"toor","super_user":"","strings_to_leak":[],"leaked_filenames":[]} + + + true + + + IP_addresses + + + - IP_addresses + IP_addresses diff --git a/scenarios/examples/vulnerability_examples/access_control_misconfiguration_examples/uid_bash_root.xml b/scenarios/examples/vulnerability_examples/access_control_misconfiguration_examples/uid_bash_root.xml index 64357f8b5..03642ae78 100644 --- a/scenarios/examples/vulnerability_examples/access_control_misconfiguration_examples/uid_bash_root.xml +++ b/scenarios/examples/vulnerability_examples/access_control_misconfiguration_examples/uid_bash_root.xml @@ -6,10 +6,10 @@ - access_control_misconfigurations_uid_bash_root + access_control_misconfigurations_suid_root_bash - + diff --git a/scenarios/examples/vulnerability_examples/access_control_misconfiguration_examples/uid_less_root.xml b/scenarios/examples/vulnerability_examples/access_control_misconfiguration_examples/uid_less_root.xml index d9e6035d2..fecb5378c 100644 --- a/scenarios/examples/vulnerability_examples/access_control_misconfiguration_examples/uid_less_root.xml +++ b/scenarios/examples/vulnerability_examples/access_control_misconfiguration_examples/uid_less_root.xml @@ -9,7 +9,7 @@ access_control_misconfigurations_uid_less_root - + diff --git a/scenarios/examples/vulnerability_examples/access_control_misconfiguration_examples/uid_vi_root.xml b/scenarios/examples/vulnerability_examples/access_control_misconfiguration_examples/uid_vi_root.xml index e0b8030d0..672491336 100644 --- a/scenarios/examples/vulnerability_examples/access_control_misconfiguration_examples/uid_vi_root.xml +++ b/scenarios/examples/vulnerability_examples/access_control_misconfiguration_examples/uid_vi_root.xml @@ -9,7 +9,7 @@ access_control_misconfigurations_vi_root - + diff --git a/scenarios/examples/vulnerability_examples/access_control_misconfigurations_uid_vi_root.xml b/scenarios/examples/vulnerability_examples/access_control_misconfigurations_uid_vi_root.xml index 19bb7eadb..d0056cffa 100644 --- a/scenarios/examples/vulnerability_examples/access_control_misconfigurations_uid_vi_root.xml +++ b/scenarios/examples/vulnerability_examples/access_control_misconfigurations_uid_vi_root.xml @@ -9,7 +9,7 @@ access_control_misconfigurations_vi_root - + diff --git a/scenarios/examples/vulnerability_examples/dirtycow.xml b/scenarios/examples/vulnerability_examples/dirtycow.xml new file mode 100644 index 000000000..aba9df04f --- /dev/null +++ b/scenarios/examples/vulnerability_examples/dirtycow.xml @@ -0,0 +1,24 @@ + + + + + + dirtycow + + + + + + + 172.16.0.12 + + + + + IP_addresses + + + + diff --git a/scenarios/tests/test_scenario.xml b/scenarios/tests/test_scenario.xml index 3c84e680c..c68efee2c 100644 --- a/scenarios/tests/test_scenario.xml +++ b/scenarios/tests/test_scenario.xml @@ -4,11 +4,14 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.github/cliffe/SecGen/scenario"> - empty_stretch - + testing + + + + - 172.16.0.5 + 172.16.0.14 diff --git a/scenarios/tests/test_scenario_apt_upgrade.xml b/scenarios/tests/test_scenario_apt_upgrade.xml new file mode 100644 index 000000000..208a0436e --- /dev/null +++ b/scenarios/tests/test_scenario_apt_upgrade.xml @@ -0,0 +1,34 @@ + + + + + Basic Narrative + Thomas Shaw + Single system narrative-based CTF challenge. + + + ctf + attack-ctf + web-hints + intermediate + + + target_server + + + + 172.12.0.2 + + + + + + + IP_addresses + + + + + diff --git a/secgen.rb b/secgen.rb index 817dfac89..72996719b 100644 --- a/secgen.rb +++ b/secgen.rb @@ -1,6 +1,7 @@ require 'getoptlong' require 'fileutils' require 'nori' +require 'open3' require_relative 'lib/helpers/constants.rb' require_relative 'lib/helpers/print.rb' @@ -30,6 +31,7 @@ def usage --help, -h: Shows this usage information --system, -y [system_name]: Only build this system_name from the scenario --snapshot: Creates a snapshot of VMs once built + --no-tests: Prevent post-provisioning tests from running. VIRTUALBOX OPTIONS: --gui-output, -g: Show the running VM (not headless) @@ -77,7 +79,7 @@ def build_config(scenario, out_dir, options) Print.info 'Resolving systems: randomising scenario...' # update systems with module selections - systems.map! { |system| + systems.map! {|system| system.module_selections = system.resolve_module_selection(all_available_modules, options) system } @@ -115,9 +117,9 @@ def build_vms(scenario, project_dir, options) retry_count = OVirtFunctions::provider_ovirt?(options) ? 2 : 0 successful_creation = false - while retry_count and !successful_creation + while retry_count >= 0 and !successful_creation vagrant_output = GemExec.exe('vagrant', project_dir, "#{command} #{system}") - if vagrant_output[:status] == 0 + if vagrant_output[:status] == 0 and post_provision_tests(project_dir, options) Print.info 'VMs created.' successful_creation = true if options[:shutdown] or OVirtFunctions::provider_ovirt?(options) @@ -141,9 +143,9 @@ def build_vms(scenario, project_dir, options) elsif match = line.match(/^([-a-zA-Z_0-9]+):[^:]+VM is not created/i) vm_not_to_destroy = match.captures[0] Print.err "Not going to destroy #{vm_not_to_destroy}, since it does not exist" - failures_to_destroy.delete_if {|x| x == vm_not_to_destroy } + failures_to_destroy.delete_if {|x| x == vm_not_to_destroy} # TODO: not sure if there is a need to remove_uncreated_vms() here too? (I don't think so?) - end + end # TODO: Add another elsif here to check if any tests have failed, edit the output of the tests so that it has a unique string that captures the vm name end failures_to_destroy = failures_to_destroy.uniq @@ -168,7 +170,7 @@ def build_vms(scenario, project_dir, options) end sleep(10) end - else # TODO: elsif vagrant_output[:exception].type == ProcessHelper::TimeoutError >destroy individually broken vms as above? + else # TODO: elsif vagrant_output[:exception].type == ProcessHelper::TimeoutError >destroy individually broken vms as above? Print.err 'Vagrant up timeout, destroying VMs and retrying...' GemExec.exe('vagrant', project_dir, 'destroy -f') end @@ -258,14 +260,14 @@ def make_forensic_image(project_dir, image_output_location, image_type) system "cd '#{project_dir}' && vagrant halt" case image_type.downcase - when 'raw', 'dd' - create_dd_image(drive_path, image_output_location) + when 'raw', 'dd' + create_dd_image(drive_path, image_output_location) - when 'ewf', 'e01' - create_ewf_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." + else + Print.info "The image type [#{image_type}] is not recognised." end end @@ -287,14 +289,14 @@ 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| + 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| + Dir["#{PROJECTS_DIR}/*"].select {|file| !File.file? file}.each_with_index do |scenario_name, scenario_number| Print.std "#{scenario_number}) #{scenario_name}" end end @@ -329,13 +331,48 @@ def get_vm_names(scenario) vm_names end +def reboot_cycle(project_dir) + Print.info 'Shutting down VMs.' + sleep(30) + GemExec.exe('vagrant', project_dir, 'halt') + sleep 5 + GemExec.exe('vagrant', project_dir, 'up --no-provision') + sleep 45 +end + +def post_provision_tests(project_dir, options) + tests_passed = true + unless options[:notests] + reboot_cycle(project_dir) + Print.info 'Running post-provision tests...' + + test_module_outputs = [] + test_script_paths = Dir.glob("#{project_dir}/puppet/*/modules/*/secgen_test/*.rb") + test_script_paths.each do |test_file_path| + test_stdout, test_stderr, test_status = Open3.capture3("bundle exec ruby #{test_file_path}") + test_module_outputs << {:stdout => test_stdout.split("\n"), :stderr => test_stderr, :exit_status => test_status} + end + test_module_outputs.each do |test_output| + if test_output[:exit_status].exitstatus != 0 + tests_passed = false + Print.err test_output[:stdout].join("\n") + Print.err "Post provision tests contained failures!" + Print.err test_output[:stderr] + else + Print.info test_output[:stdout].join("\n") + end + end + end + tests_passed +end + # end of method declarations # start of program execution -Print.std '~'*47 +Print.std '~' * 47 Print.std 'SecGen - Creates virtualised security scenarios' Print.std ' Licensed GPLv3 2014-18' -Print.std '~'*47 +Print.std '~' * 47 # Add read-options from config file (needs handling before options parsed by GetoptLong) if ARGV.include? '--read-options' @@ -377,6 +414,7 @@ opts = GetoptLong.new( ['--ovirt-network', GetoptLong::REQUIRED_ARGUMENT], ['--ovirt-affinity-group', GetoptLong::REQUIRED_ARGUMENT], ['--snapshot', GetoptLong::NO_ARGUMENT], + ['--no-tests', GetoptLong::NO_ARGUMENT], ) scenario = SCENARIO_XML @@ -387,94 +425,97 @@ options = {} opts.each do |opt, arg| case opt # Main options - when '--help' - usage - when '--scenario' - scenario = arg; - when '--project' - project_dir = arg; - when '--prefix' - options[:prefix] = arg - project_dir = project_dir(arg) + when '--help' + usage + when '--scenario' + scenario = arg; + when '--project' + project_dir = arg; + when '--prefix' + options[:prefix] = arg + project_dir = project_dir(arg) # Additional options - when '--system' - Print.info "VM control (Vagrant) commands will only apply to system #{arg} (must match a system defined in the scenario)" - options[:system] = arg - when '--reload' - Print.info "Will reload and re-provision the VMs" - options[:reload] = true - 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 '--cpu-cores' - Print.info "Number of cpus to be used set to #{arg}" - options[:cpu_cores] = arg - when '--max-cpu-usage' - Print.info "Max CPU usage set to #{arg}" - options[:max_cpu_usage] = arg - when '--shutdown' - Print.info 'Shutdown VMs after provisioning' - options[:shutdown] = true - when '--network-ranges' - Print.info 'Overriding Network Ranges' - options[:ip_ranges] = arg.split(',') - when '--forensic-image-type' - Print.info "Image output type set to #{arg}" - options[:forensic_image_type] = arg - - when '--ovirtuser' - Print.info "Ovirt Username : #{arg}" - options[:ovirtuser] = arg - when '--ovirtpass' - Print.info "Ovirt Password : ********" - options[:ovirtpass] = arg - when '--ovirt-url' - Print.info "Ovirt API url : #{arg}" - options[:ovirturl] = arg - when '--ovirtauthz' - Print.info "Ovirt Authz: #{arg}" - options[:ovirtauthz] = arg - when '--ovirt-cluster' - Print.info "Ovirt Cluster : #{arg}" - options[:ovirtcluster] = arg - when '--ovirt-network' - Print.info "Ovirt Network Name : #{arg}" - options[:ovirtnetwork] = arg - when '--ovirt-affinity-group' - Print.info "Ovirt Affinity Group : #{arg}" - options[:ovirtaffinitygroup] = arg - when '--snapshot' - Print.info "Taking snapshots when VMs are created" - options[:snapshot] = true - + when '--system' + Print.info "VM control (Vagrant) commands will only apply to system #{arg} (must match a system defined in the scenario)" + options[:system] = arg + when '--reload' + Print.info "Will reload and re-provision the VMs" + options[:reload] = true + 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.err "Argument not valid: #{arg}" - usage - exit 1 + 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 '--cpu-cores' + Print.info "Number of cpus to be used set to #{arg}" + options[:cpu_cores] = arg + when '--max-cpu-usage' + Print.info "Max CPU usage set to #{arg}" + options[:max_cpu_usage] = arg + when '--shutdown' + Print.info 'Shutdown VMs after provisioning' + options[:shutdown] = true + when '--network-ranges' + Print.info 'Overriding Network Ranges' + options[:ip_ranges] = arg.split(',') + when '--forensic-image-type' + Print.info "Image output type set to #{arg}" + options[:forensic_image_type] = arg + when '--no-tests' + Print.info "Not running post-provision tests" + options[:notests] = true + + when '--ovirtuser' + Print.info "Ovirt Username : #{arg}" + options[:ovirtuser] = arg + when '--ovirtpass' + Print.info "Ovirt Password : ********" + options[:ovirtpass] = arg + when '--ovirt-url' + Print.info "Ovirt API url : #{arg}" + options[:ovirturl] = arg + when '--ovirtauthz' + Print.info "Ovirt Authz: #{arg}" + options[:ovirtauthz] = arg + when '--ovirt-cluster' + Print.info "Ovirt Cluster : #{arg}" + options[:ovirtcluster] = arg + when '--ovirt-network' + Print.info "Ovirt Network Name : #{arg}" + options[:ovirtnetwork] = arg + when '--ovirt-affinity-group' + Print.info "Ovirt Affinity Group : #{arg}" + options[:ovirtaffinitygroup] = arg + when '--snapshot' + Print.info "Taking snapshots when VMs are created" + options[:snapshot] = true + + else + Print.err "Argument not valid: #{arg}" + usage + exit 1 end end @@ -487,53 +528,53 @@ 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(scenario, project_dir, options) - else - Print.err 'Please specify project directory to read' - usage - exit 1 - end - - when 'create-forensic-image' - image_type = options.has_key?(:forensic_image_type) ? options[:forensic_image_type] : 'raw'; - - if project_dir - build_vms(scenario, project_dir, options) - 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(scenario, project_dir, options) - make_forensic_image(project_dir, nil, image_type) - end - - when 'ovirt-post-build' - ovirt_post_build(options, scenario, project_dir) - exit 0 - - 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 - +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(scenario, project_dir, options) else - Print.err "Command not valid: #{ARGV[0]}" + Print.err 'Please specify project directory to read' usage exit 1 + end + +when 'create-forensic-image' + image_type = options.has_key?(:forensic_image_type) ? options[:forensic_image_type] : 'raw'; + + if project_dir + build_vms(scenario, project_dir, options) + 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(scenario, project_dir, options) + make_forensic_image(project_dir, nil, image_type) + end + +when 'ovirt-post-build' + ovirt_post_build(options, scenario, project_dir) + exit 0 + +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 1 end