import re USER_ALIVE = True FUNC_TABLE_SIZE = 4 FUNC_TABLE_ENTRY_SIZE = 32 CORRUPT_MESSAGE = 'Table corrupted. Try entering \'reset\' to fix it' func_table = '' def reset_table(): global func_table # This table is formatted for easier viewing, but it is really one line func_table = \ '''\ print_table \ read_variable \ write_variable \ getRandomNumber \ ''' def check_table(): global func_table if( len(func_table) != FUNC_TABLE_ENTRY_SIZE * FUNC_TABLE_SIZE): return False return True def get_func(n): global func_table # Check table for viability if( not check_table() ): print(CORRUPT_MESSAGE) return # Get function name from table func_name = '' func_name_offset = n * FUNC_TABLE_ENTRY_SIZE for i in range(func_name_offset, func_name_offset+FUNC_TABLE_ENTRY_SIZE): if( func_table[i] == ' '): func_name = func_table[func_name_offset:i] break if( func_name == '' ): func_name = func_table[func_name_offset:func_name_offset+FUNC_TABLE_ENTRY_SIZE] return func_name def print_table(): # Check table for viability if( not check_table() ): print(CORRUPT_MESSAGE) return for i in range(0, FUNC_TABLE_SIZE): j = i + 1 print(str(j)+': ' + get_func(i)) def filter_var_name(var_name): r = re.search('^[a-zA-Z_][a-zA-Z_0-9]*$', var_name) if r: return True else: return False def read_variable(): var_name = input('Please enter variable name to read: ') if( filter_var_name(var_name) ): eval('print('+var_name+')') else: print('Illegal variable name') def filter_value(value): if ';' in value or '(' in value or ')' in value: return False else: return True def write_variable(): var_name = input('Please enter variable name to write: ') if( filter_var_name(var_name) ): value = input('Please enter new value of variable: ') if( filter_value(value) ): exec('global '+var_name+'; '+var_name+' = '+value) else: print('Illegal value') else: print('Illegal variable name') def call_func(n): """ Calls the nth function in the function table. Arguments: n: The function to call. The first function is 0. """ # Check table for viability if( not check_table() ): print(CORRUPT_MESSAGE) return # Check n if( n < 0 ): print('n cannot be less than 0. Aborting...') return elif( n >= FUNC_TABLE_SIZE ): print('n cannot be greater than or equal to the function table size of '+FUNC_TABLE_SIZE) return # Get function name from table func_name = get_func(n) # Run the function eval(func_name+'()') def dummy_func1(): print('in dummy_func1') def dummy_func2(): print('in dummy_func2') def dummy_func3(): print('in dummy_func3') def dummy_func4(): print('in dummy_func4') def getRandomNumber(): print(4) # Chosen by fair die roll. # Guaranteed to be random. # (See XKCD) def win(): # This line will not work locally unless you create your own 'flag.txt' in # the same directory as this script flag = open('flag.txt', 'r').read() #flag = flag[:-1] flag = flag.strip() str_flag = '' for c in flag: str_flag += str(hex(ord(c))) + ' ' print(str_flag) def help_text(): print( ''' This program fixes vulnerabilities in its predecessor by limiting what functions can be called to a table of predefined functions. This still puts the user in charge, but prevents them from calling undesirable subroutines. * Enter 'quit' to quit the program. * Enter 'help' for this text. * Enter 'reset' to reset the table. * Enter '1' to execute the first function in the table. * Enter '2' to execute the second function in the table. * Enter '3' to execute the third function in the table. * Enter '4' to execute the fourth function in the table. Here's the current table: ''' ) print_table() reset_table() while(USER_ALIVE): choice = input('==> ') if( choice == 'quit' or choice == 'exit' or choice == 'q' ): USER_ALIVE = False elif( choice == 'help' or choice == '?' ): help_text() elif( choice == 'reset' ): reset_table() elif( choice == '1' ): call_func(0) elif( choice == '2' ): call_func(1) elif( choice == '3' ): call_func(2) elif( choice == '4' ): call_func(3) else: print('Did not understand "'+choice+'" Have you tried "help"?')