Merge pull request #20 from Jjk422/sprint_2_upload_finished

Sprint 2 upload finished
This commit is contained in:
Witcherdude
2016-05-04 15:14:29 +01:00
26 changed files with 660 additions and 194 deletions

View File

@@ -7,4 +7,6 @@ gem 'xml-simple'
group :test, :development do
gem 'minitest'
gem 'rake'
gem 'rdoc'
gem 'yard'
end

View File

@@ -1,12 +1,16 @@
GEM
remote: https://rubygems.org/
specs:
json (1.8.1)
mini_portile2 (2.0.0)
minitest (5.8.4)
nokogiri (1.6.7.2)
mini_portile2 (~> 2.0.0.rc2)
rake (10.5.0)
rdoc (4.2.2)
json (~> 1.4)
xml-simple (1.1.5)
yard (0.8.7.6)
PLATFORMS
ruby
@@ -15,4 +19,9 @@ DEPENDENCIES
minitest
nokogiri
rake
rdoc
xml-simple
yard
BUNDLED WITH
1.11.2

View File

@@ -0,0 +1,32 @@
task :default => ["yard"]
desc "Generate_yard_documentation"
task :yard do
require 'yard'
require_relative '../../lib/constants.rb'
YARD::Rake::YardocTask.new do |t|
# Files to include in yard documentation. Ruby files before the -, Other files after the dash
t.files = ["#{ROOT_DIR}/lib/**/*.rb",
"#{ROOT_DIR}/tests/**/*.rb"
# '-',
# "#{ROOT_DIR}
] # optional
t.options = [
"--title=SecGen #{VERSION_NUMBER} Documentation",
"--readme=#{ROOT_DIR}/README.md",
"--output-dir #{DOCUMENTATION_PATH}"
] # optional
t.stats_options = ['--list-undoc'] # optional
end
end
task :yard_clean do
require_relative '../../lib/constants.rb'
# NEED TO FIND A BETTER WAY TO CLEAN FILES AS VULNERABILITIES IN 'rm_rf'
# Remove the documentation directory and all files in it
rm_rf(DOCUMENTATION_PATH)
end

View File

@@ -2,12 +2,14 @@ require_relative 'systemreader.rb'
class Configuration
# populates the system class with an array of System objects.
# Populates the system class with an array of System objects.
def initialize
@systemreader = SystemReader.new
@systems = init_systems()
end
# Return all systems
# @return [Array] Array of systems objects
def get_systems
if @systems.empty?
init_systems()
@@ -15,10 +17,13 @@ class Configuration
return @systems
end
# Initialise configuration of all systems
def init_systems()
@systems = @systemreader.parse_systems
end
# Returns the existing networks if defined, else returns network from the file networks.xml
# @return [Array] Array of network objects
def self.networks
if defined? @@networks
return @@networks
@@ -26,6 +31,8 @@ class Configuration
return @@networks = _get_list(NETWORKS_XML, "//networks/network", Network)
end
# Returns the existing bases if defined, else returns bases the from the file base.xml
# @return [Array] Array of base_box objects
def self.bases
if defined? @@bases
return @@bases
@@ -33,6 +40,8 @@ class Configuration
return @@bases = _get_list(BASE_XML, "//bases/base", Basebox)
end
# Returns the existing vulnerabilities if defined, else returns vulnerabilities the from the file vuln.xml
# @return [Array] Array of vulnerability objects
def self.vulnerabilities
if defined? @@vulnerabilities
return @@vulnerabilities
@@ -40,6 +49,8 @@ class Configuration
return @@vulnerabilities = _get_list(VULN_XML, "//vulnerabilities/vulnerability", Vulnerability)
end
# Returns the existing services if defined, else returns services the from the file services.xml
# @return [Array] Array of service objects
def self.services
if defined? @@services
return @@services
@@ -47,6 +58,11 @@ class Configuration
return @@services = _get_list(SCENARIO_XML, "/systems/system/services/service", Service)
end
# Reads xml file and returns relevent items
# @param xmlfile [File] Name of XML file to read
# @param xpath [String] Path to puppet files
# @param cls [Class] Class to be imported in
# @return [Array] List containing all item from given xml file
def self._get_list(xmlfile, xpath, cls)
itemlist = []

View File

