Install setgid binary

This commit is contained in:
ts
2018-08-01 18:46:31 +01:00
parent 772ed43f0f
commit 45e5ad0646
13 changed files with 777 additions and 1 deletions

View File

@@ -0,0 +1,104 @@
# Install function for setuid_root binaries
# -- Modules calling this function must provide a Makefile and any .c files within it's <module_name>/files directory
#
# ** NOTES ***
# Do we really need a user account or can we just pass in the directory path?
#
define secgen_functions::install_setgid_binary (
$challenge_name, # Challenge name, used for the wrapper-directory
$source_module_name, # Name of the module that calls this function
$group, # Name of group
$account, # User account
$flag, # ctf flag string
$flag_name, # ctf flag name
$storage_dir = '', # Optional: Storage directory (takes precedent if supplied, e.g. nfs / smb share dir)
$strings_to_leak = [''], # Optional: strings to leak (could contain instructions or a message)
) {
if $account {
$username = $account['username']
::accounts::user { $username:
shell => '/bin/bash',
password => pw_hash($account['password'], 'SHA-512', 'mysalt'),
managehome => true,
home_mode => '0755',
}
$storage_directory = "/home/$username"
} elsif $storage_dir {
$storage_directory = $storage_dir
} else {
err('install: either account or storage_dir is required')
fail
}
$compile_directory = "$storage_directory/tmp"
$challenge_directory = "$storage_directory/$challenge_name"
$modules_source = "puppet:///modules/$source_module_name"
notice("compile_directory: ")
notice($compile_directory)
notice("challenge_directory: ")
notice($challenge_directory)
group { $group:
ensure => present,
}
# Create challenge directory
file { "create_$challenge_directory":
path => $challenge_directory,
ensure => directory,
}
# Move contents of the module's files directory into compile directory
file { "create_$compile_directory":
path => $compile_directory,
ensure => directory,
recurse => true,
source => $modules_source,
}
# Build the binary with gcc
exec { "gcc_$challenge_name-$compile_directory":
cwd => $compile_directory,
command => "/usr/bin/make",
require => File["create_$challenge_directory", "create_$compile_directory"]
}
# Move the compiled binary into the challenge directory
file { "$challenge_directory/$challenge_name":
ensure => present,
owner => 'root',
group => $group,
mode => '4771',
source => "$compile_directory/$challenge_name",
require => Exec["gcc_$challenge_name-$compile_directory"],
}
# Drop the flag file on the box and set permissions
::secgen_functions::leak_files { "$username-file-leak":
storage_directory => "$challenge_directory",
leaked_filenames => [$flag_name],
strings_to_leak => [$flag],
owner => 'root',
group => $group,
mode => '4440',
leaked_from => "accounts_$username",
require => [Group[$group], Exec["gcc_$challenge_name-$compile_directory"]],
notify => Exec["remove_$compile_directory"],
}
# Remove compile directory
exec { "remove_$compile_directory":
command => "/bin/rm -rf $compile_directory",
require => [File["$challenge_directory/$challenge_name"]]
}
}

View File

@@ -31,7 +31,7 @@ define secgen_functions::install_setuid_root_binary (
home_mode => '0755',
}
} else {
err('dc16_amadhj::install: Either storage_directory or account is required')
err('install: Either storage_directory or account is required')
fail
}

View File

@@ -0,0 +1 @@
include dc16_amadhj_group::install

View File

@@ -0,0 +1,3 @@
all:
gcc amadhj.c -o amadhj --static -s

View File

