diff --git a/filecreator.rb b/filecreator.rb index e27c96c9d..44918ad07 100644 --- a/filecreator.rb +++ b/filecreator.rb @@ -13,6 +13,7 @@ class FileCreator def initialize(systems) @systems = systems end + def generate(system) Dir::mkdir("#{PROJECTS_DIR}") unless File.exists?("#{PROJECTS_DIR}") @@ -20,7 +21,7 @@ class FileCreator build_number = count.next - p "the system is now creating the Project#{build_number}" + puts "The system is now creating the Project#{build_number}" Dir::mkdir("#{PROJECTS_DIR}/Project#{build_number}") unless File.exists?("#{PROJECTS_DIR}/#{build_number}") # initialises box before creation @@ -29,13 +30,14 @@ class FileCreator controller = ERBController.new controller.systems = system - vagrant_template = ERB.new(File.read(VAGRANT_TEMPLATE_FILE)) - p "#{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)) } + vagrant_template = ERB.new(File.read(VAGRANT_TEMPLATE_FILE), 0, '<>') + File.delete("#{PROJECTS_DIR}/Project#{build_number}/Vagrantfile") + 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)) - p "#{PROJECTS_DIR}/Project#{build_number}/Report file has been created" + 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 @@ -53,4 +55,4 @@ class ERBController def get_binding return binding end -end \ No newline at end of file +end diff --git a/lib/commandui/logo/logo.txt b/lib/commandui/logo/logo.txt index 9d45a97a7..b397b1108 100644 --- a/lib/commandui/logo/logo.txt +++ b/lib/commandui/logo/logo.txt @@ -1,6 +1,10 @@ - ______________________________________________________________________________ -| | -| Security Simulator | -| Created By Lewis Ardern | -| Leeds Met Final Year Project | -|______________________________________________________________________________| \ No newline at end of file + _____ _ _ _____ _ _ _ + / ____| (_) | / ____(_) | | | | +| (___ ___ ___ _ _ _ __ _| |_ _ _| (___ _ _ __ ___ _ _| | __ _| |_ ___ _ __ + \___ \ / _ \/ __| | | | '__| | __| | | |\___ \| | '_ ` _ \| | | | |/ _` | __| / _ \| '__| + ____) | __/ (__| |_| | | | | |_| |_| |____) | | | | | | | |_| | | (_| | |_ | (_) | | +|_____/ \___|\___|\__,_|_| |_|\__|\__, |_____/|_|_| |_| |_|\__,_|_|\__,_|\__| \___/|_| + __/ | + Licensed GPLv3 |___/ Creates virtualised security scenarios + 2014-15 By Lewis Ardern and Z.Cliffe.S + diff --git a/lib/templates/report.erb b/lib/templates/report.erb index cf44561d4..f610d5f01 100644 --- a/lib/templates/report.erb +++ b/lib/templates/report.erb @@ -1,37 +1,43 @@ -This document has been automated for build <%if systems.count == 1%> 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" +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.services.each do |v| %> + 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 %> -<%=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 %> - <% 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 %> - <% end %> - <% v.puppets.each do |p| %> - Puppet "<%=p%>.pp" has been used to create these vulnerabiliies - <% end %> - <% v.ports.each do |port| %> - Web server runs on port <%=port%> - <% end %> - <% end %> - + ==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 %>. +<% end %> +<% 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%> +<% end %> +<% end %> <% end %> diff --git a/lib/templates/vagrantbase.erb b/lib/templates/vagrantbase.erb index 212358fd7..3f5fdcb47 100644 --- a/lib/templates/vagrantbase.erb +++ b/lib/templates/vagrantbase.erb @@ -5,43 +5,52 @@ VAGRANTFILE_API_VERSION = "2" Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| - <% systems.each do |s| %> - +<% systems.each do |s| %> config.vm.define "<%=s.id%>" do |<%=s.id%>| <%=s.id%>.vm.box = "<%=s.basebox%>" <%=s.id%>.vm.box_url = "<%=s.url%>" - <% s.networks.each do |n| %> - <%grab_system_number = s.id.gsub(/[^0-9]/i, "") %> - <% n.range[9..9] = grab_system_number %> - <%=s.id%>.vm.network :public_network - <%=s.id%>.vm.network :private_network, :ip => "<%=n.range%>0" - <% end %> +<% s.networks.each do |n| %> +<%grab_system_number = s.id.gsub(/[^0-9]/i, "") %> +<% n.range[9..9] = grab_system_number %> + <%=s.id%>.vm.network :public_network + <%=s.id%>.vm.network :private_network, :ip => "<%=n.range%>0" +<% end %> <%=s.id%>.vm.synced_folder "<%=MOUNT_DIR%>", "/mount" end config.vm.provision :shell, :inline => "apt-get update --fix-missing" - <%s.vulns.each do |v|%> - <%v.puppets.each do |p|%> - config.vm.provision "puppet" do |<%=p%>| - <%=p%>.module_path = "<%=ROOT_DIR%>/mount/puppet/modules" - <%=p%>.manifests_path = "<%=ROOT_DIR%>/mount/puppet/manifests" + # Add secure services +<%s.services.each do |v|%> +<%v.puppets.each do |p|%> + config.vm.provision "puppet" do |<%=p%>| + <%=p%>.module_path = "<%=ROOT_DIR%>/mount/puppet/modules" + <%=p%>.manifests_path = "<%=ROOT_DIR%>/mount/puppet/manifests" + <%=p%>.manifest_file = "<%=p%>.pp" + end +<% end %> +<% end %> - <%=p%>.manifest_file = "<%=p%>.pp" - end - <% end %> - <% end %> + # Add vulnerabilities +<%s.vulns.each do |v|%> +<%v.puppets.each do |p|%> + config.vm.provision "puppet" do |<%=p%>| + <%=p%>.module_path = "<%=ROOT_DIR%>/mount/puppet/modules" + <%=p%>.manifests_path = "<%=ROOT_DIR%>/mount/puppet/manifests" + <%=p%>.manifest_file = "<%=p%>.pp" + end +<% end %> +<% end %> + # clean up script which clears history from the VMs and clobs files together config.vm.provision "puppet" do |cleanup| cleanup.module_path = "<%=ROOT_DIR%>/mount/puppet/modules" cleanup.manifests_path = "<%=ROOT_DIR%>/mount/puppet/manifests" - cleanup.manifest_file = "cleanup.pp" end - # clean up script which clears history and clobs files together - config.vm.provision :shell, :inline => "history -c && history -w" config.vm.provision :shell, :inline => "umount /mount/" - <% end %> + +<% end %> end diff --git a/lib/xml/boxes.xml b/lib/xml/boxes.xml index 4ac1d505a..897ca6108 100644 --- a/lib/xml/boxes.xml +++ b/lib/xml/boxes.xml @@ -1,10 +1,30 @@ - + + - + + + + + + + + + - + + + + + + + + + + + + diff --git a/lib/xml/vulns.xml b/lib/xml/vulns.xml index 39840a0b1..04199e3f8 100644 --- a/lib/xml/vulns.xml +++ b/lib/xml/vulns.xml @@ -10,7 +10,7 @@ writeableshadow @@ -62,8 +62,8 @@ distcc - 0 + puts "Searching for service matching type: " + service_query.type + search_list.delete_if{|x| x.type != service_query.type} + end + + if search_list.length == 0 + STDERR.puts "Matching service was not found please check the xml boxes.xml" + STDERR.puts "(note: you can only have one of each type of service per system)" + exit + else + # use from the top of the top of the randomised list + return_services[service_query.id] = search_list[0] + if search_list[0].type.length > 0 + puts "Selected secure service : " + search_list[0].type + end + + # enforce only one of any service type (remove from available) + legal_services.delete_if{|x| x.type == service_query.type} + end + end + return return_services.values + end +end + class NetworkManager # the user will either specify a blank network type or a knownnetwork type def self.process(networks,valid_network) @@ -136,46 +210,50 @@ class Vulnerability end class VulnerabilityManager - # the user will either specify a blank vulnerability or will check it against vulns.xml and will append - # specific information to system if the system information is empty - def self.process(vulns,valid_vulns) - new_vulns = {} + # vulnerabilities are randomly selected from the definitions in vulns.xml (all_vulns) + # based on the attributes optionally specified in boxes.xml (want_vulns) + def self.process(want_vulns, all_vulns) + return_vulns = {} - - legal_vulns = valid_vulns & vulns - vulns.each do |vuln| + legal_vulns = all_vulns.clone + want_vulns.each do |vulnerability_query| + # select based on selected type, access, cve... - if vuln.type == "" - random = valid_vulns.sample - # valid vulnerability into a new hash map of vulnerabilities - new_vulns[random.id] = random - else - has_found = false - # shuffle randomly selects first match of ftp or nfs and then abandon - legal_vulns.shuffle.each do |valid| - if vuln.type == valid.type - vuln.puppets = valid.puppets unless not vuln.puppets.empty? - vuln.ports = valid.ports unless not vuln.ports.empty? - vuln.cve = valid.cve unless not vuln.cve.empty? - vuln.privilege = valid.privilege unless not vuln.privilege.empty? - vuln.access = valid.access unless not vuln.access.empty? - vuln.details = valid.details - # valid vulnerability into a new hash map of vulnerabilities - new_vulns[vuln.id] = vuln - has_found = true - break - end - end - if not has_found - STDERR.puts "vulnerability was not found please check the xml boxes.xml" - exit - end - end - end - return new_vulns.values - end + # copy vulns array + search_list = legal_vulns.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 - #loop through vulns, fill in missing details if not enough info, choose one at random fill in vulns.. + if search_list.length == 0 + STDERR.puts "Matching vulnerability was not found please check the xml boxes.xml" + STDERR.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) + legal_vulns.delete_if{|x| x.type == vulnerability_query.type} + end + end + return return_vulns.values + end end class Conf @@ -202,15 +280,22 @@ class Conf return @@vulnerabilities = self._get_list(VULN_XML, "//vulnerabilities/vulnerability", Vulnerability) end + def self.services + if defined? @@services + return @@services + end + return @@services = self._get_list(SERVICES_XML, "//services/service", Service) + end + def self._get_list(xmlfile, xpath, cls) itemlist = [] doc = Nokogiri::XML(File.read(xmlfile)) doc.xpath(xpath).each do |item| # new class e.g networks - obj = cls.new + obj = cls.new # checks to see if there are children puppet and add string to obj.puppets - # move this to vulnerabilities class + # move this to vulnerabilities/services classes? if defined? obj.puppets item.xpath("puppets/puppet").each { |c| obj.puppets << c.text.strip if not c.text.strip.empty? } item.xpath("ports/port").each { |c| obj.ports << c.text.strip if not c.text.strip.empty? } @@ -225,4 +310,4 @@ class Conf end return itemlist end -end \ No newline at end of file +end diff --git a/systemreader.rb b/systemreader.rb index ca8788553..4b9d0d103 100644 --- a/systemreader.rb +++ b/systemreader.rb @@ -18,6 +18,7 @@ class SystemReader url = system["url"] vulns = [] networks = [] + services = [] system.css('vulnerabilities vulnerability').each do |v| vulnerability = Vulnerability.new @@ -28,23 +29,37 @@ class SystemReader vulns << vulnerability end + system.css('services service').each do |v| + service = Service.new + service.name = v['name'] + service.details = v['details'] + service.type = v['type'] + services << service + end + system.css('networks network').each do |n| network = Network.new network.name = n['name'] networks << network end - # vulns / networks are passed through to their manager and the program will create valid vulnerabilities / networks - # depending on what the user has specified these two will return valid vulns to be used in vagrant file creation. - new_vulns = VulnerabilityManager.process(vulns, Conf.vulnerabilities) - new_networks = NetworkManager.process(networks, Conf.networks) + + puts "Processing system: " + id + # vulns / networks are passed through to their manager and the program will create valid vulnerabilities / networks + # depending on what the user has specified these two will return valid vulns to be used in vagrant file creation. + new_vulns = VulnerabilityManager.process(vulns, Conf.vulnerabilities) + #puts new_vulns.inspect + + new_networks = NetworkManager.process(networks, Conf.networks) + # pass in the already selected set of vulnerabilities, and additional secure services to find + new_services = ServiceManager.process(services, Conf.services, new_vulns) - s = System.new(id, os, basebox, url, new_vulns, new_networks) - if s.is_valid_base == false - BaseManager.generate_base(s,Conf.bases) - end + s = System.new(id, os, basebox, url, new_vulns, new_networks, new_services) + if s.is_valid_base == false + BaseManager.generate_base(s,Conf.bases) + end - systems << s + systems << s end return systems end -end \ No newline at end of file +end diff --git a/vagrant.rb b/vagrant.rb index a5cc15aaf..5a3b5fbd1 100644 --- a/vagrant.rb +++ b/vagrant.rb @@ -4,8 +4,8 @@ class VagrantController def vagrant_up(build_number) #executes vagrant up from the current build. - p 'building now.....' + puts 'Building now.....' command = "cd #{PROJECTS_DIR}/Project#{build_number}/; vagrant up" exec command end -end \ No newline at end of file +end