mirror of
https://github.com/cliffe/SecGen.git
synced 2026-02-21 11:18:06 +00:00
Merge branch 'post_tests' into s2progress
# Conflicts: # modules/generators/structured_content/hackerbot_config/hbauthentication/secgen_metadata.xml # modules/generators/structured_content/hackerbot_config/hbauthentication/templates/intro.md.erb # modules/generators/structured_content/hackerbot_config/hbauthentication/templates/lab.xml.erb # modules/vulnerabilities/unix/access_control_misconfigurations/suid_root_bash/suid_root_bash.pp # modules/vulnerabilities/unix/access_control_misconfigurations/suid_root_vi/suid_root_vi.pp # modules/vulnerabilities/unix/web_training/dvwa/files/DVWA-master/vulnerabilities/csp/help/help.php # modules/vulnerabilities/unix/web_training/dvwa/manifests/apache.pp # scenarios/ctf/basic_narrative.xml # scenarios/labs/websec_lab_env.xml # scenarios/security_audit/team_project.xml
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -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
|
||||
modules/encoders/compression/huffman/tmp
|
||||
.rakeTasks
|
||||
modules/**/Gemfile.lock
|
||||
|
||||
2
Gemfile
2
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
|
||||
|
||||
44
Gemfile.lock
44
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
|
||||
|
||||
@@ -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')
|
||||
|
||||
170
lib/objects/post_provision_test.rb
Normal file
170
lib/objects/post_provision_test.rb
Normal file
@@ -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 = '<redacted>' 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
|
||||
@@ -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}"
|
||||
|
||||
|
||||
@@ -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"%>"
|
||||
|
||||
@@ -20,4 +20,5 @@
|
||||
|
||||
<reference>https://atlas.hashicorp.com/puppetlabs</reference>
|
||||
<software_license>various</software_license>
|
||||
|
||||
</base>
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<base xmlns="http://www.github/cliffe/SecGen/base"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.github/cliffe/SecGen/base">
|
||||
<name>Ubuntu Xenial 16.04 LTS 64-bit Server by puppetlabs</name>
|
||||
<author>Thomas Shaw</author>
|
||||
<module_license>GPLv3</module_license>
|
||||
<description>TODO </description>
|
||||
<cpu_word_size>64-bit</cpu_word_size>
|
||||
<type>server</type>
|
||||
<type>cli</type>
|
||||
|
||||
<platform>linux</platform>
|
||||
<platform>unix</platform>
|
||||
<distro>Ubuntu Xenial 16.04 LTS</distro>
|
||||
<url>https://app.vagrantup.com/puppetlabs/boxes/ubuntu-16.04-64-puppet/versions/1.0.0/providers/virtualbox.box</url>
|
||||
<ovirt_template>debian_server</ovirt_template>
|
||||
|
||||
<reference>https://atlas.hashicorp.com/puppetlabs</reference>
|
||||
<software_license>various</software_license>
|
||||
</base>
|
||||
@@ -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
|
||||
@@ -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
|
||||
17
modules/services/unix/email/popa3d/secgen_test/popa3d.rb
Normal file
17
modules/services/unix/email/popa3d/secgen_test/popa3d.rb
Normal file
@@ -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
|
||||
16
modules/services/unix/ftp/proftpd/secgen_test/proftpd.rb
Normal file
16
modules/services/unix/ftp/proftpd/secgen_test/proftpd.rb
Normal file
@@ -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
|
||||
16
modules/services/unix/ftp/vsftpd/secgen_test/vsftpd.rb
Normal file
16
modules/services/unix/ftp/vsftpd/secgen_test/vsftpd.rb
Normal file
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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'})
|
||||
}
|
||||
@@ -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
|
||||
17
modules/services/unix/irc/irc2/secgen_test/irc2.rb
Normal file
17
modules/services/unix/irc/irc2/secgen_test/irc2.rb
Normal file
@@ -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
|
||||
@@ -32,10 +32,6 @@
|
||||
<name>Kali.*</name>
|
||||
</conflict>
|
||||
|
||||
<conflict>
|
||||
<name>.*Stretch.*</name>
|
||||
</conflict>
|
||||
|
||||
<requires>
|
||||
<type>update</type>
|
||||
</requires>
|
||||
|
||||
16
modules/services/unix/irc/unrealirc/secgen_test/unrealirc.rb
Normal file
16
modules/services/unix/irc/unrealirc/secgen_test/unrealirc.rb
Normal file
@@ -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
|
||||
17
modules/services/unix/nfs/nfs_share/secgen_test/nfs_share.rb
Normal file
17
modules/services/unix/nfs/nfs_share/secgen_test/nfs_share.rb
Normal file
@@ -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
|
||||
39
modules/services/unix/ntp/ntp/secgen_test/ntp.rb
Normal file
39
modules/services/unix/ntp/ntp/secgen_test/ntp.rb
Normal file
@@ -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
|
||||
17
modules/services/unix/smb/samba/secgen_test/samba.rb
Normal file
17
modules/services/unix/smb/samba/secgen_test/samba.rb
Normal file
@@ -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
|
||||
@@ -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<65>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 <20>-y<> after each install means that the user doesn<73>t need to press <20>y<EFBFBD> in between each package download. The install script is based on this page: https://docs.docker.com/engine/installation/linux/docker-ce/debian/
|
||||
12
modules/utilities/unix/labtainers/manifests/config.pp
Normal file
12
modules/utilities/unix/labtainers/manifests/config.pp
Normal file
@@ -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,
|
||||
}
|
||||
|
||||
}
|
||||
27
modules/utilities/unix/labtainers/manifests/install.pp
Normal file
27
modules/utilities/unix/labtainers/manifests/install.pp
Normal file
@@ -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,
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
class readable_shadow::config {
|
||||
file { '/etc/shadow':
|
||||
ensure => present,
|
||||
mode => '0622',
|
||||
mode => '0644',
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<name>Readable Shadow File</name>
|
||||
<author>Thomas Shaw</author>
|
||||
<module_license>MIT</module_license>
|
||||
<description>Changes permissions on shadow file to 0622, reveals password hashes to local users.
|
||||
<description>Changes permissions on shadow file to 0611, reveals password hashes to local users.
|
||||
This is not a common misconfiguration, and not particularly subtle.</description>
|
||||
|
||||
<type>access_control_misconfiguration</type>
|
||||
|
||||
@@ -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
|
||||
@@ -1,4 +1,4 @@
|
||||
class uid_bash_root::config {
|
||||
class suid_root_bash::config {
|
||||
file { '/bin/bash':
|
||||
ensure => present,
|
||||
mode => '4777',
|
||||
|
||||
@@ -15,4 +15,8 @@
|
||||
|
||||
<hint>Shell permission misconfiguration</hint>
|
||||
<solution>Bash shell running with root permissions due to suid bit set (try /bin/bash -cp "some_command")</solution>
|
||||
|
||||
<conflict>
|
||||
<module_path>.*shellshock.*</module_path>
|
||||
</conflict>
|
||||
</vulnerability>
|
||||
@@ -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
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
@@ -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',
|
||||
|
||||
@@ -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
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
@@ -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',
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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'],
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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'],
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
include python2_challenge_example::install
|
||||
@@ -1,63 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<vulnerability xmlns="http://www.github/cliffe/SecGen/vulnerability"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.github/cliffe/SecGen/vulnerability">
|
||||
<name>python2 Challenge Example</name>
|
||||
<author>Thomas Shaw</author>
|
||||
<module_license>MIT</module_license>
|
||||
<description>python2 challenge example</description>
|
||||
|
||||
<type>script_challenge</type>
|
||||
<privilege>none</privilege>
|
||||
<access>local</access>
|
||||
<platform>linux</platform>
|
||||
|
||||
<challenge_type>misc</challenge_type>
|
||||
<challenge_subtype>example</challenge_subtype>
|
||||
|
||||
<!-- script dropped in account's home directory by default with setuid configuration. -->
|
||||
<read_fact>challenge_name</read_fact>
|
||||
<read_fact>script_data</read_fact>
|
||||
<read_fact>account</read_fact>
|
||||
<read_fact>flag</read_fact>
|
||||
<!-- storage_directory: Blank by default. If supplied, store the files here. e.g. NFS or SMB storage location -->
|
||||
<read_fact>storage_directory</read_fact>
|
||||
<!-- group: Blank by default. If supplied install script challenge as setgid -->
|
||||
<read_fact>group</read_fact>
|
||||
<default_input into="challenge_name">
|
||||
<value>python2_script_example</value>
|
||||
</default_input>
|
||||
<default_input into="script_data">
|
||||
<generator module_path=".*python_example"/>
|
||||
</default_input>
|
||||
<default_input into="account">
|
||||
<generator type="account">
|
||||
<input into="username">
|
||||
<value>challenges</value>
|
||||
</input>
|
||||
<input into="password">
|
||||
<value>password</value>
|
||||
</input>
|
||||
</generator>
|
||||
</default_input>
|
||||
<default_input into="flag">
|
||||
<generator type="flag_generator"/>
|
||||
</default_input>
|
||||
<default_input into="challenge_name">
|
||||
<value>python2_script_example</value>
|
||||
</default_input>
|
||||
|
||||
<requires>
|
||||
<module_path>utilities/unix/system/accounts</module_path>
|
||||
</requires>
|
||||
|
||||
<requires>
|
||||
<module_path>utilities/unix/system/binary_script_container</module_path>
|
||||
</requires>
|
||||
|
||||
<requires>
|
||||
<module_path>utilities/unix/languages/python2/python</module_path>
|
||||
</requires>
|
||||
|
||||
</vulnerability>
|
||||
@@ -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'],
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
include ruby_challenge_example::install
|
||||
@@ -1,67 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<vulnerability xmlns="http://www.github/cliffe/SecGen/vulnerability"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.github/cliffe/SecGen/vulnerability">
|
||||
<name>Ruby Challenge Example</name>
|
||||
<author>Thomas Shaw</author>
|
||||
<module_license>MIT</module_license>
|
||||
<description>Ruby challenge example</description>
|
||||
|
||||
<type>ctf_challenge</type>
|
||||
<privilege>none</privilege>
|
||||
<access>local</access>
|
||||
<platform>linux</platform>
|
||||
|
||||
<challenge_type>misc</challenge_type>
|
||||
<challenge_subtype>example</challenge_subtype>
|
||||
|
||||
<!-- script dropped in account's home directory by default with setuid configuration. -->
|
||||
<read_fact>challenge_name</read_fact>
|
||||
<read_fact>script_data</read_fact>
|
||||
<read_fact>account</read_fact>
|
||||
<read_fact>flag</read_fact>
|
||||
<!-- group: Blank by default. Uses challenge name as group name unless explicitly provided. -->
|
||||
<read_fact>group</read_fact>
|
||||
<!-- storage_directory: Blank by default. If supplied, store the files here. e.g. NFS or SMB storage location -->
|
||||
<read_fact>storage_directory</read_fact>
|
||||
<!-- port: Blank by default. If supplied install script challenge as xinetd program running on given port -->
|
||||
<read_fact>port</read_fact>
|
||||
|
||||
<default_input into="challenge_name">
|
||||
<value>ruby_challenge_example</value>
|
||||
</default_input>
|
||||
<default_input into="script_data">
|
||||
<generator module_path=".*ruby_example"/>
|
||||
</default_input>
|
||||
<default_input into="account">
|
||||
<generator type="account">
|
||||
<input into="username">
|
||||
<value>challenges</value>
|
||||
</input>
|
||||
<input into="password">
|
||||
<value>password</value>
|
||||
</input>
|
||||
</generator>
|
||||
</default_input>
|
||||
<default_input into="flag">
|
||||
<generator type="flag_generator"/>
|
||||
</default_input>
|
||||
|
||||
<requires>
|
||||
<module_path>utilities/unix/system/accounts</module_path>
|
||||
</requires>
|
||||
|
||||
<requires>
|
||||
<module_path>utilities/unix/system/binary_script_container</module_path>
|
||||
</requires>
|
||||
|
||||
<requires>
|
||||
<module_path>utilities/unix/languages/ruby</module_path>
|
||||
</requires>
|
||||
|
||||
<requires>
|
||||
<module_path>utilities/unix/system/xinetd</module_path>
|
||||
</requires>
|
||||
|
||||
</vulnerability>
|
||||
@@ -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'
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -84,9 +84,9 @@
|
||||
<software_name>unrealircd</software_name>
|
||||
<software_license>MIT</software_license>
|
||||
|
||||
<conflict>
|
||||
<name>.*Stretch.*</name>
|
||||
</conflict>
|
||||
<!--<conflict>-->
|
||||
<!--<name>.*Stretch.*</name>-->
|
||||
<!--</conflict>-->
|
||||
<conflict>
|
||||
<name>.*Kali.*</name>
|
||||
</conflict>
|
||||
|
||||
@@ -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
|
||||
@@ -40,5 +40,6 @@ class chkrootkit::install {
|
||||
leaked_filenames => $leaked_filenames,
|
||||
strings_to_leak => $strings_to_leak,
|
||||
leaked_from => "chkrootkit_vuln",
|
||||
mode => '0600'
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
1
modules/vulnerabilities/unix/local/dirtycow/dirtycow.pp
Normal file
1
modules/vulnerabilities/unix/local/dirtycow/dirtycow.pp
Normal file
@@ -0,0 +1 @@
|
||||
include dirtycow::config
|
||||
@@ -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.")
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<vulnerability xmlns="http://www.github/cliffe/SecGen/vulnerability"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.github/cliffe/SecGen/vulnerability">
|
||||
<name>DirtyCow privilege escalation</name>
|
||||
<author>Thomas Shaw</author>
|
||||
<module_license>MIT</module_license>
|
||||
<description>DirtyCow local privilege escalation. Including this module prevents the default apt-get upgrade from
|
||||
running which leaves the wheezy bases vulnerable.
|
||||
</description>
|
||||
|
||||
<type>unpatched_kernel</type>
|
||||
<type>race_condition</type>
|
||||
<privilege>root_rwx</privilege>
|
||||
<access>local</access>
|
||||
<platform>linux</platform>
|
||||
<difficulty>medium</difficulty>
|
||||
|
||||
<conflict>
|
||||
<name>.*Stretch.*</name>
|
||||
</conflict>
|
||||
<conflict>
|
||||
<name>.*Kali.*</name>
|
||||
</conflict>
|
||||
<conflict>
|
||||
<name>.*Windows.*</name>
|
||||
</conflict>
|
||||
<conflict>
|
||||
<name>.*Ubuntu.*</name>
|
||||
</conflict>
|
||||
|
||||
</vulnerability>
|
||||
@@ -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
|
||||
@@ -14,5 +14,6 @@ class setuid_nmap::init {
|
||||
leaked_filenames => $leaked_filenames,
|
||||
strings_to_leak => $strings_to_leak,
|
||||
leaked_from => "setuid_nmap",
|
||||
mode => '0600'
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -1,52 +1,52 @@
|
||||
<div class="body_padded">
|
||||
<h1>Help - Content Security Policy (CSP) Bypass</h1>
|
||||
|
||||
<div id="code">
|
||||
<table width='100%' bgcolor='white' style="border:2px #C0C0C0 solid">
|
||||
<tr>
|
||||
<td><div id="code">
|
||||
<h3>About</h3>
|
||||
<p>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.</p>
|
||||
<p>None of the vulnerabilities are actual vulnerabilities in CSP, they are vulnerabilities in the way it has been implemented.</p>
|
||||
|
||||
<br /><hr /><br />
|
||||
|
||||
<h3>Objective</h3>
|
||||
<p>Bypass Content Security Policy (CSP) and execute JavaScript in the page.</p>
|
||||
|
||||
<br /><hr /><br />
|
||||
|
||||
<h3>Low Level</h3>
|
||||
<p>Examine the policy to find all the sources that can be used to host external script files.</p>
|
||||
<pre>Spoiler: <span class="spoiler">Scripts can be included from Pastebin, try storing some JavaScript on there and then loading it in.</span></pre>
|
||||
|
||||
<br />
|
||||
|
||||
<h3>Medium Level</h3>
|
||||
<p>The CSP policy tries to use a nonce to prevent inline scripts from being added by attackers.</p>
|
||||
<pre>Spoiler: <span class="spoiler">Examine the nonce and see how it varies (or doesn't).</span></pre>
|
||||
|
||||
<br />
|
||||
|
||||
<h3>High Level</h3>
|
||||
<p>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.</p>
|
||||
<pre>Spoiler: <span class="spoiler">The JavaScript on the page will execute whatever is returned by the page, changing this to your own code will execute that instead</span></pre>
|
||||
|
||||
<br />
|
||||
|
||||
<h3>Impossible Level</h3>
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
</div></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
<p>Reference: <?php echo dvwaExternalLinkUrlGet( 'https://content-security-policy.com/', "Content Security Policy Reference" ); ?></p>
|
||||
<p>Reference: <?php echo dvwaExternalLinkUrlGet( 'https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP', "Mozilla Developer Network - CSP: script-src"); ?></p>
|
||||
<p>Reference: <?php echo dvwaExternalLinkUrlGet( 'https://blog.mozilla.org/security/2014/10/04/csp-for-the-web-we-have/', "Mozilla Security Blog - CSP for the web we have" ); ?></p>
|
||||
</div>
|
||||
<div class="body_padded">
|
||||
<h1>Help - Content Security Policy (CSP) Bypass</h1>
|
||||
|
||||
<div id="code">
|
||||
<table width='100%' bgcolor='white' style="border:2px #C0C0C0 solid">
|
||||
<tr>
|
||||
<td><div id="code">
|
||||
<h3>About</h3>
|
||||
<p>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.</p>
|
||||
<p>None of the vulnerabilities are actual vulnerabilities in CSP, they are vulnerabilities in the way it has been implemented.</p>
|
||||
|
||||
<br /><hr /><br />
|
||||
|
||||
<h3>Objective</h3>
|
||||
<p>Bypass Content Security Policy (CSP) and execute JavaScript in the page.</p>
|
||||
|
||||
<br /><hr /><br />
|
||||
|
||||
<h3>Low Level</h3>
|
||||
<p>Examine the policy to find all the sources that can be used to host external script files.</p>
|
||||
<pre>Spoiler: <span class="spoiler">Scripts can be included from Pastebin, try storing some JavaScript on there and then loading it in.</span></pre>
|
||||
|
||||
<br />
|
||||
|
||||
<h3>Medium Level</h3>
|
||||
<p>The CSP policy tries to use a nonce to prevent inline scripts from being added by attackers.</p>
|
||||
<pre>Spoiler: <span class="spoiler">Examine the nonce and see how it varies (or doesn't).</span></pre>
|
||||
|
||||
<br />
|
||||
|
||||
<h3>High Level</h3>
|
||||
<p>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.</p>
|
||||
<pre>Spoiler: <span class="spoiler">The JavaScript on the page will execute whatever is returned by the page, changing this to your own code will execute that instead</span></pre>
|
||||
|
||||
<br />
|
||||
|
||||
<h3>Impossible Level</h3>
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
</div></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
<p>Reference: <?php echo dvwaExternalLinkUrlGet( 'https://content-security-policy.com/', "Content Security Policy Reference" ); ?></p>
|
||||
<p>Reference: <?php echo dvwaExternalLinkUrlGet( 'https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP', "Mozilla Developer Network - CSP: script-src"); ?></p>
|
||||
<p>Reference: <?php echo dvwaExternalLinkUrlGet( 'https://blog.mozilla.org/security/2014/10/04/csp-for-the-web-we-have/', "Mozilla Security Blog - CSP for the web we have" ); ?></p>
|
||||
</div>
|
||||
|
||||
@@ -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
|
||||
@@ -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('/', '<title>GitList</title>')
|
||||
end
|
||||
end
|
||||
|
||||
Gitlist040Test.new.run
|
||||
@@ -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','<script type="text/javascript" src="/moin_static195/common/js/common.js"></script>')
|
||||
end
|
||||
end
|
||||
|
||||
MoinMoin195Test.new.run
|
||||
@@ -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':
|
||||
|
||||
@@ -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', '<title>Welcome to furniture!</title>')
|
||||
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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
<system>
|
||||
<system_name>target_server</system_name>
|
||||
<base distro="Debian 7.8" platform="linux" type="server"/>
|
||||
<base distro="Debian 9" platform="linux" type="server"/>
|
||||
|
||||
<input into_datastore="IP_addresses">
|
||||
<value>172.10.0.2</value>
|
||||
@@ -437,11 +437,9 @@
|
||||
</input>
|
||||
</vulnerability>
|
||||
|
||||
<utility module_path=".*sqlmap.*"/>
|
||||
|
||||
<network type="private_network">
|
||||
<input into="IP_address">
|
||||
<datastore access="next">IP_addresses</datastore>
|
||||
<datastore access="0">IP_addresses</datastore>
|
||||
</input>
|
||||
</network>
|
||||
|
||||
@@ -455,10 +453,23 @@
|
||||
<system>
|
||||
<system_name>attack_vm</system_name>
|
||||
<base distro="Kali" name="MSF"/>
|
||||
|
||||
<utility module_path=".*iceweasel">
|
||||
<input into="accounts">
|
||||
<value>{"username":"root","password":"toor","super_user":"","strings_to_leak":[],"leaked_filenames":[]}</value>
|
||||
</input>
|
||||
<input into="autostart">
|
||||
<value>true</value>
|
||||
</input>
|
||||
<input into="start_page">
|
||||
<datastore access="0">IP_addresses</datastore>
|
||||
</input>
|
||||
</utility>
|
||||
|
||||
<utility module_path=".*kali_top10"/>
|
||||
<network type="private_network">
|
||||
<input into="IP_address">
|
||||
<datastore access="next">IP_addresses</datastore>
|
||||
<datastore access="1">IP_addresses</datastore>
|
||||
</input>
|
||||
</network>
|
||||
</system>
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
|
||||
<!-- An example access control misconfiguration, setuid on /bin/bash allows programs to run with root privileges -->
|
||||
<system>
|
||||
<system_name>access_control_misconfigurations_uid_bash_root</system_name>
|
||||
<system_name>access_control_misconfigurations_suid_root_bash</system_name>
|
||||
<base platform="linux" type="server"/>
|
||||
|
||||
<vulnerability module_path="vulnerabilities/unix/access_control_misconfigurations/uid_bash_root"/>
|
||||
<vulnerability module_path="vulnerabilities/unix/access_control_misconfigurations/suid_root_bash"/>
|
||||
|
||||
<utility module_path=".*parameterised_accounts">
|
||||
<input into="accounts">
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<system_name>access_control_misconfigurations_uid_less_root</system_name>
|
||||
<base platform="linux" type="server"/>
|
||||
|
||||
<vulnerability module_path="modules/vulnerabilities/unix/access_control_misconfigurations/uid_less_root"/>
|
||||
<vulnerability module_path="modules/vulnerabilities/unix/access_control_misconfigurations/suid_root_less"/>
|
||||
|
||||
<utility module_path=".*parameterised_accounts">
|
||||
<input into="accounts">
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<system_name>access_control_misconfigurations_vi_root</system_name>
|
||||
<base platform="linux" type="server"/>
|
||||
|
||||
<vulnerability module_path="vulnerabilities/unix/access_control_misconfigurations/uid_vi_root"/>
|
||||
<vulnerability module_path="vulnerabilities/unix/access_control_misconfigurations/suid_root_vi"/>
|
||||
|
||||
<utility module_path=".*parameterised_accounts">
|
||||
<input into="accounts">
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<system_name>access_control_misconfigurations_vi_root</system_name>
|
||||
<base platform="linux" type="server"/>
|
||||
|
||||
<vulnerability module_path="vulnerabilities/unix/access_control_misconfigurations/uid_vi_root"/>
|
||||
<vulnerability module_path="vulnerabilities/unix/access_control_misconfigurations/suid_root_vi"/>
|
||||
|
||||
<network type="private_network" range="dhcp"/>
|
||||
</system>
|
||||
|
||||
24
scenarios/examples/vulnerability_examples/dirtycow.xml
Normal file
24
scenarios/examples/vulnerability_examples/dirtycow.xml
Normal file
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<scenario xmlns="http://www.github/cliffe/SecGen/scenario"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.github/cliffe/SecGen/scenario">
|
||||
|
||||
<system>
|
||||
<system_name>dirtycow</system_name>
|
||||
<base platform="linux" distro="Debian 7.8" />
|
||||
|
||||
<!-- DirtyCOW vulnerability module leaves the debian 7 bases unpatched by default. -->
|
||||
<vulnerability module_path=".*dirtycow.*"/>
|
||||
|
||||
<input into_datastore="IP_addresses">
|
||||
<value>172.16.0.12</value>
|
||||
</input>
|
||||
|
||||
<network type="private_network">
|
||||
<input into="IP_address">
|
||||
<datastore access="0">IP_addresses</datastore>
|
||||
</input>
|
||||
</network>
|
||||
</system>
|
||||
</scenario>
|
||||
@@ -4,11 +4,14 @@
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.github/cliffe/SecGen/scenario">
|
||||
<system>
|
||||
<system_name>empty_stretch</system_name>
|
||||
<base platform="linux" distro="Debian 9" type="server"/>
|
||||
<system_name>testing</system_name>
|
||||
<base platform="linux" distro="Debian 7.8" type="server"/>
|
||||
|
||||
<!--<vulnerability module_path=".*dirtycow.*"/>-->
|
||||
<vulnerability module_path=".*suid_root_bash.*"/>
|
||||
|
||||
<input into_datastore="IP_addresses">
|
||||
<value>172.16.0.5</value>
|
||||
<value>172.16.0.14</value>
|
||||
</input>
|
||||
|
||||
<network type="private_network">
|
||||
|
||||
34
scenarios/tests/test_scenario_apt_upgrade.xml
Normal file
34
scenarios/tests/test_scenario_apt_upgrade.xml
Normal file
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<scenario xmlns="http://www.github/cliffe/SecGen/scenario"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.github/cliffe/SecGen/scenario">
|
||||
|
||||
<name>Basic Narrative</name>
|
||||
<author>Thomas Shaw</author>
|
||||
<description>Single system narrative-based CTF challenge.
|
||||
</description>
|
||||
|
||||
<type>ctf</type>
|
||||
<type>attack-ctf</type>
|
||||
<type>web-hints</type>
|
||||
<difficulty>intermediate</difficulty>
|
||||
|
||||
<system>
|
||||
<system_name>target_server</system_name>
|
||||
<base distro="Debian 7.8" platform="linux" type="server"/>
|
||||
|
||||
<input into_datastore="IP_addresses">
|
||||
<value>172.12.0.2</value>
|
||||
</input>
|
||||
|
||||
<utility type="upgrade"/>
|
||||
|
||||
<network type="private_network">
|
||||
<input into="IP_address">
|
||||
<datastore access="0">IP_addresses</datastore>
|
||||
</input>
|
||||
</network>
|
||||
</system>
|
||||
|
||||
</scenario>
|
||||
335
secgen.rb
335
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
|
||||
|
||||
Reference in New Issue
Block a user