@@ -0,0 +1,445 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <fcntl.h>
uint64_t exp_l( uint64_t base, uint64_t power)
{
int i = 0;
uint64_t j = base;
if ( power == 0 ) {
return 1;
}
for ( i = 0; i < power-1; i++) {
j *= base;
}
return j;
}
uint64_t xor( uint64_t a, uint64_t b)
{
return a ^ b;
}
uint64_t shla( uint64_t a, uint64_t dabits)
{
uint64_t high = 0;
uint64_t low = 0;
dabits = dabits % 64;
if ( dabits == 0 ) {
return a;
}
high = a << dabits;
low = a >> (64-dabits);
return high | low;
}
uint64_t shra( uint64_t a, uint64_t dabits)
{
uint64_t high = 0;
uint64_t low = 0;
dabits = dabits % 64;
if ( dabits == 0 ) {
return a;
}
low = a >> dabits;
high = a << (64-dabits);
return high | low;
}
/*
0 1 2 3 4 5 6 7
5 0 4 6 7 3 1 2
*/
uint64_t swap_bytes( uint64_t value)
{
uint64_t final = 0;
final |= ( (value & 0xff) << 24);
final |= ( (value & 0xff00) << 24);
final |= ( (value & 0xff0000) << 40);
final |= ( (value & 0xff000000) << 16);
final |= ( (value & 0xff00000000) >> 16);
final |= ( (value & 0xff0000000000) >> 40);
final |= ( (value & 0xff000000000000) >> 40);
final |= ( (value & 0xff00000000000000) >> 8);
return final;
}
uint64_t swap_two( uint64_t value, uint64_t one, uint64_t two)
{
uint64_t t_one = 0;
uint64_t t_two = 0;
uint64_t mask_one = 0xff;
uint64_t mask_two = 0xff;
mask_one <<= one*8;
mask_two <<= two*8;
mask_one ^= 0xffffffffffffffff;
mask_two ^= 0xffffffffffffffff;
t_one = (value >> (one*8)) & 0xff;
t_two = (value >> (two*8)) & 0xff;
/// Clear the bits
value &= (mask_one & mask_two);
value |= (t_two << ( one*8));
value |= (t_one << ( two*8));
return value;
}
uint64_t xor_neighbor( uint64_t value)
{
int i = 0;
uint64_t t = 0;
t |= ((value & 0xff00000000000000) >> 8) ^ (value & 0xff000000000000);
t |= ((value & 0xff000000000000) >> 8) ^ (value & 0xff0000000000);
t |= ((value & 0xff0000000000) >> 8) ^ (value & 0xff00000000);
t |= ((value & 0xff00000000) >> 8) ^ (value & 0xff000000);
t |= ((value & 0xff000000) >> 8) ^ (value & 0xff0000);
t |= ((value & 0xff0000) >> 8) ^ (value & 0xff00);
t |= ((value & 0xff00) >> 8) ^ (value & 0xff);
t |= ((value & 0xff) << 56) ^ (value & 0xff00000000000000);
return t;
}
uint64_t munge_one( uint64_t value )
{
value = xor( value, 0x35966a685c73335a);
value = swap_two( value, 2, 0);
value = xor( value, 0x89fdaf6604952df1);
value = xor( value, 0xe9f30f0ce704876a);
value = swap_two( value, 2, 3);
value = xor( value, 0xbdc5026d3c0b56e6);
value = shla( value, 16);
value = shla( value, 35);
value = shra( value, 19);
value = xor_neighbor( value );
value = shla( value, 36);
value = shra( value, 40);
value = swap_two( value, 1, 0);
value = xor( value, 0x5de229fb3804db17);
value = swap_bytes( value );
value = swap_bytes( value );
value = swap_two( value, 2, 1);
value = xor( value, 0x6aad877366e921f5);
value = swap_two( value, 3, 0);
value = swap_bytes( value );
value = xor( value, 0x58d83e9d5e6d5083);
value = shra( value, 22);
value = xor_neighbor( value );
value = xor( value, 0x47b4d980070a9b73);
value = xor_neighbor( value );
value = xor_neighbor( value );
value = swap_two( value, 6, 5);
value = shla( value, 59);
value = swap_two( value, 5, 2);
value = swap_two( value, 2, 3);
value = shla( value, 12);
value = xor( value, 0xad25307f8e364b17);
value = xor( value, 0x48a56d5afe0da4c2);
value = shla( value, 6);
value = swap_two( value, 6, 5);
value = shra( value, 11);
value = swap_bytes( value );
value = xor( value, 0x869365db4c9f3cb6);
value = swap_bytes( value );
value = shra( value, 2);
value = xor( value, 0x4085aa8c0693425b);
value = shla( value, 35);
value = shla( value, 9);
value = xor_neighbor( value );
value = shla( value, 7);
value = shla( value, 38);
value = xor_neighbor( value );
value = xor( value, 0xdef2d72447ef4e1b);
value = swap_bytes( value );
value = swap_bytes( value );
value = swap_two( value, 2, 7);
value = shra( value, 51);
value = swap_bytes( value );
value = shra( value, 19);
value = xor( value, 0x95de49591a44ee21);
value = xor_neighbor( value );
value = swap_bytes( value );
value = shra( value, 16);
return value;
}
uint64_t munge_two( uint64_t value )
{
value = shla( value, 22);
value = swap_bytes( value );
value = swap_two( value, 4, 1);
value = swap_bytes( value );
value = xor_neighbor( value );
value = shla( value, 35);
value = swap_two( value, 2, 6);
value = xor( value, 0x80a9ea4f90944fea);
value = shla( value, 3);
value = swap_two( value, 0, 1);
value = swap_two( value, 1, 2);
value = swap_bytes( value );
value = xor_neighbor( value );
value = swap_two( value, 5, 1);
value = shra( value, 24);
value = shla( value, 39);
value = swap_two( value, 2, 4);
value = xor( value, 0x678e70a16230a437);
value = swap_two( value, 4, 3);
value = swap_two( value, 0, 7);
value = shla( value, 62);
value = swap_bytes( value );
value = swap_two( value, 7, 6);
value = swap_two( value, 2, 6);
value = swap_bytes( value );
value = xor_neighbor( value );
value = swap_two( value, 5, 2);
value = xor_neighbor( value );
value = swap_two( value, 1, 7);
value = xor( value, 0x41ea5cf418a918e7);
value = swap_bytes( value );
value = xor_neighbor( value );
value = swap_two( value, 1, 4);
value = shla( value, 10);
value = swap_bytes( value );
value = swap_bytes( value );
value = shra( value, 24);
value = swap_two( value, 0, 4);
value = shra( value, 61);
value = swap_two( value, 3, 4);
value = shra( value, 35);
value = shla( value, 55);
value = shla( value, 34);
value = xor_neighbor( value );
value = xor_neighbor( value );
value = shra( value, 23);
value = shla( value, 59);
value = shra( value, 20);
value = shla( value, 28);
value = xor( value, 0xc26499379c0927cd);
value = xor_neighbor( value );
value = shra( value, 13);
return value;
}
uint64_t munge_three( uint64_t value )
{
value = shla( value, 18);
value = shla( value, 29);
value = swap_two( value, 5, 3);
value = swap_two( value, 0, 7);
value = shla( value, 18);
value = xor( value, 0xc9ab604bb92038ad);
value = shra( value, 33);
value = swap_two( value, 0, 4);
value = xor_neighbor( value );
value = swap_two( value, 6, 2);
value = shra( value, 13);
value = shra( value, 20);
value = xor( value, 0x58609be21eb37866);
value = xor_neighbor( value );
value = swap_bytes( value );
value = shra( value, 46);
value = swap_two( value, 2, 3);
value = shra( value, 44);
value = shra( value, 3);
value = swap_two( value, 4, 3);
value = xor_neighbor( value );
value = swap_two( value, 7, 6);
value = shra( value, 59);
value = shra( value, 38);
value = swap_bytes( value );
value = swap_two( value, 1, 5);
value = swap_bytes( value );
value = shla( value, 27);
value = xor( value, 0xbed577a97eb7966f);
value = shra( value, 14);
value = shla( value, 7);
value = shla( value, 18);
value = shla( value, 57);
value = xor( value, 0xb44427be7889c31b);
value = xor( value, 0xce745c65abecb66);
value = xor( value, 0x94b1608adb7f7221);
value = xor( value, 0x85bef139817ebc4a);
value = swap_two( value, 5, 1);
value = shla( value, 20);
value = shla( value, 24);
value = shra( value, 46);
value = shra( value, 13);
value = xor( value, 0xc95e5c35034b9775);
value = shla( value, 7);
value = xor( value, 0x8e60900383fa5ea);
value = xor( value, 0x59d5bcbf8b0cc9fd);
value = xor_neighbor( value );
value = swap_two( value, 4, 7);
value = xor_neighbor( value );
value = shra( value, 22);
value = shra( value, 50);
value = xor_neighbor( value );
return value;
}
uint64_t munge_four( uint64_t value )
{
value = swap_two( value, 1, 7);
value = shla( value, 6);
value = swap_two( value, 2, 5);
value = shra( value, 57);
value = xor( value, 0xc852fa4047662ce);
value = swap_two( value, 5, 1);
value = shla( value, 1);
value = xor_neighbor( value );
value = xor( value, 0x5ddfc2422c2a449e);
value = xor_neighbor( value );
value = shla( value, 6);
value = xor_neighbor( value );
value = shla( value, 33);
value = shra( value, 25);
value = xor_neighbor( value );
value = xor( value, 0xa94a4c87a942c60);
value = swap_two( value, 6, 2);
value = xor_neighbor( value );
value = xor( value, 0xcc508fa31a0da5ab);
value = xor( value, 0x880218b9f910dcbc);
value = xor_neighbor( value );
value = xor( value, 0x85d7e666ecdba611);
value = shra( value, 8);
value = shra( value, 43);
value = xor( value, 0x633a915bd59ac97b);
value = swap_two( value, 3, 1);
value = swap_two( value, 5, 7);
value = swap_bytes( value );
value = xor_neighbor( value );
value = shra( value, 59);
value = shra( value, 10);
value = xor_neighbor( value );
value = swap_two( value, 2, 1);
value = swap_two( value, 7, 2);
value = xor_neighbor( value );
value = xor( value, 0x648fff323d235735);
value = xor( value, 0xfc9f8d635fd85eb3);
value = xor( value, 0xff651571c16e5cb3);
value = swap_two( value, 2, 4);
value = swap_two( value, 5, 4);
value = shra( value, 11);
value = xor_neighbor( value );
value = shla( value, 39);
value = swap_bytes( value );
value = xor_neighbor( value );
value = xor( value, 0xc798d4e5c0e97b1c);
value = swap_bytes( value );
value = xor_neighbor( value );
value = shla( value, 35);
value = swap_two( value, 3, 5);
value = xor_neighbor( value );
value = swap_bytes( value );
value = xor_neighbor( value );
return value;
}
int munge_all( unsigned char *data )
{
int i = 0;
uint64_t *base = NULL;
uint64_t one;
uint64_t two;
uint64_t thr;
uint64_t fou;
read( 0, data, 32);
for ( i = 0; i < 32; i++ ) {
if ( ((data[i] < 0x41) || ( 0x7a < data[i])) && (data[i] != 0x20) ) {
return 0;
} else if ( data[i] == ']') {
return 0;
} else if ( data[i] == '\\') {
return 0;
} else if ( data[i] == '^') {
return 0;
} else if ( data[i] == '`') {
return 0;
} else if ( data[i] == '[') {
return 0;
}
}
base = (uint64_t*)data;
one = munge_one( base[0]);
two = munge_two( base[1]);
thr = munge_three( base[2]);
fou = munge_four( base[3]);
one = one^two^thr^fou;
if ( one == 0xb101124831c0110a) {
return 1;
}
return 0;
}
void printflag()
{
int fd;
int len;
unsigned char data[128];
fd = open("flag", O_RDONLY);
if ( fd <= 0 ) {
printf("Failed to open flag.\n");
return;
}
len = lseek( fd, 0, SEEK_END);
lseek(fd, 0, SEEK_SET);
if ( len > 128 ) {
len = 128;
}
memset(data, 0, 128);
read( fd, data, len);
close(fd);
printf("%s\n", data);
return;
}
int main(int argc, char**argv)
{
int fd;
unsigned char data[32];
bzero( data, 32 );
if ( munge_all( data ) ) {
printflag();
}
return 0;
}