@@ -1,25 +1,74 @@
#FILE CONSTANTS
## FILE_CONSTANTS ##
# Root directory of SecGen file structure
ROOT_DIR = File.expand_path('../../../SecGen',__FILE__)
# Path to Scenario.xml file
SCENARIO_XML = "#{ROOT_DIR}/config/scenario.xml"
# Path to Networks.xml file
NETWORKS_XML = "#{ROOT_DIR}/xml/networks.xml"
# Path to services.xml file
SERVICES_XML = "#{ROOT_DIR}/xml/services.xml"
# Path to bases.xml file
BASE_XML = "#{ROOT_DIR}/xml/bases.xml"
# Path to mount directory
MOUNT_DIR = "#{ROOT_DIR}/mount/"
# Path to build directory
BUILD_DIR = "#{ROOT_DIR}/modules/build/"
# Path to mount/puppet directory
MOUNT_PUPPET_DIR = "#{ROOT_DIR}/mount/puppet"
# Path to projects directory
PROJECTS_DIR = "#{ROOT_DIR}/projects"
# Path to environments directory
ENVIRONMENTS_PATH = "#{ROOT_DIR}/modules/environments"
#PATH CONSTANTS
## PATH_CONSTANTS ##
# Path to modules directory
MODULES_PATH = "#{ROOT_DIR}/modules/"
# Path to vulnerabilities directory
VULNERABILITIES_PATH = "#{ROOT_DIR}/modules/vulnerabilities/"
#ERROR CONSTANTS
# Path to documentation (Make sure documentation directory is already deleted with rake yard_clean before changing this)
DOCUMENTATION_PATH = "#{ROOT_DIR}/documentation/yard/doc"
## ERROR_CONSTANTS ##
# Vulnerability not found in scenario.xml file error
VULN_NOT_FOUND = "Matching vulnerability was not found please check the xml scenario.xml"
#RUNTIME_CONSTANTS
## RUNTIME_CONSTANTS ##
# CVE numbers available
AVAILABLE_CVE_NUMBERS = []
#VAGRANT_FILE_CONSTANTS
## VAGRANT_FILE_CONSTANTS ##
# Path to cleanup directory
PATH_TO_CLEANUP = "#{ROOT_DIR}/modules/build/puppet/"
# Path to vagrantbase.erb file
VAGRANT_TEMPLATE_FILE = "#{ROOT_DIR}/lib/templates/vagrantbase.erb"
# Path to report.erb file
REPORT_TEMPLATE_FILE = "#{ROOT_DIR}/lib/templates/report.erb"
## VERSION_CONSTANTS ##
# Version number of SecGen
# e.g. [release state (0 = alpha, 3 = final release)].[Major bug fix].[Minor bug fix].[Cosmetic or other features]
VERSION_NUMBER = '0.0.0.1'

View File

@@ -2,9 +2,15 @@ class ERBController
# ERB Controller initializes the system and returns the binding when mapping .erb files
attr_accessor :systems
# Initialise systems array
# @return [Array] Empty array for systems
def initialize
@systems = []
end
# Returns binding of mapped .erb files
# @return binding ?????
def get_binding
return binding
end

View File

@@ -2,14 +2,21 @@ require 'erb'
require_relative 'erb_controller'
require_relative 'constants'
require_relative 'configuration'
require_relative 'xml_report_generator'
require 'fileutils'
class FileCreator
# Creates project directory, uses .erb files to create a report and the vagrant file that will be used
# to create the virtual machines
# Initialises configuration variable
# @param config [Object]
def initialize(config)
@configuration = config
end
# Generate all relevant files for the project
# @return [Int] Build number of the newly generated project
def generate()
systems = @configuration.get_systems
Dir::mkdir("#{PROJECTS_DIR}") unless File.exists?("#{PROJECTS_DIR}")
@@ -20,6 +27,8 @@ class FileCreator
puts "The system is now creating the Project#{build_number}"
Dir::mkdir("#{PROJECTS_DIR}/Project#{build_number}") unless File.exists?("#{PROJECTS_DIR}/#{build_number}")
puts 'Creating the projects mount directory'
Dir::mkdir("#{PROJECTS_DIR}/Project#{build_number}/mount") unless File.exists?("#{PROJECTS_DIR}/Project#{build_number}/mount")
# initialises box before creation
command = "cd #{PROJECTS_DIR}/Project#{build_number}/; vagrant init"
@@ -29,16 +38,21 @@ class FileCreator
controller.systems = systems
vagrant_template = ERB.new(File.read(VAGRANT_TEMPLATE_FILE), 0, '<>')
if File.exists?("#{PROJECTS_DIR}/Project#{build_number}/Vagrantfile")
File.delete("#{PROJECTS_DIR}/Project#{build_number}/Vagrantfile")
end
File.delete("#{PROJECTS_DIR}/Project#{build_number}/Vagrantfile")
end
puts "#{PROJECTS_DIR}/Project#{build_number}/Vagrantfile file has been created"
File.open("#{PROJECTS_DIR}/Project#{build_number}/Vagrantfile", 'w') { |file| file.write(vagrant_template.result(controller.get_binding)) }
#report_template = ERB.new(File.read(REPORT_TEMPLATE_FILE), 0, '<>')
#puts "#{PROJECTS_DIR}/Project#{build_number}/Report file has been created"
#File.open("#{PROJECTS_DIR}/Project#{build_number}/Report", 'w'){ |file| file.write(report_template.result(controller.get_binding)) }
# Create the Report file
report_template = ERB.new(File.read(REPORT_TEMPLATE_FILE), 0, '<>')
puts "#{PROJECTS_DIR}/Project#{build_number}/Report file has been created"
File.open("#{PROJECTS_DIR}/Project#{build_number}/Report", 'w'){ |file| file.write(report_template.result(controller.get_binding)) }
return build_number
# Create the Report.xml file
xml_report_generator = XMLReportGenerator.new(systems, build_number)
xml_report_generator.write_xml_report
puts "#{PROJECTS_DIR}/Project#{build_number}/Report.xml file has been created"
return build_number
end
end

View File

