def confirm(): logger().warn( "***************************************************************************************" ) logger().warn("*") logger().warn("* RUNNING THIS TOOL MAY RESULT IN UNBOOTABLE OS!") logger().warn("* USE IT FOR TESTING PURPOSES ON TEST SYSTEMS ONLY") logger().warn("*") logger().warn( "* The tool converts PE/COFF EFI executables to TE EFI executables.") logger().warn( "* The tool can also automatically replace files (boot loaders)") logger().warn( "* listed in the configuration file with the generated TE executable.") logger().warn("*") logger().warn( "* If after reboot, TE executable runs then the firmware doesn't properly" ) logger().warn("* enforce Secure Boot checks on TE EFI executables") logger().warn("*") logger().warn( "* If TE executable doesn't run then the firmware correctly blocked it." ) logger().warn( "* To restore OS boot loader in this case you may use one of the following:" ) logger().warn( "* - Disable Secure Boot in BIOS, boot to external drive (e.g. Linux or UEFI shell)" ) logger().warn( "* then restore original boot loader executables from .bak files") logger().warn( "* - On Windows, use recovery mode which should automatically restore correct executables" ) logger().warn("*") logger().warn( "***************************************************************************************" ) s = cs_input("Type 'yes' to continue running the tool > ") if s != 'yes': sys.exit(0)
def run(self, module_argv): self.logger.start_test("Fuzz UEFI Variable Interface") self.logger.warn( "Are you sure you want to continue fuzzing UEFI variable interface?" ) s = cs_input("Type 'yes' to continue > ") if s != 'yes': return # Default options _NAME = 'FuzzerVarName' _GUID = UUID('414C4694-F4CF-0525-69AF-C99C8596530F') _ATTRIB = 0x07 _SIZE = 0x08 _DATA = struct.pack("B", 0x41) * _SIZE ITERATIONS = 1000 SEED = int(time()) CASE = 1 BOUND_STR = 255 #tested value that can be increased or decreased to fit the limit bounds BOUND_INT = 1000 FUZZ_NAME = True FUZZ_GUID = True FUZZ_ATTRIB = True FUZZ_DATA = True FUZZ_SIZE = True # Init fuzzing primitives name_prim = prim.string(value=_NAME, max_len=BOUND_STR) attrib_prim = prim.dword( value=_ATTRIB) # i think the attrib field is 4 bytes large? data_prim = prim.random_data(value=_DATA, min_length=0, max_length=BOUND_INT) help_text = False if len(module_argv): fz_cli = module_argv[0].lower() if ('all' != fz_cli): FUZZ_NAME = False FUZZ_GUID = False FUZZ_ATTRIB = False FUZZ_DATA = False FUZZ_SIZE = False if ('name' == fz_cli): FUZZ_NAME = True elif ('guid' == fz_cli): FUZZ_GUID = True elif ('attrib' == fz_cli): FUZZ_ATTRIB = True elif ('data' == fz_cli): FUZZ_DATA = True elif ('size' == fz_cli): FUZZ_SIZE = True else: help_text = self.usage() if len(module_argv) > 1: if (module_argv[1].isdigit()): ITERATIONS = int(module_argv[1]) else: help_text = self.usage() if len(module_argv) > 2: if (module_argv[2].isdigit()): SEED = int(module_argv[2]) else: help_text = self.usage() if len(module_argv) > 3: if (module_argv[3].isdigit()): CASE = int(module_argv[3]) else: help_text = self.usage() if not help_text: random.seed(SEED) write_file('SEED.txt', str(SEED)) if not len(module_argv): fz_cli = 'all' self.logger.log('Test : {}'.format(fz_cli)) self.logger.log('Iterations: {:d}'.format(ITERATIONS)) self.logger.log('Seed : {:d}'.format(SEED)) self.logger.log('Test case : {:d}'.format(CASE)) self.logger.log('') for count in range(1, ITERATIONS + CASE): if FUZZ_NAME: _NAME = '' if name_prim.mutate(): _NAME = name_prim.render() else: # if mutate() returns false, we need to reload the primitive name_prim = prim.string(value=_NAME, max_len=BOUND_STR) _NAME = name_prim.render() if FUZZ_GUID: _GUID = uuid4() if FUZZ_ATTRIB: if attrib_prim.mutate(): _ATTRIB = attrib_prim.render() else: attrib_prim = prim.dword(value=_ATTRIB) _ATTRIB = attrib_prim.render() if FUZZ_DATA: if data_prim.mutate(): _DATA = data_prim.render() else: data_prim = prim.random_data(value=_DATA, min_length=0, max_length=BOUND_INT) data_prim.mutate() _DATA = data_prim.render() if FUZZ_SIZE: if _DATA: _SIZE = random.randrange(len(_DATA)) else: _SIZE = random.randrange(1024) if (count < CASE): continue self.logger.log(' Running test #{:d}:'.format(count)) self.logger.flush() status = self._uefi.set_EFI_variable(_NAME, str(_GUID), _DATA, _SIZE, _ATTRIB) self.logger.log(status) status = self._uefi.delete_EFI_variable(_NAME, str(_GUID)) self.logger.log(status) return ModuleResult.PASSED