View File

@@ -0,0 +1,22 @@
class dc16_amadhj_group::install {
$secgen_params = secgen_functions::get_parameters($::base64_inputs_file)
if $secgen_params['account'][0] != ''{
$account = parsejson($secgen_params['account'][0])
} else {
$account = undef
}
notice("account: ")
notice($account)
::secgen_functions::install_setgid_binary { 'defcon16_amadhj_group':
source_module_name => 'dc16_amadhj_group',
challenge_name => $secgen_params['challenge_name'][0],
group => $secgen_params['group'][0],
account => $account,
flag => $secgen_params['flag'][0],
flag_name => 'flag',
storage_dir => $secgen_params['storage_directory'][0],
strings_to_leak => $secgen_params['strings_to_leak'],
}
}

View File

@@ -0,0 +1,50 @@
<?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>DefCon Quals 2016 - amadhj</name>
<author>Thomas Shaw</author>
<module_license>MIT</module_license>
<description>Binary Reverse Engineering CTF Challenge from the Defcon 2016 CTF Qualifier.</description>
<type>ctf_challenge</type>
<type>reverse_engineering</type>
<privilege>none</privilege>
<access>local</access>
<platform>linux</platform>
<!-- binary dropped in account's home directory by default. -->
<read_fact>challenge_name</read_fact>
<read_fact>group</read_fact>
<read_fact>account</read_fact>
<read_fact>flag</read_fact>
<read_fact>strings_to_leak</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>
<default_input into="challenge_name">
<value>amadhj</value>
</default_input>
<default_input into="group">
<value>test</value>
</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>
</vulnerability>