@@ -1,9 +1,10 @@
require 'fileutils'
class Bootstrap
# Bootstrap the application by creating or moving all relevant puppet files
def bootstrap
puts 'Bootstrapping application..'
#if mount doesnt exist create the directory structure
#if mount does not exist create the directory structure
if !Dir.exists?("#{ROOT_DIR}/mount")
create_directory_structure
move_vulnerability_puppet_files
@@ -21,6 +22,8 @@ class Bootstrap
private
# Create directory structure for puppet files
# Structure /mount/puppet/module and /mount/puppet/manifest
def create_directory_structure
print 'Mount directory not present, creating..'
Dir.mkdir("#{ROOT_DIR}/mount")
@@ -33,6 +36,7 @@ class Bootstrap
puts ' Complete'
end
# Copy all puppet files from /modules/vulnerabilities/ to /mount/puppet/module and /mount/puppet/module
def move_vulnerability_puppet_files
puts 'Moving vulnerability manifests'
Dir.glob("#{ROOT_DIR}/modules/vulnerabilities/*/*/*/*.pp").each do |puppet_file|
@@ -48,6 +52,7 @@ class Bootstrap
end
end
# Copy all puppet files from /modules/services to /mount/puppet/manifest and /mount/puppet/module
def move_secure_service_puppet_files
puts 'Moving Service manifests'
Dir.glob("#{ROOT_DIR}/modules/services/*/*/*/*.pp").each do |puppet_file|
@@ -67,6 +72,7 @@ class Bootstrap
end
end
# Move dependency modules, build manifests and build modules
def move_build_puppet_files
puts 'Moving Dependency modules'
@@ -96,6 +102,7 @@ class Bootstrap
end
# Purge all puppet files from mount directory
def purge_puppet_files
FileUtils.rm_rf("#{ROOT_DIR}/mount")
end

View File

@@ -2,6 +2,9 @@ require_relative '../objects/vulnerability.rb'
require_relative '../constants.rb'
class VulnerabilityHelper
# Assign all values to a new vulnerability object
# @param vulnerability_hash [Hash]
# @return [Object] Vulnerability object containing all available values
def getVulnerabilityObject(vulnerability_hash)
vulnerability = Vulnerability.new
vulnerability.type = vulnerability_hash['type'] if vulnerability_hash['type']

View File

