mirror of
https://github.com/cliffe/SecGen.git
synced 2026-02-21 11:18:06 +00:00
datastores for storing and reusing calculated values
This commit is contained in:
@@ -1,3 +1,6 @@
|
||||
# ONE global variable
|
||||
$datastore = {}
|
||||
|
||||
## FILE / DIR CONSTANTS ##
|
||||
|
||||
# Root directory of SecGen file structure
|
||||
|
||||
@@ -12,10 +12,12 @@ class Module
|
||||
# XML validity ensures valid and complete information.
|
||||
|
||||
attr_accessor :write_to_module_with_id # the module instance that this module writes to
|
||||
attr_accessor :write_to_datastore # the datastore to store the result to
|
||||
attr_accessor :write_output_variable # the variable/fact written to
|
||||
attr_accessor :output # the result of local processing
|
||||
attr_accessor :unique_id # the unique id for this module *instance*
|
||||
attr_accessor :received_inputs # any locally calculated inputs fed into this module instance
|
||||
attr_accessor :received_datastores # any datastores to be fed into this module instance
|
||||
|
||||
attr_accessor :conflicts
|
||||
attr_accessor :requires
|
||||
@@ -35,6 +37,7 @@ class Module
|
||||
self.output = []
|
||||
self.write_to_module_with_id = write_output_variable = ''
|
||||
self.received_inputs = {}
|
||||
self.received_datastores = {}
|
||||
self.default_inputs_selectors = {}
|
||||
self.default_inputs_literals = {}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ class System
|
||||
|
||||
# for each module specified in the scenario
|
||||
module_selectors.each do |module_filter|
|
||||
selected_modules += select_modules(module_filter.module_type, module_filter.attributes, available_modules, selected_modules, module_filter.unique_id, module_filter.write_output_variable, module_filter.write_to_module_with_id, module_filter.received_inputs, module_filter.default_inputs_literals)
|
||||
selected_modules += select_modules(module_filter.module_type, module_filter.attributes, available_modules, selected_modules, module_filter.unique_id, module_filter.write_output_variable, module_filter.write_to_module_with_id, module_filter.received_inputs, module_filter.default_inputs_literals, module_filter.write_to_datastore, module_filter.received_datastores)
|
||||
end
|
||||
selected_modules
|
||||
|
||||
@@ -64,7 +64,7 @@ class System
|
||||
# returns a list containing a module (plus any default input modules and dependencies recursively) of the module type with the required attributes
|
||||
# modules are selected from the list of available modules and will be checked against previously selected modules for conflicts
|
||||
# raises an exception when unable to resolve and the retry limit has not been reached
|
||||
def select_modules(module_type, required_attributes, available_modules, previously_selected_modules, unique_id, write_outputs_to, write_to_module_with_id, received_inputs, default_inputs_literals)
|
||||
def select_modules(module_type, required_attributes, available_modules, previously_selected_modules, unique_id, write_outputs_to, write_to_module_with_id, received_inputs, default_inputs_literals, write_to_datastore, received_datastores)
|
||||
default_modules_to_add = []
|
||||
|
||||
search_list = available_modules.clone
|
||||
@@ -101,10 +101,23 @@ class System
|
||||
# propagate module relationships established when the filter was created
|
||||
selected.write_output_variable = write_outputs_to
|
||||
selected.write_to_module_with_id = write_to_module_with_id
|
||||
selected.write_to_datastore = write_to_datastore
|
||||
selected.unique_id = unique_id
|
||||
selected.received_inputs = received_inputs
|
||||
selected.received_datastores = received_datastores
|
||||
selected.default_inputs_literals = selected.default_inputs_literals.merge(default_inputs_literals)
|
||||
|
||||
# feed in input from any received datastores
|
||||
if selected.received_datastores != {}
|
||||
Print.verbose "Receiving datastores: #{selected.received_datastores}"
|
||||
selected.received_datastores.each do |input_key, datastore_value|
|
||||
datastore_value.each do |datastore|
|
||||
(received_inputs[input_key] ||=[]).push(*$datastore[datastore])
|
||||
Print.verbose "Adding #{input_key} - #{datastore} (#{$datastore[datastore]})"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# if no input received from the scenario, apply default input values/modules
|
||||
default_modules_to_add += select_default_modules(selected, available_modules, previously_selected_modules + [selected])
|
||||
|
||||
@@ -131,6 +144,12 @@ class System
|
||||
selected.output = JSON.parse(`ruby #{selected.local_calc_file} #{args_string}`.chomp)
|
||||
end
|
||||
|
||||
# store the output of the module into a datastore, if specified
|
||||
if selected.write_to_datastore && selected.write_to_datastore.size != 0
|
||||
($datastore[selected.write_to_datastore] ||=[]).push(*selected.output)
|
||||
Print.verbose "Storing into datastore: #{selected.write_to_datastore} = #{$datastore[selected.write_to_datastore].to_s}"
|
||||
end
|
||||
|
||||
# add any modules that the selected module requires
|
||||
dependencies = select_required_modules(selected, available_modules, previously_selected_modules + default_modules_to_add + [selected])
|
||||
end
|
||||
@@ -178,7 +197,7 @@ class System
|
||||
default_module_selectors_to_add.each do |module_to_add|
|
||||
module_to_add.write_to_module_with_id = selected.unique_id
|
||||
|
||||
default_modules_to_add.concat select_modules(module_to_add.module_type, module_to_add.attributes, available_modules, previously_selected_modules + default_modules_to_add, module_to_add.unique_id, module_to_add.write_output_variable, module_to_add.write_to_module_with_id, module_to_add.received_inputs, module_to_add.default_inputs_literals)
|
||||
default_modules_to_add.concat select_modules(module_to_add.module_type, module_to_add.attributes, available_modules, previously_selected_modules + default_modules_to_add, module_to_add.unique_id, module_to_add.write_output_variable, module_to_add.write_to_module_with_id, module_to_add.received_inputs, module_to_add.default_inputs_literals, module_to_add.write_to_datastore, module_to_add.received_datastores)
|
||||
end
|
||||
end
|
||||
else
|
||||
@@ -230,7 +249,7 @@ class System
|
||||
Print.verbose "Dependency satisfied by previously selected module: #{existing.printable_name}"
|
||||
else
|
||||
Print.verbose 'Adding required modules...'
|
||||
modules_to_add += select_modules('any', required, available_modules, modules_to_add + selected_modules, '', '', '', {}, {})
|
||||
modules_to_add += select_modules('any', required, available_modules, modules_to_add + selected_modules, '', '', '', {}, {}, {}, {})
|
||||
end
|
||||
end
|
||||
modules_to_add
|
||||
|
||||
@@ -50,6 +50,19 @@ class SystemReader
|
||||
system_attributes["#{attr.name}"] = attr.text unless attr.text.nil? || attr.text == ''
|
||||
end
|
||||
|
||||
# literal values to store directly in a datastore
|
||||
system_node.xpath('*[@into_datastore]/value').each do |value|
|
||||
name = value.xpath('../@into_datastore').to_s
|
||||
($datastore[name] ||= []).push(value.text)
|
||||
end
|
||||
|
||||
# datastore in a datastore
|
||||
if system_node.xpath('//*[@into_datastore]/datastore').to_s != ""
|
||||
Print.err "WARNING: a datastore cannot capture the values from another datastore (this will be ignored)"
|
||||
Print.err "The scenario has datastore(s) that try to save directly into another datastore -- currently this is only possible via an encoder"
|
||||
sleep 2
|
||||
end
|
||||
|
||||
# for each module selection
|
||||
system_node.xpath('//vulnerability | //service | //utility | //network | //base | //encoder | //generator').each do |module_node|
|
||||
# create a selector module, which is a regular module instance used as a placeholder for matching requirements
|
||||
@@ -60,10 +73,18 @@ class SystemReader
|
||||
# check if we need to be sending the module output to another module
|
||||
module_node.xpath('parent::input').each do |input|
|
||||
# Parent is input -- track that we need to send write value somewhere
|
||||
input.xpath('..').each do |input_parent|
|
||||
module_selector.write_output_variable = input.xpath('@into').to_s
|
||||
module_selector.write_to_module_with_id = input_parent.path.gsub(/[^a-zA-Z0-9]/, '')
|
||||
# if we need to feed results to parent module
|
||||
if input.xpath('@into').to_s
|
||||
input.xpath('..').each do |input_parent|
|
||||
module_selector.write_output_variable = input.xpath('@into').to_s
|
||||
module_selector.write_to_module_with_id = input_parent.path.gsub(/[^a-zA-Z0-9]/, '')
|
||||
end
|
||||
end
|
||||
# check if we need to send the module output to a datastore
|
||||
if input.xpath('@into_datastore').to_s
|
||||
module_selector.write_to_datastore = input.xpath('@into_datastore').to_s
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# check if we are being passed an input *literal value*
|
||||
@@ -74,6 +95,14 @@ class SystemReader
|
||||
(module_selector.received_inputs[variable] ||= []).push(value)
|
||||
end
|
||||
|
||||
# check if we are being passed a datastore as input
|
||||
module_node.xpath('input/datastore').each do |input_value|
|
||||
variable = input_value.xpath('../@into').to_s
|
||||
value = input_value.text
|
||||
Print.verbose " -- datastore: #{variable} = #{value}"
|
||||
(module_selector.received_datastores[variable] ||= []).push(value)
|
||||
end
|
||||
|
||||
|
||||
module_node.xpath('@*').each do |attr|
|
||||
module_selector.attributes["#{attr.name}"] = [attr.text] unless attr.text.nil? || attr.text == ''
|
||||
|
||||
@@ -21,9 +21,11 @@
|
||||
<xs:element name='generator' type='ServiceUtilityEncoderGeneratorType' minOccurs='0' maxOccurs='unbounded' />
|
||||
<xs:element name='encoder' type='ServiceUtilityEncoderGeneratorType' minOccurs='0' maxOccurs='unbounded' />
|
||||
<xs:element name='value' type='xs:string' minOccurs='0' maxOccurs='unbounded' />
|
||||
<xs:element name='datastore' type='xs:string' minOccurs='0' maxOccurs='unbounded' />
|
||||
</xs:choice>
|
||||
</xs:sequence>
|
||||
<xs:attribute name='into' type='xs:string'/>
|
||||
<xs:attribute name='into_datastore' type='xs:string'/>
|
||||
|
||||
</xs:complexType>
|
||||
<xs:complexType name="SystemType">
|
||||
@@ -37,6 +39,7 @@
|
||||
</xs:element>
|
||||
<xs:element name='base' type='BaseType' minOccurs='1' maxOccurs='1' />
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="input" type="InputElements" minOccurs="0" maxOccurs="unbounded" />
|
||||
<xs:element name='vulnerability' type='VulnerabilityType' minOccurs='0' maxOccurs='unbounded' />
|
||||
<xs:element name='service' type='ServiceUtilityEncoderGeneratorType' minOccurs='0' maxOccurs='unbounded' />
|
||||
<xs:element name='utility' type='ServiceUtilityEncoderGeneratorType' minOccurs='0' maxOccurs='unbounded' />
|
||||
|
||||
@@ -33,6 +33,9 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
|
||||
end %>
|
||||
end
|
||||
|
||||
# SecGen datastore
|
||||
# <%= JSON.generate($datastore) %>
|
||||
|
||||
# SecGen modules
|
||||
<% system.module_selections.each do |selected_module| -%>
|
||||
|
||||
|
||||
27
scenarios/datastore_examples/example.xml
Normal file
27
scenarios/datastore_examples/example.xml
Normal file
@@ -0,0 +1,27 @@
|
||||
<?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>example_server</system_name>
|
||||
<base platform="linux"/>
|
||||
|
||||
<input into_datastore="business_name">
|
||||
<value>BusinessName1</value>
|
||||
</input>
|
||||
|
||||
<!--select a vulnerability that leaks strings-->
|
||||
<vulnerability read_fact="strings_to_leak">
|
||||
<!--direct the output from below into strings_to_leak-->
|
||||
<input into="strings_to_leak" into_datastore="flags">
|
||||
<datastore>business_name</datastore>
|
||||
<generator type="flag_generator" />
|
||||
</input>
|
||||
</vulnerability>
|
||||
|
||||
<network type="private_network" range="dhcp"/>
|
||||
</system>
|
||||
|
||||
</scenario>
|
||||
33
scenarios/datastore_examples/precalculate_strings.xml
Normal file
33
scenarios/datastore_examples/precalculate_strings.xml
Normal file
@@ -0,0 +1,33 @@
|
||||
<?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>example_server</system_name>
|
||||
<base platform="linux"/>
|
||||
|
||||
<input into_datastore="business_name">
|
||||
<value>BusinessName1</value>
|
||||
</input>
|
||||
<input into_datastore="username">
|
||||
<generator type="username_generator" />
|
||||
<generator type="username_generator" />
|
||||
<value>cliffe</value>
|
||||
</input>
|
||||
|
||||
<!--select a vulnerability that leaks strings-->
|
||||
<vulnerability read_fact="strings_to_leak">
|
||||
<!--direct the output from below into strings_to_leak-->
|
||||
<input into="strings_to_leak" into_datastore="flags">
|
||||
<datastore>business_name</datastore>
|
||||
<datastore>username</datastore>
|
||||
<generator type="flag_generator" />
|
||||
</input>
|
||||
</vulnerability>
|
||||
|
||||
<network type="private_network" range="dhcp"/>
|
||||
</system>
|
||||
|
||||
</scenario>
|
||||
32
scenarios/datastore_examples/store_flags.xml
Normal file
32
scenarios/datastore_examples/store_flags.xml
Normal file
@@ -0,0 +1,32 @@
|
||||
<?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>example_server</system_name>
|
||||
<base platform="linux"/>
|
||||
|
||||
<!--select a vulnerability that leaks strings-->
|
||||
<vulnerability read_fact="strings_to_leak">
|
||||
<!--direct the output from below into strings_to_leak-->
|
||||
<input into="strings_to_leak" into_datastore="flags">
|
||||
<generator type="flag_generator" />
|
||||
<generator type="flag_generator" />
|
||||
</input>
|
||||
</vulnerability>
|
||||
|
||||
<!--select a vulnerability that leaks strings-->
|
||||
<vulnerability read_fact="strings_to_leak">
|
||||
<!--direct the output from below into strings_to_leak-->
|
||||
<input into="strings_to_leak" into_datastore="flags">
|
||||
<generator type="flag_generator" />
|
||||
<generator type="flag_generator" />
|
||||
</input>
|
||||
</vulnerability>
|
||||
|
||||
<network type="private_network" range="dhcp"/>
|
||||
</system>
|
||||
|
||||
</scenario>
|
||||
Reference in New Issue
Block a user