View File

@@ -0,0 +1 @@
require ruby_script_container::init

View File

@@ -0,0 +1,42 @@
define ruby_script_container::account($username, $group, $password, $strings_to_leak, $leaked_filenames) {
group { $group:
ensure => present,
}
::accounts::user { $username:
shell => '/bin/bash',
password => pw_hash($password, 'SHA-512', 'mysalt'),
managehome => true,
home_mode => '0755',
groups => [$group],
require => Group[$group],
}
# strings_to_leak[0]: flag in /home/<username>/flag.txt
::secgen_functions::leak_files { "$username-file-leak":
storage_directory => "/home/$username/",
leaked_filenames => $leaked_filenames,
strings_to_leak => [$strings_to_leak[0]],
owner => $username,
group => $group,
mode => '2440',
leaked_from => "accounts_$username",
require => Group[$group],
}
file { "/home/$username/test.rb":
owner => $username,
group => $group,
mode => '2777',
ensure => file,
content => template('ruby_script_container/template.rb.erb'),
require => Group[$group],
}
# exec { "$username-compileandsetup1":
# cwd => "/home/$username/",
# command => "sudo chown $username:shadow prompt && sudo chmod 2755 prompt",
# path => [ '/bin/', '/sbin/' , '/usr/bin/', '/usr/sbin/' ],
# }
}