@@ -4,114 +4,124 @@ require_relative 'vulnerability_helper'
require 'xmlsimple'
class VulnerabilityProcessor
def initialize()
@vulnerability_helper = VulnerabilityHelper.new
end
# returns a hash of compatible vulnerabilities based on what is provided in scenario.xml (scenario_vulns)
# based on the attributes optionally specified in scenario.xml (scenario_vulns)
def process(scenario_vulns)
#Initialise the Vulnerability processor object by creating a new VulnerabilityHelper object
def initialize()
@vulnerability_helper = VulnerabilityHelper.new
end
# returns a hash of compatible vulnerabilities based on what is provided in scenario.xml (scenario_vulns)
# based on the attributes optionally specified in scenario.xml (scenario_vulns)
# @param scenario_vulns [String] Attributes specified in scenario.xml
# @return [Hash] Vulnerability values
def process(scenario_vulns)
return_vulns = {}
return_vulns = {}
all_vulnerabilities = get_vulnerabilities_array
all_vulnerabilities = get_vulnerabilities_array
scenario_vulns.each do |vulnerability_query|
# select based on selected type, access, cve...
search_list = all_vulnerabilities.clone
# shuffle order of available vulnerabilities
search_list.shuffle!
# remove all the vulns that don't match the current selection (type, etc)
if vulnerability_query.type.length > 0
puts "Searching for vulnerability matching type: " + vulnerability_query.type
search_list.delete_if{|x| x.type != vulnerability_query.type}
end
if vulnerability_query.access.length > 0
puts "Searching for vulnerability matching access: " + vulnerability_query.access
search_list.delete_if{|x| x.access != vulnerability_query.access}
end
if vulnerability_query.cve.length > 0
puts "Searching for vulnerability matching CVE: " + vulnerability_query.cve
search_list.delete_if{|x| x.cve != vulnerability_query.cve}
end
if vulnerability_query.difficulty.length > 0
puts "Searching for vulnerability matching difficulty: " + vulnerability_query.difficulty
search_list.delete_if{|x| x.difficulty != vulnerability_query.difficulty}
end
if vulnerability_query.cvss_rating.length > 0
puts "Searching for vulnerability matching cvss rating: " + vulnerability_query.cvss_rating
remove_by_cvss(vulnerability_query, search_list)
end
if vulnerability_query.vector_string.length > 0
puts "Searching for vulnerability based on vector string: " + vulnerability_query.vector_string
remove_by_vector(vulnerability_query, search_list)
end
if search_list.length == 0
puts VULN_NOT_FOUND
puts "(note: you can only have one of each type of vulnerability per system)"
exit
else
# use from the top of the top of the randomised list
return_vulns[vulnerability_query.id] = search_list[0]
if search_list[0].type.length > 0
puts "Selected vulnerability : " + search_list[0].type
end
# enforce only one of any vulnerability type (remove from available)
search_list.delete_if{|x| x.type == vulnerability_query.type}
end
scenario_vulns.each do |vulnerability_query|
# select based on selected type, access, cve...
search_list = all_vulnerabilities.clone
# shuffle order of available vulnerabilities
search_list.shuffle!
# remove all the vulns that don't match the current selection (type, etc)
if vulnerability_query.type.length > 0
puts "Searching for vulnerability matching type: " + vulnerability_query.type
search_list.delete_if{|x| x.type != vulnerability_query.type}
end
if vulnerability_query.access.length > 0
puts "Searching for vulnerability matching access: " + vulnerability_query.access
search_list.delete_if{|x| x.access != vulnerability_query.access}
end
if vulnerability_query.cve.length > 0
puts "Searching for vulnerability matching CVE: " + vulnerability_query.cve
search_list.delete_if{|x| x.cve != vulnerability_query.cve}
end
if vulnerability_query.difficulty.length > 0
puts "Searching for vulnerability matching difficulty: " + vulnerability_query.difficulty
search_list.delete_if{|x| x.difficulty != vulnerability_query.difficulty}
end
return return_vulns.values
end
def get_vulnerabilities_array
vulnerabilities = []
Dir.glob("#{ROOT_DIR}/modules/vulnerabilities/**/**/secgen_metadata.xml").each do |file|
vulnerability_hash = XmlSimple.xml_in(file, {})
vulnerability = @vulnerability_helper.getVulnerabilityObject(vulnerability_hash)
vulnerabilities.push(vulnerability)
if vulnerability_query.cvss_rating.length > 0
puts "Searching for vulnerability matching cvss rating: " + vulnerability_query.cvss_rating
remove_by_cvss(vulnerability_query, search_list)
end
return vulnerabilities
if vulnerability_query.vector_string.length > 0
puts "Searching for vulnerability based on vector string: " + vulnerability_query.vector_string
remove_by_vector(vulnerability_query, search_list)
end
if search_list.length == 0
puts VULN_NOT_FOUND
puts "(note: you can only have one of each type of vulnerability per system)"
exit
else
# use from the top of the top of the randomised list
return_vulns[vulnerability_query.id] = search_list[0]
if search_list[0].type.length > 0
puts "Selected vulnerability : " + search_list[0].type
end
# enforce only one of any vulnerability type (remove from available)
search_list.delete_if{|x| x.type == vulnerability_query.type}
end
end
def remove_by_cvss (vulnerability_query, search_list)
puts case vulnerability_query.cvss_rating
when 'none' # 0.0
search_list.delete_if{|x| x.cvss_score.to_f > 0 }
when 'low' # 0.1 - 3.9
search_list.delete_if{|x| x.cvss_score.to_f == 0 or x.cvss_score.to_f > 4 }
when 'medium' # 4.0 - 6.9
search_list.delete_if{|x| x.cvss_score.to_f < 4 or x.cvss_score.to_f > 7 }
when 'high' # 7.0 - 8.9
search_list.delete_if{|x| x.cvss_score.to_f < 7 and x.cvss_score.to_f <= 9 }
when 'critical' # 9.0 - 10
search_list.delete_if{|x| x.cvss_score.to_f < 9 }
end
return return_vulns.values
end
# Get array of vulnerability objects
# @return [Array] Array containing vulnerability objects
def get_vulnerabilities_array
vulnerabilities = []
Dir.glob("#{ROOT_DIR}/modules/vulnerabilities/**/**/secgen_metadata.xml").each do |file|
vulnerability_hash = XmlSimple.xml_in(file, {})
vulnerability = @vulnerability_helper.getVulnerabilityObject(vulnerability_hash)
vulnerabilities.push(vulnerability)
end
# method which removes vulnerabilities from the search_list based on vector string provided
# in the vulnerability_query (i.e. a user specified <vulnerability> in scenario.xml)
def remove_by_vector (query_vulnerability, search_list)
return vulnerabilities
end
# Remove vulnerability queries from search list
# @param vulnerability_query [String] Vulnerability query
# @param search_list [Array] List containing all remaining vulnerabilities
def remove_by_cvss (vulnerability_query, search_list)
puts case vulnerability_query.cvss_rating
when 'none' # 0.0
search_list.delete_if{|x| x.cvss_score.to_f > 0 }
when 'low' # 0.1 - 3.9
search_list.delete_if{|x| x.cvss_score.to_f == 0 or x.cvss_score.to_f > 4 }
when 'medium' # 4.0 - 6.9
search_list.delete_if{|x| x.cvss_score.to_f < 4 or x.cvss_score.to_f > 7 }
when 'high' # 7.0 - 8.9
search_list.delete_if{|x| x.cvss_score.to_f < 7 and x.cvss_score.to_f <= 9 }
when 'critical' # 9.0 - 10
search_list.delete_if{|x| x.cvss_score.to_f < 9 }
end
end
# method which removes vulnerabilities from the search_list based on vector string provided
# in the vulnerability_query (i.e. a user specified <vulnerability> in scenario.xml)
# @param query_vulnerability [String] Vector string for desired vulnerabilities
# @param search_list [Array] List containing all remaining vulnerabilities
def remove_by_vector(query_vulnerability, search_list)
query_vector_hash = query_vulnerability.get_vector_hash
for query_vector_pair in query_vector_hash
search_list.delete_if{ |vulnerability|
search_vector_hash = vulnerability.get_vector_hash
search_vector_pair = search_vector_hash.assoc(query_vector_pair[0])
if search_vector_pair != nil
query_vector_pair[1] != search_vector_pair[1]
else
true
end
}
end
search_list.delete_if{ |vulnerability|
search_vector_hash = vulnerability.get_vector_hash
search_vector_pair = search_vector_hash.assoc(query_vector_pair[0])
if search_vector_pair != nil
query_vector_pair[1] != search_vector_pair[1]
else
true
end
}
end
end
end

View File

@@ -1,4 +1,8 @@
class BaseManager
# Generates a basebox system from a sample of the bases.xml file
# @param system [Object] System object
# @param bases [Array] Bases array
# @return [Object] Basebox system
def self.generate_base(system,bases)
# takes a sample from bases.xml and then assigns it to system
box = bases.sample

