def run(self, module_argv): self.logger.start_test( "Check for suspicious EFI binaries in UEFI firmware") self.usage() if len(module_argv) > 0: self.vt = VirusTotalPublicApi(module_argv[0]) if len(module_argv) > 1: self.vt_threshold = int(module_argv[1]) image_file = DEF_FWIMAGE_FILE if len(module_argv) > 2: # Use provided firmware image image_file = module_argv[2] self.logger.log( "[*] reading FW image from file: {}".format(image_file)) else: # Read firmware image directly from SPI flash memory self.spi = SPI(self.cs) (base, limit, freg) = self.spi.get_SPI_region(BIOS) image_size = limit + 1 - base self.logger.log( "[*] dumping FW image from ROM to {}: 0x{:08X} bytes at [0x{:08X}:0x{:08X}]" .format(image_file, base, limit, image_size)) self.logger.log( "[*] this may take a few minutes (instead, use 'chipsec_util spi dump')..." ) self.spi.read_spi_to_file(base, image_size, image_file) self.image = read_file(image_file) return self.check_reputation()
def run(self, module_argv): self.logger.start_test( "Check for black-listed EFI binaries in UEFI firmware") self.usage() image_file = DEF_FWIMAGE_FILE if len(module_argv) == 0: # Read firmware image directly from SPI flash memory self.spi = SPI(self.cs) (base, limit, freg) = self.spi.get_SPI_region(BIOS) image_size = limit + 1 - base self.logger.log( "[*] dumping FW image from ROM to {}: 0x{:08X} bytes at [0x{:08X}:0x{:08X}]" .format(image_file, base, limit, image_size)) self.logger.log( "[*] this may take a few minutes (instead, use 'chipsec_util spi dump')..." ) self.spi.read_spi_to_file(base, image_size, image_file) elif len(module_argv) > 0: # Use provided firmware image image_file = module_argv[0] self.logger.log( "[*] reading FW image from file: {}".format(image_file)) self.image = read_file(image_file) # Load JSON config with black-listed EFI modules if len(module_argv) > 1: self.cfg_name = module_argv[1] cfg_pth = os.path.join(get_main_dir(), "chipsec/modules/tools/uefi", self.cfg_name) with open(cfg_pth, 'r') as blacklist_json: self.efi_blacklist = json.load(blacklist_json) return self.check_blacklist()
def run(self, module_argv): self.logger.start_test( "simple list generation/checking for (U)EFI firmware") self.res = ModuleResult.SKIPPED op = module_argv[0] if len(module_argv) > 0 else 'generate' if op in ['generate', 'check']: if len(module_argv) <= 2: self.usage() return self.res elif len(module_argv) > 2: json_file = module_argv[1] image_file = module_argv[2] self.logger.log( "[*] reading firmware from '{}'...".format(image_file)) else: image_file = DEF_FWIMAGE_FILE json_file = DEF_EFILIST_FILE self.spi = SPI(self.cs) (base, limit, freg) = self.spi.get_SPI_region(BIOS) image_size = limit + 1 - base self.logger.log( "[*] dumping firmware image from ROM to '{}': 0x{:08X} bytes at [0x{:08X}:0x{:08X}]" .format(image_file, image_size, base, limit)) self.spi.read_spi_to_file(base, image_size, image_file) self.image_file = image_file self.image = read_file(image_file) json_pth = os.path.abspath(json_file) if op == 'generate': if os.path.exists(json_pth): self.logger.error( "JSON file '{}' already exists. Exiting...".format( json_file)) self.res = ModuleResult.ERROR else: self.res = self.generate_efilist(json_pth) elif op == 'check': if not os.path.exists(json_pth): self.logger.error( "JSON file '{}' doesn't exists. Exiting...".format( json_file)) self.res = ModuleResult.ERROR else: self.res = self.check_list(json_pth) elif op == 'help': self.usage() else: self.logger.error( "unrecognized command-line argument to the module") self.usage() return self.res
def run(self, module_argv): self.logger.start_test( "Check for blocked EFI binaries in UEFI firmware") self.usage() image_file = DEF_FWIMAGE_FILE if len(module_argv) == 0: # Read firmware image directly from SPI flash memory self.spi = SPI(self.cs) (base, limit, freg) = self.spi.get_SPI_region(BIOS) image_size = limit + 1 - base self.logger.log( "[*] Dumping FW image from ROM to {}: 0x{:08X} bytes at [0x{:08X}:0x{:08X}]" .format(image_file, base, limit, image_size)) self.logger.log( "[*] This may take a few minutes (instead, use 'chipsec_util spi dump')..." ) self.spi.read_spi_to_file(base, image_size, image_file) elif len(module_argv) > 0: # Use provided firmware image image_file = module_argv[0] self.logger.log( "[*] Reading FW image from file: {}".format(image_file)) self.image = read_file(image_file) if not self.image: if len(module_argv) == 0: self.logger.log_important( 'Unable to read SPI and generate FW image. Access may be blocked.' ) self.logger.error('No FW image file to read. Exiting!') self.res = ModuleResult.ERROR return self.res # Load JSON config with blocked EFI modules if len(module_argv) > 1: self.cfg_name = module_argv[1] cfg_pth = os.path.join(get_main_dir(), "chipsec/modules/tools/uefi", self.cfg_name) with open(cfg_pth, 'r') as blockedlist_json: self.efi_blockedlist = json.load(blockedlist_json) self.res = self.check_blockedlist() return self.res
def run(self): try: self._spi = SPI(self.cs) except SpiRuntimeError as msg: self.logger.error(msg) return self._msg = "it may take a few minutes (use DEBUG or VERBOSE logger options to see progress)" t = time.time() self.func() self.logger.log( "[CHIPSEC] (spi) time elapsed {:.3f}".format(time.time() - t))
def __init__(self): BaseModule.__init__(self) self.spi = SPI( self.cs )
class bios_wp(BaseModule): def __init__(self): BaseModule.__init__(self) self.spi = SPI( self.cs ) def is_supported(self): return True def check_BIOS_write_protection(self): self.logger.start_test( "BIOS Region Write Protection" ) # # BIOS Control Register # #reg_value = chipsec.chipset.read_register(self.cs, 'BC') #chipsec.chipset.print_register(self.cs, 'BC', reg_value) #ble = chipsec.chipset.get_register_field(self.cs, 'BC', reg_value, 'BLE') ble = self.cs.get_control('BiosLockEnable', with_print=True) #bioswe = self.cs.get_register_field('BC', reg_value, 'BIOSWE') bioswe = self.cs.get_control('BiosWriteEnable') #smmbwp = chipsec.chipset.get_register_field(self.cs, 'BC', reg_value, 'SMM_BWP') smmbwp = self.cs.get_control( 'SmmBiosWriteProtection' ) # Is the BIOS flash region write protected? write_protected = 0 if 1 == ble and 0 == bioswe: if 1 == smmbwp: self.logger.log_good( "BIOS region write protection is enabled (writes restricted to SMM)" ) write_protected = 1 else: self.logger.log_important( "Enhanced SMM BIOS region write protection has not been enabled (SMM_BWP is not used)" ) else: self.logger.log_bad( "BIOS region write protection is disabled!" ) return write_protected == 1 def check_SPI_protected_ranges(self): (bios_base,bios_limit,bios_freg) = self.spi.get_SPI_region( BIOS ) self.logger.log( "\n[*] BIOS Region: Base = 0x{:08X}, Limit = 0x{:08X}".format(bios_base,bios_limit) ) self.spi.display_SPI_Protected_Ranges() pr_cover_bios = False pr_partial_cover_bios = False # for j in range(5): # (base,limit,wpe,rpe,pr_reg_off,pr_reg_value) = spi.get_SPI_Protected_Range( j ) # if (wpe == 1 and base < limit and base <= bios_base and limit >= bios_limit): # pr_cover_bios = True # if (wpe == 1 and base < limit and limit > bios_base): # pr_partial_cover_bios = True areas_to_protect = [(bios_base, bios_limit)] protected_areas = list() for j in range(5): (base,limit,wpe,rpe,pr_reg_off,pr_reg_value) = self.spi.get_SPI_Protected_Range( j ) if base > limit: continue if wpe == 1: for area in areas_to_protect: # overlap bottom start,end = area if base <= start and limit >= start: if limit >= end: areas_to_protect.remove(area) else: areas_to_protect.remove(area) area = (limit+1,end) areas_to_protect.append(area) # overlap top elif base <= end and limit >= end: if base <= start: areas_to_protect.remove(area) else: areas_to_protect.remove(area) area = (start,base-1) areas_to_protect.append(area) start,end = area # split elif base > start and limit < end: areas_to_protect.remove(area) areas_to_protect.append((start,base-1)) areas_to_protect.append((limit+1, end)) if (len(areas_to_protect) == 0): pr_cover_bios = True else: if (len(areas_to_protect) != 1 or areas_to_protect[0] != (bios_base,bios_limit)): pr_partial_cover_bios = True if pr_partial_cover_bios: self.logger.log( '' ) self.logger.log_important( "SPI protected ranges write-protect parts of BIOS region (other parts of BIOS can be modified)" ) else: if not pr_cover_bios: self.logger.log( '' ) self.logger.log_important( "None of the SPI protected ranges write-protect BIOS region" ) return pr_cover_bios # -------------------------------------------------------------------------- # run( module_argv ) # Required function: run here all tests from this module # -------------------------------------------------------------------------- def run(self, module_argv ): wp = self.check_BIOS_write_protection() spr = self.check_SPI_protected_ranges() self.logger.log('') if wp: if spr: self.logger.log_passed_check( "BIOS is write protected (by SMM and SPI Protected Ranges)" ) else: self.logger.log_passed_check( "BIOS is write protected" ) else: if spr: self.logger.log_passed_check( "SPI Protected Ranges are configured to write protect BIOS" ) else: self.logger.log_important( 'BIOS should enable all available SMM based write protection mechanisms or configure SPI protected ranges to protect the entire BIOS region' ) self.logger.log_failed_check( "BIOS is NOT protected completely" ) if wp or spr: return ModuleResult.PASSED else: return ModuleResult.FAILED
class scan_image(BaseModule): def __init__(self): BaseModule.__init__(self) self.uefi = UEFI(self.cs) self.image = None self.efi_list = None self.suspect_modules = {} def is_supported(self): return True # # callbacks to uefi_search.check_match_criteria # def genlist_callback(self, efi_module): md = {} if type(efi_module) == EFI_SECTION: #if efi_module.MD5: md["md5"] = efi_module.MD5 if efi_module.SHA256: md["sha1"] = efi_module.SHA1 if efi_module.parentGuid: md["guid"] = efi_module.parentGuid if efi_module.ui_string: md["name"] = efi_module.ui_string if efi_module.Name and efi_module.Name != SECTION_NAMES[ EFI_SECTION_PE32]: md["type"] = efi_module.Name self.efi_list[efi_module.SHA256] = md else: pass # # Generates new list of EFI executable binaries # def generate_efilist(self, json_pth): self.efi_list = {} self.logger.log( "[*] generating a list of EFI executables from firmware image...") efi_tree = build_efi_model(self.uefi, self.image, None) matching_modules = search_efi_tree(efi_tree, self.genlist_callback, EFIModuleType.SECTION_EXE, True) self.logger.log( "[*] found {:d} EFI executables in UEFI firmware image '{}'". format(len(self.efi_list), self.image_file)) self.logger.log("[*] creating JSON file '{}'...".format(json_pth)) write_file( "{}".format(json_pth), json.dumps(self.efi_list, indent=2, separators=(',', ': '), cls=UUIDEncoder)) return ModuleResult.PASSED # # Checks EFI executable binaries against allowed list # def check_list(self, json_pth): self.efi_list = {} with open(json_pth) as data_file: self.efilist = json.load(data_file) self.logger.log( "[*] checking EFI executables against the list '{}'".format( json_pth)) # parse the UEFI firmware image and look for EFI modules matching list # - match only executable EFI sections (PE/COFF, TE) # - find all occurrences of matching EFI modules efi_tree = build_efi_model(self.uefi, self.image, None) matching_modules = search_efi_tree(efi_tree, self.genlist_callback, EFIModuleType.SECTION_EXE, True) self.logger.log( "[*] found {:d} EFI executables in UEFI firmware image '{}'". format(len(self.efi_list), self.image_file)) for m in self.efi_list: if not (m in self.efilist): self.suspect_modules[m] = self.efi_list[m] guid = self.efi_list[m]["guid"] if 'guid' in self.efi_list[ m] else '?' name = self.efi_list[m]["name"] if 'name' in self.efi_list[ m] else '<unknown>' sha1 = self.efi_list[m]["sha1"] if 'sha1' in self.efi_list[ m] else '' self.logger.log_important( "found EFI executable not in the list:\n {} (sha256)\n {} (sha1)\n {{{}}}\n {}" .format(m, sha1, guid, name)) if len(self.suspect_modules) > 0: self.logger.log_warn_check( "found {:d} EFI executables not in the list '{}'".format( len(self.suspect_modules), json_pth)) return ModuleResult.WARNING else: self.logger.log_passed_check( "all EFI executables match the list '{}'".format(json_pth)) return ModuleResult.PASSED def usage(self): self.logger.log(USAGE_TEXT) # -------------------------------------------------------------------------- # run( module_argv ) # Required function: run here all tests from this module # -------------------------------------------------------------------------- def run(self, module_argv): self.logger.start_test( "simple list generation/checking for (U)EFI firmware") self.res = ModuleResult.SKIPPED op = module_argv[0] if len(module_argv) > 0 else 'generate' if op in ['generate', 'check']: if len(module_argv) > 1: json_file = module_argv[1] image_file = module_argv[2] self.logger.log( "[*] reading firmware from '{}'...".format(image_file)) else: image_file = DEF_FWIMAGE_FILE json_file = DEF_EFILIST_FILE self.spi = SPI(self.cs) (base, limit, freg) = self.spi.get_SPI_region(BIOS) image_size = limit + 1 - base self.logger.log( "[*] dumping firmware image from ROM to '{}': 0x{:08X} bytes at [0x{:08X}:0x{:08X}]" .format(image_file, image_size, base, limit)) self.spi.read_spi_to_file(base, image_size, image_file) self.image_file = image_file self.image = read_file(image_file) json_pth = os.path.abspath(json_file) if op == 'generate': if os.path.exists(json_pth): self.logger.error( "JSON file '{}' already exists. Exiting...".format( json_file)) self.res = ModuleResult.ERROR else: self.res = self.generate_efilist(json_pth) elif op == 'check': if not os.path.exists(json_pth): self.logger.error( "JSON file '{}' doesn't exists. Exiting...".format( json_file)) self.res = ModuleResult.ERROR else: self.res = self.check_list(json_pth) elif op == 'help': self.usage() else: self.logger.error( "unrecognized command-line argument to the module") self.usage() return self.res
class spi_access(BaseModule): def __init__(self): BaseModule.__init__(self) self.spi = SPI(self.cs) def is_supported(self): return True ## # Displays the SPI Regions Access Permissions def check_flash_access_permissions(self): res = ModuleResult.PASSED fdv = self.cs.read_register_field('HSFS', 'FDV') == 1 frap = self.cs.read_register('FRAP') brra = self.cs.get_register_field('FRAP', frap, 'BRRA') brwa = self.cs.get_register_field('FRAP', frap, 'BRWA') if self.cs.is_register_defined('FDOC') and self.cs.is_register_defined( 'FDOD'): self.cs.write_register('FDOC', 0x3000) tmp_reg = self.cs.read_register('FDOD') brra |= ((tmp_reg >> 8) & 0xFFF) brwa |= ((tmp_reg >> 20) & 0xFFF) # Informational # State of Flash Descriptor Valid bit if not fdv: self.logger.log("[*] Flash Descriptor Valid bit is not set") # CPU/Software access to Platform Data region (platform specific) if brwa & (1 << PLATFORM_DATA): self.logger.log( "[*] Software has write access to Platform Data region in SPI flash (it's platform specific)" ) # Warnings # CPU/Software access to GBe region if brwa & (1 << GBE): res = ModuleResult.WARNING self.logger.log_warning( "Software has write access to GBe region in SPI flash") # Failures # CPU/Software access to Flash Descriptor region (Read Only) if brwa & (1 << FLASH_DESCRIPTOR): res = ModuleResult.FAILED self.logger.log_bad( "Software has write access to SPI flash descriptor") # CPU/Software access to Intel ME region (Read Only) if brwa & (1 << ME): res = ModuleResult.FAILED self.logger.log_bad( "Software has write access to Management Engine (ME) region in SPI flash" ) if fdv: if ModuleResult.PASSED == res: self.logger.log_passed_check( "SPI Flash Region Access Permissions in flash descriptor look ok" ) elif ModuleResult.FAILED == res: self.logger.log_failed_check( "SPI Flash Region Access Permissions are not programmed securely in flash descriptor" ) elif ModuleResult.WARNING == res: self.logger.log_warn_check( "Certain SPI flash regions are writeable by software") else: res = ModuleResult.WARNING self.logger.log_warn_check( "Either flash descriptor is not valid or not present on this system" ) return res # -------------------------------------------------------------------------- # run( module_argv ) # Required function: run here all tests from this module # -------------------------------------------------------------------------- def run(self, module_argv): self.logger.start_test("SPI Flash Region Access Control") self.spi.display_SPI_Ranges_Access_Permissions() self.res = self.check_flash_access_permissions() return self.res
class blacklist(BaseModule): def __init__(self): BaseModule.__init__(self) self.uefi = UEFI(self.cs) self.cfg_name = 'blacklist.json' self.image = None self.efi_blacklist = None def is_supported(self): return True def blacklist_callback(self, efi_module): return check_match_criteria(efi_module, self.efi_blacklist, self.logger) def check_blacklist(self): res = ModuleResult.PASSED self.logger.log( "[*] searching for EFI binaries that match criteria from '{}':". format(self.cfg_name)) for k in self.efi_blacklist.keys(): entry = self.efi_blacklist[k] self.logger.log(" {:16} - {}".format( k, entry['description'] if 'description' in entry else '')) #if 'match' in entry: # for c in entry['match'].keys(): self.logger.log( "[*] {}".format(entry['match'][c]) ) #if 'exclude' in entry: # self.logger.log( "[*] excluding binaries:" ) # for c in entry['exclude']: self.logger.log( "[*] {}".format(entry['exclude'][c]) ) # parse the UEFI firmware image and look for EFI modules matching the balck-list efi_tree = build_efi_model(self.uefi, self.image, None) #match_types = (spi_uefi.EFIModuleType.SECTION_EXE|spi_uefi.EFIModuleType.FILE) match_types = EFIModuleType.SECTION_EXE matching_modules = search_efi_tree(efi_tree, self.blacklist_callback, match_types) found = len(matching_modules) > 0 self.logger.log('') if found: res = ModuleResult.WARNING self.logger.log_warn_check( "Black-listed EFI binary found in the UEFI firmware image") else: self.logger.log_passed_check( "Didn't find any black-listed EFI binary") return res def usage(self): self.logger.log(USAGE_TEXT) # -------------------------------------------------------------------------- # run( module_argv ) # Required function: run here all tests from this module # -------------------------------------------------------------------------- def run(self, module_argv): self.logger.start_test( "Check for black-listed EFI binaries in UEFI firmware") self.usage() image_file = DEF_FWIMAGE_FILE if len(module_argv) == 0: # Read firmware image directly from SPI flash memory self.spi = SPI(self.cs) (base, limit, freg) = self.spi.get_SPI_region(BIOS) image_size = limit + 1 - base self.logger.log( "[*] dumping FW image from ROM to {}: 0x{:08X} bytes at [0x{:08X}:0x{:08X}]" .format(image_file, base, limit, image_size)) self.logger.log( "[*] this may take a few minutes (instead, use 'chipsec_util spi dump')..." ) self.spi.read_spi_to_file(base, image_size, image_file) elif len(module_argv) > 0: # Use provided firmware image image_file = module_argv[0] self.logger.log( "[*] reading FW image from file: {}".format(image_file)) self.image = read_file(image_file) # Load JSON config with black-listed EFI modules if len(module_argv) > 1: self.cfg_name = module_argv[1] cfg_pth = os.path.join(get_main_dir(), "chipsec/modules/tools/uefi", self.cfg_name) with open(cfg_pth, 'r') as blacklist_json: self.efi_blacklist = json.load(blacklist_json) return self.check_blacklist()
class bios_wp(BaseModule): def __init__(self): BaseModule.__init__(self) self.spi = SPI(self.cs) def is_supported(self): return True def check_BIOS_write_protection(self): ble = self.cs.get_control('BiosLockEnable', with_print=True) bioswe = self.cs.get_control('BiosWriteEnable') smmbwp = self.cs.get_control('SmmBiosWriteProtection') # Is the BIOS flash region write protected? write_protected = 0 if (1 == ble) and (0 == bioswe): if 1 == smmbwp: self.logger.log_good( "BIOS region write protection is enabled (writes restricted to SMM)" ) write_protected = 1 else: self.logger.log_important( "Enhanced SMM BIOS region write protection has not been enabled (SMM_BWP is not used)" ) else: self.logger.log_bad("BIOS region write protection is disabled!") return write_protected == 1 def check_SPI_protected_ranges(self): (bios_base, bios_limit, _) = self.spi.get_SPI_region(BIOS) self.logger.log( "\n[*] BIOS Region: Base = 0x{:08X}, Limit = 0x{:08X}".format( bios_base, bios_limit)) self.spi.display_SPI_Protected_Ranges() pr_cover_bios = False pr_partial_cover_bios = False areas_to_protect = [(bios_base, bios_limit)] for j in range(5): (base, limit, wpe, _, _, _) = self.spi.get_SPI_Protected_Range(j) if base > limit: continue if wpe == 1: areas = areas_to_protect[:] for area in areas: (start, end) = area if (base <= start) and (limit >= start): # overlap bottom if limit >= end: areas_to_protect.remove(area) else: areas_to_protect.remove(area) area = (limit + 1, end) areas_to_protect.append(area) elif (base <= end) and (limit >= end): # overlap top if base <= start: areas_to_protect.remove(area) else: areas_to_protect.remove(area) area = (start, base - 1) areas_to_protect.append(area) elif (base > start) and (limit < end): # split areas_to_protect.remove(area) areas_to_protect.append((start, base - 1)) areas_to_protect.append((limit + 1, end)) if (len(areas_to_protect) == 0): pr_cover_bios = True else: if (len(areas_to_protect) != 1) or (areas_to_protect[0] != (bios_base, bios_limit)): pr_partial_cover_bios = True if pr_partial_cover_bios: self.logger.log('') self.logger.log_important( "SPI protected ranges write-protect parts of BIOS region (other parts of BIOS can be modified)" ) else: if not pr_cover_bios: self.logger.log('') self.logger.log_important( "None of the SPI protected ranges write-protect BIOS region" ) return pr_cover_bios # -------------------------------------------------------------------------- # run( module_argv ) # Required function: run here all tests from this module # -------------------------------------------------------------------------- def run(self, module_argv): self.logger.start_test("BIOS Region Write Protection") wp = self.check_BIOS_write_protection() spr = self.check_SPI_protected_ranges() self.logger.log('') if wp: if spr: self.logger.log_passed( "BIOS is write protected (by SMM and SPI Protected Ranges)" ) else: self.logger.log_passed("BIOS is write protected") else: if spr: self.logger.log_passed( "SPI Protected Ranges are configured to write protect BIOS" ) else: self.logger.log_important( 'BIOS should enable all available SMM based write protection mechanisms.' ) self.logger.log_important( 'Or configure SPI protected ranges to protect the entire BIOS region.' ) self.logger.log_failed("BIOS is NOT protected completely") if wp or spr: self.res = ModuleResult.PASSED else: self.res = ModuleResult.FAILED return self.res
def __init__(self): BaseModule.__init__(self) self.iobar = iobar( self.cs ) self.spi = SPI( self.cs )
class bios_smi(BaseModule): def __init__(self): BaseModule.__init__(self) self.iobar = iobar( self.cs ) self.spi = SPI( self.cs ) def is_supported(self): return (self.cs.get_chipset_id() not in chipsec.chipset.CHIPSET_FAMILY_ATOM) def get_PMBASE(self): if self.iobar.is_IO_BAR_defined( 'PMBASE' ): (io_base,io_size) = self.iobar.get_IO_BAR_base_address( 'PMBASE' ) return io_base else: return (self.cs.pci.read_dword( 0, 31, 0, self.cs.Cfg.CFG_REG_PCH_LPC_PMBASE ) & self.cs.Cfg.CFG_REG_PCH_LPC_PMBASE_MASK) def get_TCOBASE(self): return (self.get_PMBASE() + self.cs.Cfg.TCOBASE_ABASE_OFFSET) def check_SMI_locks(self): self.logger.start_test( "SMI Events Configuration" ) # # First check SMM_BWP in BIOS control to warn if SMM write-protection of the BIOS is not enabled # (BcRegister, reg_value) = self.spi.get_BIOS_Control() #self.logger.log( BcRegister ) if 0 == BcRegister.SMM_BWP: self.logger.log_bad( "SMM BIOS region write protection has not been enabled (SMM_BWP is not used)\n" ) ok = True # # Check if global SMI is enabled and TCO SMI is enabled (GBL_SMI_EN and TCO_EN in PMBASE[SMI_EN]) # pmbase = self.get_PMBASE() self.logger.log("[*] PMBASE (ACPI I/O Base) = 0x%04X" % pmbase ) smi_en = self.cs.io.read_port_dword( pmbase + self.cs.Cfg.PMBASE_SMI_EN ) self.logger.log("[*] SMI_EN (SMI Control and Enable) register [I/O port 0x%X] = 0x%08X" % (pmbase + self.cs.Cfg.PMBASE_SMI_EN,smi_en) ) self.logger.log(" [13] TCO_EN (TCO Enable) = %u" % ((smi_en & (1<<13)) >> 13) ) self.logger.log(" [00] GBL_SMI_EN (Global SMI Enable) = %u" % (smi_en & 0x1) ) if (smi_en & 0x1) != 1: ok = False self.logger.log_bad( "Global SMI is not enabled" ) elif ((smi_en & (1<<13)) >> 13) != 1: self.logger.warn( "TCO SMI is not enabled. BIOS may not be using it" ) else: self.logger.log_good( "All required SMI events are enabled" ) # # TCO_LOCK TCOBASE I/O register # tcobase = pmbase + self.cs.Cfg.TCOBASE_ABASE_OFFSET self.logger.log("[*] TCOBASE (TCO I/O Base) = 0x%04X" % tcobase ) tco1_cnt = self.cs.io.read_port_word( tcobase + 0x8 ) # TCO1_CNT (TCOBASE + 0x8 = (ACPIBASE + 0x60) + 0x8) self.logger.log("[*] TCO1_CNT (TCO1 Control) register [I/O port 0x%X] = 0x%04X" % (tcobase + 0x8, tco1_cnt) ) self.logger.log(" [12] TCO_LOCK = %u" % ((tco1_cnt & (1<<12)) >> 12) ) if ((tco1_cnt & (1<<12)) >> 12) != 1: ok = False self.logger.log_bad( "TCO SMI event configuration is not locked. TCO SMI events can be disabled" ) else: self.logger.log_good( "TCO SMI configuration is locked" ) # # SMI_LOCK 0:31:0 PCIe CFG register # gen_pmcon_1 = self.cs.pci.read_word( 0, 31, 0, self.cs.Cfg.GEN_PMCON ) # BDF 0:31:0 offset 0xA0 (GEN_PMCON_1), SMI_LOCK is bit 0 self.logger.log("[*] GEN_PMCON_1 (General PM Config 1) register [BDF 0:31:0 + 0x%X] = 0x%04X" % (self.cs.Cfg.GEN_PMCON, gen_pmcon_1) ) self.logger.log(" [04] SMI_LOCK = %u" % ((gen_pmcon_1 & (1<<4)) >> 4) ) if ((gen_pmcon_1 & (1<<4)) >> 4) != 1: ok = False self.logger.log_bad( "SMI events global configuration is not locked. SMI events can be disabled" ) else: self.logger.log_good( "SMI events global configuration is locked" ) if ok: res = ModuleResult.PASSED self.logger.log_passed_check( "All required SMI sources seem to be enabled and locked!" ) else: if BcRegister.SMM_BWP == 1: res = ModuleResult.WARNING self.logger.log_warn_check( "Not all required SMI sources are enabled and locked, but SPI flash writes are still restricted to SMM." ) else: res = ModuleResult.FAILED self.logger.log_failed_check( "Not all required SMI sources are enabled and locked!" ) return res # -------------------------------------------------------------------------- # run( module_argv ) # Required function: run here all tests from this module # -------------------------------------------------------------------------- def run( self, module_argv ): return self.check_SMI_locks()
class bios_smi(BaseModule): def __init__(self): BaseModule.__init__(self) self.iobar = iobar(self.cs) self.spi = SPI(self.cs) def is_supported(self): return (self.cs.get_chipset_id() not in chipsec.chipset.CHIPSET_FAMILY_ATOM) def get_PMBASE(self): if self.iobar.is_IO_BAR_defined('PMBASE'): (io_base, io_size) = self.iobar.get_IO_BAR_base_address('PMBASE') return io_base else: return (self.cs.pci.read_dword(0, 31, 0, self.cs.Cfg.CFG_REG_PCH_LPC_PMBASE) & self.cs.Cfg.CFG_REG_PCH_LPC_PMBASE_MASK) def get_TCOBASE(self): return (self.get_PMBASE() + self.cs.Cfg.TCOBASE_ABASE_OFFSET) def check_SMI_locks(self): self.logger.start_test("SMI Events Configuration") # # First check SMM_BWP in BIOS control to warn if SMM write-protection of the BIOS is not enabled # (BcRegister, reg_value) = self.spi.get_BIOS_Control() #self.logger.log( BcRegister ) if 0 == BcRegister.SMM_BWP: self.logger.log_bad( "SMM BIOS region write protection has not been enabled (SMM_BWP is not used)\n" ) ok = True # # Check if global SMI is enabled and TCO SMI is enabled (GBL_SMI_EN and TCO_EN in PMBASE[SMI_EN]) # pmbase = self.get_PMBASE() self.logger.log("[*] PMBASE (ACPI I/O Base) = 0x%04X" % pmbase) smi_en = self.cs.io.read_port_dword(pmbase + self.cs.Cfg.PMBASE_SMI_EN) self.logger.log( "[*] SMI_EN (SMI Control and Enable) register [I/O port 0x%X] = 0x%08X" % (pmbase + self.cs.Cfg.PMBASE_SMI_EN, smi_en)) self.logger.log(" [13] TCO_EN (TCO Enable) = %u" % ((smi_en & (1 << 13)) >> 13)) self.logger.log(" [00] GBL_SMI_EN (Global SMI Enable) = %u" % (smi_en & 0x1)) if (smi_en & 0x1) != 1: ok = False self.logger.log_bad("Global SMI is not enabled") elif ((smi_en & (1 << 13)) >> 13) != 1: self.logger.warn( "TCO SMI is not enabled. BIOS may not be using it") else: self.logger.log_good("All required SMI events are enabled") # # TCO_LOCK TCOBASE I/O register # tcobase = pmbase + self.cs.Cfg.TCOBASE_ABASE_OFFSET self.logger.log("[*] TCOBASE (TCO I/O Base) = 0x%04X" % tcobase) tco1_cnt = self.cs.io.read_port_word( tcobase + 0x8) # TCO1_CNT (TCOBASE + 0x8 = (ACPIBASE + 0x60) + 0x8) self.logger.log( "[*] TCO1_CNT (TCO1 Control) register [I/O port 0x%X] = 0x%04X" % (tcobase + 0x8, tco1_cnt)) self.logger.log(" [12] TCO_LOCK = %u" % ((tco1_cnt & (1 << 12)) >> 12)) if ((tco1_cnt & (1 << 12)) >> 12) != 1: ok = False self.logger.log_bad( "TCO SMI event configuration is not locked. TCO SMI events can be disabled" ) else: self.logger.log_good("TCO SMI configuration is locked") # # SMI_LOCK 0:31:0 PCIe CFG register # gen_pmcon_1 = self.cs.pci.read_word( 0, 31, 0, self.cs.Cfg.GEN_PMCON ) # BDF 0:31:0 offset 0xA0 (GEN_PMCON_1), SMI_LOCK is bit 0 self.logger.log( "[*] GEN_PMCON_1 (General PM Config 1) register [BDF 0:31:0 + 0x%X] = 0x%04X" % (self.cs.Cfg.GEN_PMCON, gen_pmcon_1)) self.logger.log(" [04] SMI_LOCK = %u" % ((gen_pmcon_1 & (1 << 4)) >> 4)) if ((gen_pmcon_1 & (1 << 4)) >> 4) != 1: ok = False self.logger.log_bad( "SMI events global configuration is not locked. SMI events can be disabled" ) else: self.logger.log_good("SMI events global configuration is locked") if ok: res = ModuleResult.PASSED self.logger.log_passed_check( "All required SMI sources seem to be enabled and locked!") else: if BcRegister.SMM_BWP == 1: res = ModuleResult.WARNING self.logger.log_warn_check( "Not all required SMI sources are enabled and locked, but SPI flash writes are still restricted to SMM." ) else: res = ModuleResult.FAILED self.logger.log_failed_check( "Not all required SMI sources are enabled and locked!") return res # -------------------------------------------------------------------------- # run( module_argv ) # Required function: run here all tests from this module # -------------------------------------------------------------------------- def run(self, module_argv): return self.check_SMI_locks()
class reputation(BaseModule): def __init__(self): BaseModule.__init__(self) self.uefi = UEFI(self.cs) self.image = None self.vt_threshold = 10 self.vt = None def is_supported(self): if has_virus_total_apis: return True else: self.logger.log_important( """Can't import module 'virus_total_apis'. Please run 'pip install virustotal-api' and try again.""") return False def reputation_callback(self, efi_module): vt_report = self.vt.get_file_report(efi_module.SHA256) while vt_report["response_code"] == 204: # The Public API is limited to 4 requests per minute. if self.logger.DEBUG: self.logger.log( "VT API quota exceeded, sleeping for 1 minute... (-.-)zzZZ" ) time.sleep(60) # Retry. vt_report = self.vt.get_file_report(efi_module.SHA256) if vt_report["results"]["response_code"] == 0: # Hash is unknown to VT. self.logger.log_warn_check( "Unfamiliar EFI binary found in the UEFI firmware image\n{}". format(efi_module)) return False if vt_report["results"]["positives"] >= self.vt_threshold: self.logger.log_bad( "Suspicious EFI binary found in the UEFI firmware image\n{}". format(efi_module)) return True if self.logger.VERBOSE: self.logger.log( "Benign EFI binary found in the UEFI firmware image\n{}". format(efi_module)) return False def check_reputation(self): res = ModuleResult.PASSED # parse the UEFI firmware image and look for EFI modules matching the balck-list efi_tree = build_efi_model(self.uefi, self.image, None) match_types = EFIModuleType.SECTION_EXE matching_modules = search_efi_tree(efi_tree, self.reputation_callback, match_types) found = len(matching_modules) > 0 self.logger.log('') if found: res = ModuleResult.WARNING self.logger.log_warn_check( "Suspicious EFI binary found in the UEFI firmware image") else: self.logger.log_passed_check( "Didn't find any suspicious EFI binary") return res def usage(self): self.logger.log(USAGE_TEXT) # -------------------------------------------------------------------------- # run( module_argv ) # Required function: run here all tests from this module # -------------------------------------------------------------------------- def run(self, module_argv): self.logger.start_test( "Check for suspicious EFI binaries in UEFI firmware") self.usage() if len(module_argv) > 0: self.vt = VirusTotalPublicApi(module_argv[0]) if len(module_argv) > 1: self.vt_threshold = int(module_argv[1]) image_file = DEF_FWIMAGE_FILE if len(module_argv) > 2: # Use provided firmware image image_file = module_argv[2] self.logger.log( "[*] reading FW image from file: {}".format(image_file)) else: # Read firmware image directly from SPI flash memory self.spi = SPI(self.cs) (base, limit, freg) = self.spi.get_SPI_region(BIOS) image_size = limit + 1 - base self.logger.log( "[*] dumping FW image from ROM to {}: 0x{:08X} bytes at [0x{:08X}:0x{:08X}]" .format(image_file, base, limit, image_size)) self.logger.log( "[*] this may take a few minutes (instead, use 'chipsec_util spi dump')..." ) self.spi.read_spi_to_file(base, image_size, image_file) self.image = read_file(image_file) return self.check_reputation()