View File

@@ -0,0 +1,25 @@
class ruby_script_container::init {
$secgen_parameters = secgen_functions::get_parameters($::base64_inputs_file)
$group = $secgen_parameters['group'][0]
::accounts::user { 'temp':
shell => '/bin/bash',
password => pw_hash('temp', 'SHA-512', 'mysalt'),
managehome => true,
home_mode => '0755',
groups => [$group],
}
$accounts = $secgen_parameters['accounts']
$accounts.each |$raw_account| {
$account = parsejson($raw_account)
$username = $account['username']
ruby_script_container::account { "script_container_$username":
username => $username,
password => $account['password'],
group => $group,
strings_to_leak => $account['strings_to_leak'],
leaked_filenames => $account['leaked_filenames']
}
}
}

View File

@@ -0,0 +1,49 @@
<?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>Binary script container</name>
<author>Thomas Shaw</author>
<module_license>MIT</module_license>
<description>Binary container module for script based challenges.</description>
<type>system</type>
<type>script_challenge_container</type>
<privilege>none</privilege>
<access>local</access>
<platform>linux</platform>
<read_fact>accounts</read_fact>
<default_input into="accounts">
<generator type="account">
<input into="username">
<value>test</value>
</input>
<input into="password">
</input>
<input into="leaked_filenames">
<value>flag.txt</value>
</input>
<input into="strings_to_leak">
<generator type="flag_generator"/> <!-- flag in /home/<username>/flag.txt -->
</input>
</generator>
</default_input>
<requires>
<module_path>utilities/unix/system/accounts</module_path>
</requires>
<requires>
<module_path>utilities/.*ruby.*</module_path>
</requires>
<!-- Need a way on to the box. -->
<!--<requires>-->
<!--<privilege>user_rwx</privilege>-->
<!--</requires>-->
</vulnerability>

View File

@@ -0,0 +1,3 @@
puts "hallo worlden!"
File.read('/home/test/flag.txt')

View File

@@ -0,0 +1,31 @@
<?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">
<!-- an example system with dc16_amadhj setuid binary reversing challenge installed with default parameters.
username/pw: challenges/password -->
<system>
<system_name>reverse_me</system_name>
<base platform="linux" type="server"/>
<!--TODO: Combine the dc16_amadhj with dc16_amadhj_group, use same pattern for all type=".*pwnable_binary" -->
<!-- 1) Default uses an account and drops the binary in the users home directory -->
<vulnerability module_path=".*dc16_amadhj_group.*"/>
<!-- 2) Using a custom storage directory -->
<!--<vulnerability module_path=".*dc16_amadhj_group.*">-->
<!--<input into="account">-->
<!--<value/>-->
<!--</input>-->
<!--<input into="storage_directory">-->
<!--<value>/test</value>-->
<!--</input>-->
<!--</vulnerability>-->
<network type="private_network" range="dhcp"/>
</system>
</scenario>