View File

@@ -1,5 +1,10 @@
class NetworkManager
# the user will either specify a blank misc type or a knownnetwork type
# Check if given networks are valid if networks valid return the values, else display error message
# @param networks [Array] Networks to check for validity
# @param valid_network [String] Valid network value
# @return [Array] Returns all the values for new_networks as an array
def self.process(networks,valid_network)
new_networks = {}
# intersection of valid networks / user defined networks

View File

@@ -2,6 +2,10 @@ class ServiceManager
# secure services are randomly selected from the definitions in services.xml (secure_services)
# based on the attributes optionally specified in scenario.xml (want_services)
# However, if the service type has already had a vulnerability assigned (selected_vulns), it is ignored here
# @param want_services [String] Services specified in scenario.xml
# @param secure_services [String] Random services selected from definitions in services.xml
# @param selected_vulns [Array] Vulnerabilities that have already been assigned
# @return [Object] Service object
def self.process(want_services, secure_services, selected_vulns=[])
return_services = {}
legal_services = secure_services.clone

View File

@@ -1,3 +1,17 @@
class Basebox
attr_accessor :name, :os, :distro, :vagrantbase, :url
# Name of the basebox
attr_accessor :name
# Operating system on the basebox
attr_accessor :os
# Distro running on the basebox
attr_accessor :distro
# Selected vagrantbase of the system
attr_accessor :vagrantbase
# Url link to the puppet basebox
attr_accessor :url
end

View File

@@ -1,7 +1,7 @@
#Contains common components that modules will inherit from.
class BaseModule
#Name of the module
# Name of the module
attr_accessor :name
#Type of the module

View File

@@ -1,22 +1,36 @@
class Network
attr_accessor :name, :range
# Network name
attr_accessor :name
# Network range
attr_accessor :range
# Initialise Network object
# @param name [String] Network name
# @param range [String] Network range
def initialize(name="", range="")
@name = name
@range = range
end
# Returns a string containing all object variables concatenated together
# @return [String] Hash containing @name and @range object variables as a concatenated string
def id
hash = @name + @range
return hash
# return string that connects everything to 1 massive string
end
# Check if name matches networks.xml from scenario.xml
# @param other [String]
# @return [Boolean] Returns true if @name matches networks.xml from scenario.xml
def eql? other
# checks if name matches networks.xml from scenario.xml
other.kind_of?(self.class) && @name == other.name
end
# Returns a hash of the type
# @return [Hash] Hash of the object variable @type
def hash
@type.hash
end

View File

@@ -1,6 +1,21 @@
class Service
attr_accessor :name, :type, :details, :puppets
# Service name
attr_accessor :name
# Type of service
attr_accessor :type
# Service details
attr_accessor :details
# Puppet files used to create service
attr_accessor :puppets
# Initialise Service object
# @param name [String] service name
# @param type [String] service range
# @param details [String] service details
# @param puppets [Array] puppet files used to create service
def initialize(name="", type="", details="", puppets=[])
@name = name
@type = type
@@ -8,14 +23,21 @@ class Service
@puppets = puppets
end
# Check if name matches services.xml from scenario.xml
# @param other [String]
# @return [Boolean] Returns true if @type matches services.xml from scenario.xml
def eql? other
other.kind_of?(self.class) && @type == other.type
end
# Returns a hash of the type
# @return [Hash] hash of the object variable @type
def hash
@type.hash
end
# Returns string containing the object type variable
# @return [String] Services id string
def id
return @type
end

View File

@@ -1,6 +1,13 @@
class Site
attr_accessor :name, :type
# Site name
attr_accessor :name
# Type of site
attr_accessor :type
# Initialize site object
# @param name [String]
# @param type [String]
def initialize(name='', type='')
@name = name
@type = type

View File

@@ -1,8 +1,39 @@
class System
# can access from outside of class
attr_accessor :id, :os, :url,:basebox, :networks, :vulns, :services, :sites
#initalizes system variables
# System's id number
attr_accessor :id
# Operating system running on the system
attr_accessor :os
# URL to the puppet basebox
attr_accessor :url
# Puppet basebox name
attr_accessor :basebox
# Networks used by the system
attr_accessor :networks
# Vulnerabilite's installed on the system
attr_accessor :vulns
# Services installed on the system
attr_accessor :services
# Sites to be served from the system
attr_accessor :sites
# Initalizes System object
# @param id [String] Identifier string for system object
# @param os [String] Operating system installed on the system
# @param basebox [String] Puppet basebox used to create the system
# @param url [String] url to the selected puppet basebox
# @param vulns [Array] Array containing selected vulnerability objects
# @param networks [Array] Array containing selected network objects
# @param services [Array] Array containing selected services objects
# @param sites [Array] Array containing selected sites objects
def initialize(id, os, basebox, url, vulns=[], networks=[], services=[], sites=[])
@id = id
@os = os
@@ -14,6 +45,8 @@ class System
@sites = sites
end
# Checks to see if the selected base is a valid basebox and is in the vagrant file
# @return [Boolean] Is the basebox valid
def is_valid_base
valid_base = Configuration.bases

View File

