mirror of
https://github.com/cliffe/SecGen.git
synced 2026-02-20 13:50:45 +00:00
Superclass for script challenges, ruby and python2 examples
This commit is contained in:
130
lib/objects/local_script_challenge_generator.rb
Normal file
130
lib/objects/local_script_challenge_generator.rb
Normal file
@@ -0,0 +1,130 @@
|
||||
require 'getoptlong'
|
||||
require_relative '../helpers/constants'
|
||||
require 'base64'
|
||||
|
||||
# Inherited by local script challenge generators
|
||||
# stdout used to return value
|
||||
# use Print.local to print status messages (formatted to stdout)
|
||||
|
||||
# A nice side-effect is that each of these modules is also an executable script
|
||||
|
||||
class ScriptChallengeGenerator
|
||||
require_relative '../helpers/print.rb'
|
||||
|
||||
attr_accessor :module_name
|
||||
attr_accessor :has_base64_inputs
|
||||
attr_accessor :outputs
|
||||
|
||||
# override this
|
||||
def initialize
|
||||
# default values
|
||||
self.module_name = 'Null generator'
|
||||
self.has_base64_inputs = false
|
||||
self.outputs = []
|
||||
end
|
||||
|
||||
# override this
|
||||
def generate
|
||||
self.outputs << shebang_line + script_content
|
||||
end
|
||||
|
||||
def read_arguments
|
||||
# Get command line arguments
|
||||
opts = get_options
|
||||
|
||||
# process option arguments
|
||||
opts.each do |opt, arg|
|
||||
# Check if base64 decoding is required and set instance variable
|
||||
if opt == '--b64'
|
||||
self.has_base64_inputs = true
|
||||
end
|
||||
# Decode if required
|
||||
argument = self.has_base64_inputs ? Base64.strict_decode64(arg) : arg
|
||||
process_options(opt, argument)
|
||||
end
|
||||
end
|
||||
|
||||
# Override this when using read_fact's in your module
|
||||
def get_options
|
||||
GetoptLong.new(*get_options_array)
|
||||
end
|
||||
|
||||
def get_options_array
|
||||
[['--help', '-h', GetoptLong::NO_ARGUMENT],
|
||||
['--b64', GetoptLong::OPTIONAL_ARGUMENT]]
|
||||
end
|
||||
|
||||
# Override this when using read_fact's in your module. Always call super first
|
||||
def process_options(opt, arg)
|
||||
unless option_is_valid(opt)
|
||||
Print.err "Argument not valid: #{arg}"
|
||||
usage
|
||||
exit
|
||||
end
|
||||
|
||||
case opt
|
||||
when '--help'
|
||||
usage
|
||||
when '--b64'
|
||||
# do nothing
|
||||
end
|
||||
end
|
||||
|
||||
def usage
|
||||
Print.err "Usage:
|
||||
#{$0} [--options]
|
||||
"
|
||||
exit
|
||||
end
|
||||
|
||||
def run
|
||||
Print.local module_name
|
||||
|
||||
read_arguments
|
||||
|
||||
Print.local_verbose "Generating..."
|
||||
generate
|
||||
|
||||
# print the first 1000 chars to screen
|
||||
output = self.outputs.to_s
|
||||
length = output.length
|
||||
if length < 1000
|
||||
Print.local_verbose "Generated: #{output}..."
|
||||
else
|
||||
Print.local_verbose "Generated: #{output.to_s[0..1000]}..."
|
||||
Print.local_verbose "(Displaying 1000/#{length} length output)"
|
||||
end
|
||||
|
||||
puts has_base64_inputs ? base64_encode_outputs : self.outputs
|
||||
end
|
||||
|
||||
def base64_encode_outputs
|
||||
self.outputs.map { |o| Base64.strict_encode64 o }
|
||||
end
|
||||
|
||||
def option_is_valid(opt_to_check)
|
||||
arg_validity = false
|
||||
valid_arguments = get_options_array
|
||||
valid_arguments.each{ |valid_arg_array|
|
||||
valid_arg_array.each_with_index { |valid_arg|
|
||||
if valid_arg == opt_to_check
|
||||
arg_validity = true
|
||||
end
|
||||
}
|
||||
}
|
||||
arg_validity
|
||||
end
|
||||
|
||||
def script_content
|
||||
# override me with script content
|
||||
end
|
||||
|
||||
def interpreter_path
|
||||
# override me with a string containing the interpreter path e.g. "/bin/bash"
|
||||
end
|
||||
|
||||
def shebang_line
|
||||
"#!/usr/local/bin/suid #{interpreter_path} --\n"
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
#!/usr/bin/ruby
|
||||
|
||||
require_relative '../../../../../../../lib/objects/local_script_challenge_generator.rb'
|
||||
class RubyExampleScriptGenerator < ScriptChallengeGenerator
|
||||
|
||||
def initialize
|
||||
super
|
||||
self.module_name = 'Python Example Script Generator'
|
||||
end
|
||||
|
||||
|
||||
def interpreter_path
|
||||
'/usr/bin/python'
|
||||
end
|
||||
|
||||
def script_content
|
||||
"from sys import argv
|
||||
with open('flag') as f:
|
||||
print f.read()"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
RubyExampleScriptGenerator.new.run
|
||||
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<generator xmlns="http://www.github/cliffe/SecGen/generator"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.github/cliffe/SecGen/generator">
|
||||
<name>Ruby Example Challenge Generator</name>
|
||||
<author>Thomas Shaw</author>
|
||||
<module_license>MIT</module_license>
|
||||
<description>TODO</description>
|
||||
|
||||
<type>python2_script_challenge</type>
|
||||
|
||||
<platform>linux</platform>
|
||||
<platform>windows</platform>
|
||||
|
||||
<output_type>script</output_type>
|
||||
|
||||
</generator>
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/ruby
|
||||
|
||||
require_relative '../../../../../../../lib/objects/local_string_generator.rb'
|
||||
class RubyExampleScriptGenerator < StringGenerator
|
||||
require_relative '../../../../../../../lib/objects/local_script_challenge_generator.rb'
|
||||
class RubyExampleScriptGenerator < ScriptChallengeGenerator
|
||||
|
||||
def initialize
|
||||
super
|
||||
@@ -9,9 +9,12 @@ class RubyExampleScriptGenerator < StringGenerator
|
||||
end
|
||||
|
||||
|
||||
def generate
|
||||
self.outputs << "#!/usr/local/bin/suid /usr/bin/ruby --
|
||||
puts File.read('flag')"
|
||||
def interpreter_path
|
||||
'/usr/bin/ruby'
|
||||
end
|
||||
|
||||
def script_content
|
||||
"puts File.read('flag')"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
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'],
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
include python2_challenge_example::install
|
||||
@@ -0,0 +1,61 @@
|
||||
<?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>ctf_challenge</type>
|
||||
<type>script_challenge</type>
|
||||
<privilege>none</privilege>
|
||||
<access>local</access>
|
||||
<platform>linux</platform>
|
||||
|
||||
<!-- 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/python</module_path>
|
||||
</requires>
|
||||
|
||||
</vulnerability>
|
||||
Reference in New Issue
Block a user