@@ -1,65 +1,131 @@
require_relative('../constants.rb')
class Vulnerability
attr_accessor :type, :privilege, :access ,:puppets, :details, :ports, :name, :cve, :files, :scripts, :platform, :difficulty, :cvss_rating, :cvss_score, :vector_string
# The type of vulnerability
attr_accessor :type
def initialize(type='', privilege='', access='', puppets=[], details='', ports=[], platform ='', name='', cve='', files=[], scripts=[], difficulty ='', cvss_rating='', cvss_score='',vector_string='')
@type = type
@privilege = privilege
@access = access
@puppets = puppets
@details = details
@ports = ports
@platform = platform
@name = name
@cve = cve
@files = files
@scripts = scripts
@difficulty = difficulty
@cvss_rating = cvss_rating
@cvss_score = cvss_score
@vector_string = vector_string
# The privilege level the vulnerability gives
attr_accessor :privilege
# Base Vector String:
# Example 1: 'AV:L/AC:H/Au:N/C:N/I:P/A:C'
# Access Vector: L = Local access, A = adjacent access, N = network access
# Access Complexity: H = High, M = Medium, L = Low
# Authentication: N = None required, S = Single instance, M = Multi instance
# Confidentiality Impact: N = None, P = Partial, C = Complete
# Integrity Impact: N = None, P = Partial, C = Complete
# Availabiliy Impact: N = None, P = Partial, C = Complete
# The access level the vulnerability gives
attr_accessor :access
end
# The puppet files used for the vulnerability
attr_accessor :puppets
def id
return @type + @privilege + @access
end
# Details describing the vulnerability
attr_accessor :details
def vulnerability_path
return "#{ROOT_DIR}/modules/vulnerabilities/#{@platform}/#{@type}/#{@name}"
end
# Ports used by the vulnerability
attr_accessor :ports
def puppet_path
return vulnerability_path + '/puppet'
end
# Name given to the vulnerability
attr_accessor :name
def is_vector_populated
return vector_string.length > 0
end
# Vulnerability's CVE number
attr_accessor :cve
#
def get_vector_hash
base_vector_string = vector_string # for example: "AV:L/AC:H/Au:N/C:N/I:P/A:C"
base_vector_array = base_vector_string.split('/') # split to get: ['AV:L', 'AC:H', 'Au:N','C:N', 'I:P', 'A:C']
#
attr_accessor :files
#
attr_accessor :scripts
# Platform the vulnerability will work on
attr_accessor :platform
# Difficulty of the vulnerability
attr_accessor :difficulty
# Vulnerability's cvss_rating
attr_accessor :cvss_rating
# Vulnerability's cvss_score
attr_accessor :cvss_score
# Vulnerability's vector_string, e.g. AV:L/AC:H/Au:N/C:N/I:P/A:C
attr_accessor :vector_string
# Initialises Vulnerability object
# @param type [String] Type of vulnerability
# @param privilege [String] Privilege obtained after successful exploitation
# @param access [String] Access obtained after successful exploitation
# @param puppets [Array] Array of puppet files needed for the vulnerability
# @param details [String] Details of the vulnerability
# @param ports [Array] Ports used by the vulnerability
# @param platform [String] Platform the vulnerability will work on
# @param name [String] Name of the vulnerability
# @param cve [String] CVE number of the vulnerability
# @param files [Array]
# @param scripts [Array]
# @param difficulty [String] Difficulty level of exploiting the vulnerability
# @param cvss_rating [String] Vulnerability's cvss_rating
# @param cvss_score [String] Vulnerability's cvss_score
# @param vector_string [String] Vulnerability's vector_string, e.g. AV:L/AC:H/Au:N/C:N/I:P/A:C
def initialize(type='', privilege='', access='', puppets=[], details='', ports=[], platform ='', name='', cve='', files=[], scripts=[], difficulty ='', cvss_rating='', cvss_score='',vector_string='')
@type = type
@privilege = privilege
@access = access
@puppets = puppets
@details = details
@ports = ports
@platform = platform
@name = name
@cve = cve
@files = files
@scripts = scripts
@difficulty = difficulty
@cvss_rating = cvss_rating
@cvss_score = cvss_score
@vector_string = vector_string
# Base Vector String:
# Example 1: 'AV:L/AC:H/Au:N/C:N/I:P/A:C'
# Access Vector: L = Local access, A = adjacent access, N = network access
# Access Complexity: H = High, M = Medium, L = Low
# Authentication: N = None required, S = Single instance, M = Multi instance
# Confidentiality Impact: N = None, P = Partial, C = Complete
# Integrity Impact: N = None, P = Partial, C = Complete
# Availability Impact: N = None, P = Partial, C = Complete
# convert this into a hash map
base_vector_hash = {}
for vector_element_string in base_vector_array
vector_element_array = vector_element_string.split(':')
if vector_element_array[1] != nil
base_vector_hash.store(vector_element_array[0], vector_element_array[1])
end
end
return base_vector_hash
end
end
# Returns identifier string made of the @type, @privilege and @access object variables
# @return [String] Identifier string made of the @type, @privilege and @access object variables
def id
return @type + @privilege + @access
end
# Returns path to the selected vulnerabilities files
# @return [String] Path to the vulnerability files
def vulnerability_path
return "#{ROOT_DIR}/modules/vulnerabilities/#{@platform}/#{@type}/#{@name}"
end
# Returns path to the puppet files for the selected vulnerability
# @return [String] Path to the puppet files for the selected vulnerability
def puppet_path
return vulnerability_path + '/puppet'
end
def is_vector_populated
return vector_string.length > 0
end
# Returns hash made of all the components in the vector string
# @return [Hash] Hash of vector string components
def get_vector_hash
base_vector_string = vector_string # for example: "AV:L/AC:H/Au:N/C:N/I:P/A:C"
base_vector_array = base_vector_string.split('/') # split to get: ['AV:L', 'AC:H', 'Au:N','C:N', 'I:P', 'A:C']
# convert this into a hash map
base_vector_hash = {}
for vector_element_string in base_vector_array
vector_element_array = vector_element_string.split(':')
if vector_element_array[1] != nil
base_vector_hash.store(vector_element_array[0], vector_element_array[1])
end
end
return base_vector_hash
end
end

View File

@@ -12,6 +12,7 @@ require_relative 'objects/vulnerability'
require 'nokogiri'
class SystemReader
# initializes systems xml from BOXES_XML const
def initialize()
@vulnerability_processor = VulnerabilityProcessor.new
@@ -19,6 +20,7 @@ class SystemReader
# uses nokogiri to extract all system information from scenario.xml will add it to the system class after
# checking if the vulnerabilities / networks exist from system.rb
# @return [Array] Array containing Systems objects
def parse_systems
systems = []
doc = Nokogiri::XML(File.read(SCENARIO_XML))

View File

@@ -1,43 +1,44 @@
<%if systems.count == 1%>
There was only 1 system generated for this project.
There was only 1 system generated for this project.
<%else %>
There were <%systems.count%> systems generated for this project. <%end%>
There were <%systems.count%> systems generated for this project.
<%end%>
The module files for puppet can be found here: "<%=ROOT_DIR%>/mount/puppet/modules"
The manifest files for puppet can be found here: "<%=ROOT_DIR%>/mount/puppet/manifests"
<% systems.each do |s| %>
====System: <%=s.id%>====
<%=s.id%> uses <%=s.basebox%> a distro of <%=s.os%> which can be downloaded from <%=s.url%>
<% s.networks.each do |n| %> <%grab_system_number = s.id.gsub(/[^0-9]/i, "") %> <% n.range[9..9] = grab_system_number %>
ip address for <%=s.id%> = <%=n.range%>0 <% end %>
==Secure services==
<%=s.id%> uses <%=s.basebox%> a distro of <%=s.os%> which can be downloaded from <%=s.url%>
<% s.networks.each do |n| %> <%grab_system_number = s.id.gsub(/[^0-9]/i, "") %> <% n.range[9..9] = grab_system_number %>
ip address for <%=s.id%> = <%=n.range%>0
<% end %>
==Secure services==
<% s.services.each do |v| %>
Here is a summary of the service <%=v.name%>:
Type: <%=v.type%>.
Name: <%= v.name %>.
Details: <%= v.details %>.
Here is a summary of the service <%=v.name%>:
Type: <%=v.type%>.
Name: <%= v.name %>.
Details: <%= v.details %>.
<% v.puppets.each do |p| %>
Puppet "<%=p%>.pp" has been used to create this service.
<% end %>
<% end %>
==Vulnerabilities==
==Vulnerabilities==
<% s.vulns.each do |v| %>
Here is a summary of the vulnerability <%=v.type%>:
Type: <%=v.type%>.
Details: <%= v.details %>.
privilege: <%= v.privilege %>.
access: <%= v.access %>.
<%if not v.cve == ""%>
cve: <%= v.cve %>.
Here is a summary of the vulnerability <%=v.type%>:
Type: <%=v.type%>.
Details: <%= v.details %>.
privilege: <%= v.privilege %>.
access: <%= v.access %>.
<%if not v.cve == ""%>cve: <%= v.cve %>.
<% end %>
<% v.puppets.each do |p| %>
Puppet "<%=p%>.pp" has been used to create this vulnerability.
<% v.puppets.each do |p| %>Puppet "<%=p%>.pp" has been used to create this vulnerability.
<% end %>
<% v.ports.each do |port| %>
Runs on port <%=port%>
<%#=<% v.ports.each do |port| %>
<%#=Runs on port <%=port%>
<%#=<% end %>
<% end %>
<% end %>
<% end %>

View File

@@ -2,10 +2,12 @@ require_relative 'filecreator.rb'
class VagrantController
# Executes vagrant up for the specified build
# @param build_number [Int] Selected build number to execute vagrant up on
def vagrant_up(build_number)
#executes vagrant up from the current build.
puts 'Building now.....'
command = "cd #{PROJECTS_DIR}/Project#{build_number}/; vagrant up"
exec command
exec command
end
end

136
lib/xml_report_generator.rb Normal file
View File

@@ -0,0 +1,136 @@
require 'xmlsimple'
# Convert systems objects into xml
class XMLReportGenerator
# Initialize the class with the systems array and the current build number
# @param systems [Array] Array of all systems objects
# @param build_number [Int] Current build number of system
def initialize(systems, build_number)
@systems = systems
@build_number = build_number
end
### Start of private methods ###
private
##
# Generates hashes as an array for all network interfaces showing the system's ip
# @param s [Array] Current system being generated
# @return [Array] Array of all network hashes
def get_networks_hash(s)
networks_array = Array.new
networks_hash = Hash.new
s.networks.each do |n|
# grab_system_number = s.id.gsub(/[^0-9]/i, "")
# n.range[9..9] = grab_system_number
networks_hash['network'] = [n.range << '0']
networks_array << networks_hash
end
return networks_array
end
##
# Generates hashes as an array for all services to be installed on the specific system
# @param s [Array] Current system being generated
# @return [Array] Array of all service hashes
def get_services_hash(s)
service_array = Array.new
service_hash = Hash.new
s.services.each do |v|
service_hash['type'] = [v.type] unless v.type.empty?
service_hash['name'] = [v.name] unless v.name.empty?
service_hash['details'] = [v.details] unless v.details.empty?
v.puppets.each do |p|
service_hash['puppet_file'] = ["#{p}.pp"]
end
service_array << service_hash
end
return service_array
end
# Generates hashes as an array for all vulnerabilities to be placed on the specific system
# @param s [Array] Current system being generated
# @return [Array] Array of all vulnerability hashes
def get_vulnerabilities_hash(s)
vulns_array = Array.new
vulns_hash = Hash.new
s.vulns.each do |v|
vulns_hash['type'] = [v.type] unless v.type.empty?
vulns_hash['details'] = [v.details] unless v.details.empty?
vulns_hash['privilege'] = [v.privilege] unless v.privilege.empty?
vulns_hash['access'] = [v.access] unless v.access.empty?
vulns_hash['cve'] = [v.cve] unless v.cve.empty?
vulns_hash['difficulty'] = [v.difficulty] unless v.difficulty.empty?
vulns_hash['cvss_rating'] = [v.cvss_rating] unless v.cvss_rating.empty?
vulns_hash['cvss_score'] = [v.cvss_score] unless v.cvss_score.empty?
vulns_hash['vector_string'] = [v.vector_string] unless v.vector_string.empty?
v.puppets.each do |p|
vulns_hash['puppet_file'] = ["#{p['puppet'][0]}.pp"]
end
vulns_array << vulns_hash
end
return vulns_array
end
# Generates hashes as an array for all sites to be placed on the specific system
# @param s [Array] Current system being generated
# @return [Array] Array of all vulnerability hashes
def get_sites_hash(s)
sites_array = Array.new
sites_hash = Hash.new
s.sites.each do |v|
sites_hash['name'] = [v.name] unless (v.name.nil? || v.name.empty?)
sites_hash['type'] = [v.type] unless v.type.empty?
sites_array << sites_hash
end
return sites_array
end
# Creates a hash in the specific format for the XmlSimple library
# @return [Hash] Hash compatible with XmlSimple
def create_xml_hash
hash = Hash.new
@systems.each do |system|
hash = {
'id' => system.id, 'basebox' => system.basebox, 'os' => system.os, 'url' => system.url,
'networks' => get_networks_hash(system),
'services' => get_services_hash(system),
'vulnerabilities' => get_vulnerabilities_hash(system),
'sites' => get_sites_hash(system)
}
end
return hash
end
### Start of public methods ###
public
# Write the xml to an xml file
def write_xml_report
XmlSimple.xml_out(create_xml_hash,{:rootname => 'system',:OutputFile => "#{PROJECTS_DIR}/Project#{@build_number}/Report.xml"})
end
# Return the xml as a string
# @return [String]
def return_xml
return XmlSimple.xml_out(create_xml_hash,{:rootname => 'system'})
end
# Print the xml to the console
def print_xml
puts XmlSimple.xml_out(create_xml_hash,{:rootname => 'system'})
end
end

View File

@@ -6,7 +6,7 @@ require_relative 'lib/systemreader.rb'
require_relative 'lib/vagrant.rb'
require_relative 'lib/helpers/bootstrap'
# Displays secgen usage data
def usage
puts 'Usage:
' + $0 + ' [options]
@@ -20,6 +20,8 @@ def usage
exit
end
# Builds the vagrant configuration file
# @return build_number [Integer] Current system's build number
def build_config
puts 'Reading configuration file for virtual machines you want to create'
@@ -33,11 +35,14 @@ def build_config
return build_number
end
# Builds the vm via the vagrant file corresponding to build number
# @param build_number [Integer] Desired system's build number
def build_vms(build_number)
vagrant = VagrantController.new
vagrant.vagrant_up(build_number)
end
# Runs methods to run and configure a new vm from the configuration file
def run
build_number = build_config()
build_vms(build_number)
@@ -55,13 +60,15 @@ if ARGV.length < 1
usage
end
# Get command line arguments
opts = GetoptLong.new(
[ '--help', '-h', GetoptLong::NO_ARGUMENT ],
[ '--run', '-r', GetoptLong::NO_ARGUMENT ],
[ '--build-config', '-c', GetoptLong::NO_ARGUMENT ],
[ '--build-vms', '-v', GetoptLong::NO_ARGUMENT ]
[ '--build-vms', '-v', GetoptLong::REQUIRED_ARGUMENT ]
)
# Direct via command line arguments
opts.each do |opt, arg|
case opt
when '--help'
@@ -73,7 +80,7 @@ opts.each do |opt, arg|
when '--build-config'
build_config()
when '--build-vms'
build_vms()
build_vms(arg)
end
end

View File

@@ -1,3 +1,4 @@
<!--Bases.xml-->
<bases>
<base name="CentOS6.2" os="linux" distro="centos" url="https://dl.dropbox.com/sh/9rldlpj3cmdtntc/56JW-DSK35/centos-62-32bit-puppet.box" vagrantbase="CentOS6.2withpuppet" ></base>
<base name="CentOS6.3" os="linux" distro="centos" url="https://dl.dropbox.com/sh/9rldlpj3cmdtntc/chqwU6EYaZ/centos-63-32bit-puppet.box" vagrantbase="CentOS6.3withpuppet" ></base>