def pack_delete(request): pack_id = ReqParams.one(request, 'pack_id') # delete fw_files_storage # delete fw_files # delete pack_files_storage # delete pack_files file_list = FwFileDO.search_files_of_pack(pack_id) for file in file_list: FwFilesStorage.delete(file['file_id']) # if len(file_list) > 0: FwFileDO.delete_many_of_pack(pack_id) pack_info = PackFileDO.fetch_pack(pack_id) PackFilesStorage.delete(pack_info['file_id']) PackFileDO.delete(pack_id) # 保存操作日志 LogRecords.save('', category='statistics', action='删除固件包', desc='删除指定固件包(ID=%s)的信息,' % pack_id) return sys_app_ok_p([])
def save_proc(self, name, path, file_type, content, index, total, extra_props=None): name = str(name) file_id = StrUtils.uuid_str() # 保存文件参数 FwFileDO.save_file_item(self.pack_id, file_id, name, file_type, file_path=path, extra_props=extra_props) # 保存文件内容 FwFilesStorage.save(file_id, name, path, file_type, content) percent = (index + 1) * 100.0 / total MyTask.save_task_percentage(self.task_id, percent) return not MyTask.is_task_stopped(self.task_id)
def verify_all_exec_bin_files(self, pack_id, image_file_name, task_id): # 获取本固件包所有的二进制可执行文件记录 bin_files_list = FwFileDO.search_files_of_pack(pack_id, FileType.EXEC_FILE) # 枚举每个文件,读出其文件数据,校验 total_count = len(bin_files_list) for index, file_item in enumerate(bin_files_list): # 检查任务状态 if MyTask.is_task_stopped(task_id): break # 保存任务执行百分比 self._save_task_percentage(task_id, index, total_count) # 注意:此处一定要设置覆写,否则判定的是旧文件数据,造成判定结果错误 file_path = FwFilesStorage.export(file_item['file_id'], file_name=task_id, override=True) file_type, extra_props = FsBase.verify_exec_bin_file(file_path) # 修改文件的类型属性,或增加可执行二进制文件的CPU架构 # 暂时不更新存储桶中的“内容类型” FwFileDO.update_verified_file_type(file_item['file_id'], file_type, extra_props=extra_props) # 保存任务完成状态 MyTask.save_exec_info(task_id, 100.0) # 完成验证二进制文件,启动任务cfg_analyze PackFiles.start_exec_bin_cfg_analyze_task(self.pack_id, image_file_name)
def check_component(pack_id, task_id): MyRedis.set('running_check_com_flag', True) # 获取本固件包所有的二进制可执行文件记录 fw_files_list = FwFileDO.search_files_of_pack(pack_id, FileType.EXEC_FILE) pack_item = PackFileDO.fetch_pack(pack_id) process_file_name = pack_item.get('name') # pack_item['name'] MyTask.save_exec_info_name(task_id, process_file_name) # 枚举每个文件,根据文件名检索组件库(make),校验 total_count = len(fw_files_list) for index, file_item in enumerate(fw_files_list): percentage = round(index * 100 / total_count, 1) MyTask.save_exec_info(task_id, percentage) componentinfo = MakeCOMFileDO.search_component_name( file_item['file_name']) if componentinfo is None: continue FwFileDO.set_component(file_item['file_id'], 1) # 相似度匹配计算,标记漏洞(version / edbid) fw_file_id = file_item['file_id'] component_file_id = componentinfo['file_id'] print(SysUtils.get_now_time()) # 计算相似度 比较耗时 openssl计算大约两分钟 similarity = assembly.calc_cosine_algorithm(fw_file_id, component_file_id) print(SysUtils.get_now_time()) # 相似度阈值设定: 0-100 if similarity < utils.sys.config.g_similarity: print(similarity) continue # 相似度大于阈值 标记漏洞(version / edbid) com_file_info = PackCOMFileDO.fetch_pack(componentinfo['pack_id']) version = com_file_info['version'] name = com_file_info['name'] edb_id = com_file_info['edb_id'] FwFileDO.set_component_extra_props( fw_file_id, { 'version': version, 'name': name, 'edb_id': edb_id, 'similarity': similarity }) MyRedis.set('running_check_com_flag', False) # 保存任务完成状态 MyTask.save_exec_info(task_id, 100.0) return
def remove_virtual_pack(pack_id): # 获取该固件包关联的所有文件 ID files_list = FwFileDO.get_files_of_pack(pack_id) file_id_list = [file_item['file_id'] for file_item in files_list] # 移除存储桶中的文件内容 FwFilesStorage.delete_many(file_id_list) # 移除该固件包关联的所有文件记录 FwFileDO.delete_many_of_pack(pack_id) # 移除固件包记录 PackFileDO.delete(pack_id)
def cfg_all_exec_bin_files(self, pack_id, task_id): # 获取本固件包所有的二进制可执行文件记录 bin_files_list = FwFileDO.search_files_of_pack(pack_id, FileType.EXEC_FILE) # 枚举每个文件,读出其文件数据,校验 total_count = len(bin_files_list) for index, file_item in enumerate(bin_files_list): # 检查任务状态 if MyTask.is_task_stopped(task_id): break # 保存任务执行百分比 self._save_task_percentage(task_id, index, total_count) # 注意:此处一定要设置覆写,否则判定的是旧文件数据,造成判定结果错误 file_id = file_item['file_id'] file_path = FwFilesStorage.export(file_item['file_id'], file_name=task_id, override=True) is_cfg = CfgAnalyzeService.has_cfg_analyze(file_id) if not is_cfg: try: # 通过 project 快速解析文件 angr_proj = AngrProj(file_id, progress_callback=self.run_percent_cb, task_id=task_id, cfg_mode='cfg_fast') # 从 project 中提取函数列表 functions = FunctionParse.functions_extract(angr_proj.proj) # 保存 函数列表到数据库 FileCacheDAO.save_functions(file_id, functions) arch = str(angr_proj.proj.arch) # 设置文件已完成 CFG 分析的标记 FwFileDO.set_cfg_analyzed(file_id, 1, arch) PackFileDO.updateArch(pack_id, arch) except Exception as e: print(e) # 保存任务完成状态 MyTask.save_exec_info(task_id, 100.0) # 包分析完成标志 PackFileDO.analyze_complet(pack_id, 1)
def _get_arch(self, file_id): file_item = FwFileDO.find(file_id) # if file_item['extra_props'] is None or file_item['extra_props']['arch'] is None: if file_item.get('extra_props') is None: return 'ARM', None else: return file_item['extra_props'].get( 'arch'), file_item['extra_props'].get('endianness')
def pack_exec_files_tree(request): pack_id, tree_type = ReqParams.many(request, ['pack_id', 'tree_type']) start_check_component_task(pack_id) # # # 检查组件关联 # # check_component(pack_id, FileType.EXEC_FILE) # # 修改为任务处理方式进行检查组件关联 关联组件标记,相似度匹配计算,标记漏洞(version/edbid) # # 启动编译任务 # extra_info = {'task_type': TaskType.COMPONENT_CHECK, # 'task_name': '检查组件关联', # 'task_desc': '检查组件关联,相似度匹配计算,标记漏洞(version/edbid)'} # task = MyTask(check_component, (pack_id,), extra_info=extra_info) # task_id = task.get_task_id() # 读取所有可执行文件 exec_list = FwFileDO.search_files_of_pack(pack_id, FileType.EXEC_FILE) if tree_type is None or len(tree_type) == 0 or tree_type == 'normal': # file_path_insert_into_tree 树,初始化为字典 tree_type = 'normal' exec_tree = {} elif tree_type == 'antd': # file_path_insert_into_antd_tree 树,初始化为数组 exec_tree = [] else: tree_type = 'normal' exec_tree = {} # 对每个文件做树的各级节点定位和创建 for exec_file in exec_list: # 获取文件路径 file_path = exec_file['file_path'] file_id = exec_file['file_id'] component = exec_file['component'] # if exec_file['component'] is not None: # component = exec_file['component'] # else: # component = 0 if file_path is None or len(file_path) == 0: continue if tree_type == 'normal': MyTree.file_path_insert_into_tree(exec_tree, file_path, file_id, component) elif tree_type == 'antd': MyTree.file_path_insert_into_antd_tree(exec_tree, file_path, file_id, component) # 保存操作日志 LogRecords.save('', category='statistics', action='读取固件包文件结构', desc='获取指定固件包(ID=%s)的文件结构(模式为:%s)' % (pack_id, tree_type)) return sys_app_ok_p(exec_tree)
def has_cfg_analyze(file_id): try: item = FwFileDO.find(file_id) item['cfg_analyze'] == 1 except Exception as e: # print(e) return False return True
def analyze_cfg_proc(self, file_id, task_id): self.task_id = task_id # 通过 project 快速解析文件 angr_proj = AngrProj(file_id, progress_callback=self.run_percent_cb, task_id=task_id, cfg_mode='cfg_fast') # 从 project 中提取函数列表 functions = FunctionParse.functions_extract(angr_proj.proj) # 保存 函数列表到数据库 FileCacheDAO.save_functions(file_id, functions) print(str(angr_proj.proj.arch)) arch = str(angr_proj.proj.arch) # 设置文件已完成 CFG 分析的标记 FwFileDO.set_cfg_analyzed(file_id, 1, arch)
def has_detect_overflow(file_id): try: item = FwFileDO.find(file_id) if item['file_detect_overflow'] == 1: return True except Exception as e: # print(e) return False return False
def com_files_list(request): # 读取所有组件文件 com_list = FwFileDO.search_all_com_files() print(com_list) comlist = [] for com in com_list: print(com) inverted = com.get('inverted') cfg_analyze = com.get('cfg_analyze') file_type_verified = com.get('file_type_verified') extra_props = com.get('extra_props') if extra_props is not None: extra_props.setdefault('name', '') extra_props.setdefault('version', '') extra_props.setdefault('edb_id', '') extra_props.setdefault('similarity', '') name = extra_props['name'] version = extra_props['version'] edb_id = extra_props['edb_id'] similarity = extra_props['similarity'] else: name = "" version = "" edb_id = "" similarity = "" doc = { 'file_id': com['file_id'], 'file_path': com['file_path'], 'component': com['component'], 'create_time': com['create_time'], 'file_name': com['file_name'], 'file_type': com['file_type'], 'pack_id': com['pack_id'], 'version': version, 'name': name, 'edb_id': edb_id, 'file_type_verified': file_type_verified, 'cfg_analyze': cfg_analyze, 'inverted': inverted, 'similarity': similarity, 'fw_name': com['pack_docs'][0]['name'] } comlist.append(doc) # 保存操作日志 LogRecords.save('', category='statistics', action='查询所有组件文件列表', desc='查询所有组件文件列表') return sys_app_ok_p(comlist)
def _save_image(file_index, pack_id): # 获取 文件的路径和文件类型 file_path = LoadDefaultPack._get_fw_file_path(file_index) if file_path is None: return None # 文件类型 file_type = LoadDefaultPack._get_file_type(file_index) # 新的文件 UUID file_id = StrUtils.uuid_str() # 读取文件内容 contents = MyFile.read(file_path) # 保存文件记录 FwFileDO.save_file_item(pack_id, file_id, os.path.basename(file_path), file_type) # 保存文件内容 FwFilesStorage.save(file_id, os.path.basename(file_path), os.path.basename(file_path), file_type, contents) return file_id
def _save_file_db(path_file_name, pack_id): # 获取 文件的路径和文件类型 # file_path = _get_fw_file_path(virtual_id) # if file_path is None: # return None # print(path_file_name) file_path, file_name = os.path.split(path_file_name) # 新的文件 UUID file_id = StrUtils.uuid_str() # 获取文件类型 内容 file_type, contents = check_file_type(path_file_name) # file_type = _get_file_type(file_name) if contents is None: # linux 系统下 BINWALK会提取出空目录,读目录文件为None return None # 保存文件记录 FwFileDO.save_file_item(pack_id, file_id, file_name, file_type, file_path) # 保存文件内容 FwFilesStorage.save(file_id, file_name, file_path, file_type, contents) # 返回文件ID return file_id
def add_single_exec(file_name, file_data): # 新的 pack ID pack_id = StrUtils.uuid_str() # 保存虚拟包记录 PackFileDO.save(pack_id, '', name=file_name, pack_type=PackType.VIRTUAL, file_type=FileType.PACK) # 新的 pack 文件 UUID exec_file_id = StrUtils.uuid_str() # 保存文件记录 FwFileDO.save_file_item(pack_id, exec_file_id, file_name, FileType.EXEC_FILE) # 在存储桶中保存文件数据 # 保存文件内容 FwFilesStorage.save(exec_file_id, file_name, file_name, FileType.EXEC_FILE, file_data) return pack_id, exec_file_id
def analyze_cfg_proc_auto(self, task_id): # 查询所有文件 list_file_id = FwFileDO._db_get_all_file(FileType.EXEC_FILE) for file in list_file_id: # print(file) file_id = file['file_id'] is_cfg = CfgAnalyzeService.has_cfg_analyze(file_id) if not is_cfg: # 启动分析任务 self.task_id = task_id self.file_id = file_id try: # 通过 project 快速解析文件 angr_proj = AngrProj(file_id, progress_callback=self.run_percent_cb, task_id=task_id, cfg_mode='cfg_fast') # angr_proj = AngrProj(file_id, progress_callback=self.run_percent_cb, cfg_mode='cfg_fast') # 从 project 中提取函数列表 functions = FunctionParse.functions_extract(angr_proj.proj) # 保存 函数列表到数据库 FileCacheDAO.save_functions(file_id, functions) print(str(angr_proj.proj.arch)) arch = str(angr_proj.proj.arch) # 设置文件已完成 CFG 分析的标记 FwFileDO.set_cfg_analyzed(file_id, 1, arch) # PackFileDO.updateArch(arch) time.sleep(1) except Exception as e: print(e)
def remove_pack_proc(self, pack_id, task_id): # 获取该固件包关联的所有文件 ID files_list = FwFileDO.get_files_of_pack(pack_id) file_id_list = [file_item['file_id'] for file_item in files_list] # 第一步,总进度条的 0-80% # 移除存储桶中,该固件包关联的所有文件 total_count = len(file_id_list) for index, file_id in enumerate(file_id_list): if MyTask.is_task_stopped(task_id): return self._save_task_percentage(task_id, index, total_count, 80.0) FwFilesStorage.delete(file_id) # print('delete {} of {}'.format(index, total_count)) # time.sleep(2) # FwFilesStorage.delete_many(file_id_list) # 第二步,总进度条的 80-85% # 移除存储桶中,固件包自身文件 MyTask.save_task_percentage(task_id, 80.0) pack_item = PackFileDO.fetch_pack(pack_id) pack_file_id = pack_item['file_id'] PackFilesStorage.delete(pack_file_id) # 第三步,总进度条的 85-95% # 移除该固件包关联的所有文件记录 MyTask.save_task_percentage(task_id, 85.0) FwFileDO.delete_many_of_pack(pack_id) # 第四步,总进度条的 95-100% # 移除该固件包自身记录 MyTask.save_task_percentage(task_id, 95.0) PackFileDO.delete(pack_id) # 完成任务 MyTask.save_task_percentage(task_id, 100.0)
def get_unpack_files_stat(self): pack_id = self.pack_id file_type_list = PackInfoService._file_type_list() unpack_files = {} for file_type in file_type_list: # 不统计固件包的文件数量 if file_type == FileType.PACK: continue # 获取文件类型的别名 alias = FileType.get_alias(file_type) # 统计指定类型文件的数量 count = FwFileDO.count_files(pack_id, file_type) unpack_files[str(file_type)] = {'alias': alias, 'count': count} fw_files = {'unpack_files': unpack_files} return fw_files
def vuler_association(request): print('vuler_association') file_id, version, name, edb_id = ReqParams.many( request, ['file_id', 'version', 'name', 'edb_id']) rv = FwFileDO.set_component_extra_props(file_id, { 'version': version, 'name': name, 'edb_id': edb_id }) # 保存操作日志 LogRecords.save('', category='statistics', action='组件手动漏洞关联', desc='组件手动漏洞关联(漏洞编号 版本 名称)') if rv.matched_count == 1: return sys_app_ok_p('组件手动漏洞关联成功') else: return sys_app_ok_p('组件手动漏洞关联失败,文件未找到')
def com_files_tree(request): tree_type = ReqParams.one(request, 'tree_type') # 读取所有组件文件 com_list = FwFileDO.search_all_com_files() if tree_type is None or len(tree_type) == 0 or tree_type == 'normal': tree_type = 'normal' exec_tree = {} elif tree_type == 'antd': exec_tree = [] else: tree_type = 'normal' exec_tree = {} # 对每个文件做树的各级节点定位和创建 for exec_file in com_list: # 获取文件路径 file_path = exec_file['file_path'] file_id = exec_file['file_id'] component = exec_file['component'] if file_path is None or len(file_path) == 0: continue if tree_type == 'normal': MyTree.file_path_insert_into_tree(exec_tree, file_path, file_id) elif tree_type == 'antd': MyTree.file_path_insert_into_antd_tree(exec_tree, file_path, file_id) # 保存操作日志 LogRecords.save('', category='statistics', action='查询所有组件文件目录树', desc='获取所有组件文件目录树结构(模式为:%s)' % (tree_type)) return sys_app_ok_p(exec_tree)
def open_image(self): # 查找指定包的 FS 镜像文件 file_docs = FwFileDO.search_files_of_pack(self.pack_id, FileType.FS_IMAGE) if len(file_docs) == 0: print("find nothing file_docs") return # 只取第一个镜像文件 image_file = file_docs[0] # 导出镜像文件到临时目录 image_file_path = FwFilesStorage.export(image_file['file_id']) # 返回实际文件名 任务对应文件名 image_file_name = image_file['file_name'] # 解析镜像文件 image, fs = self.parse_image_file(image_file, image_file_path) # 尝试 SquashFS 解析,并验证 # image = SquashFS(image_file_path) # if image.check_format(): # pass return image, image_file_name, fs
def detect_vulner(request): file_id = ReqParams.one(request, 'file_id') # pack_id = ReqParams.one(request, 'pack_id') # fw_vul_analyze = FwVulnerAnalyze(file_id) # res = fw_vul_analyze.vuler_analyze() # return sys_app_ok_p({'res': res}) # 查询文件 detect 分析的标记 is_detect = OverflowDetectService.has_detect_overflow(file_id) if not is_detect: # 启动detect任务 task_id = OverflowDetectService.start_detect_task(file_id) # 保存操作日志 LogRecords.save({ 'task_id': task_id, 'file_id': file_id }, category='analysis', action='分析OVERFLOW', desc='对二进制文件做溢出漏洞分析') # 返回响应:任务初始化的信息 return sys_app_ok_p(MyTask.fetch_exec_info(task_id)) file_item = FwFileDO.find(file_id) buffer_overflow = file_item.get('buffer_overflow') integer_overflow = file_item.get('integer_overflow') cmd_injection_overflow = file_item.get('cmd_injection_overflow') # return sys_app_ok_p({'缓冲区溢出': buffer_overflow, '整数溢出': integer_overflow, '命令注入溢出': cmd_injection_overflow}) overflow_list = [] overflow_list.append({"name": "缓冲区溢出", "value": buffer_overflow}) overflow_list.append({"name": "整数溢出", "value": integer_overflow}) overflow_list.append({"name": "命令注入溢出", "value": cmd_injection_overflow}) return sys_app_ok_p({'overflow': overflow_list})
def detect(self): type_name, buffer_overflow = Overflow_Detect.buffer_overflow(self) FwFileDO.set_file_detect_overflow(self.file_id, buffer_overflow, None, None) return buffer_overflow
def inverted(self, file_id): file_result = fw_files_col.find({'file_id': file_id}) file_list = list(file_result) if file_list is None or len(file_list) == 0: return sys_app_err('ERROR_INVALID_PARAMETER') filePo = file_list[0] file_path = filePo.get('file_path') # file_path = 'E:/samples/argv_test' # file_path = 'E:/samples/py_code.txt' dict1 = {} dict2 = {} sentences = InvertedIndex.read_file(self, file_path) sentencesLen = len(sentences) for i in range(sentencesLen): sentence = sentences[i] for word in sentence: if word == '': continue if word.lower() not in dict1: dict1[word.lower()] = set() # new word dict2[word.lower()] = 1 else: dict2[word.lower()] += 1 dict1[word.lower()].add(i + 1) # update for dictionary answer_list = sorted(dict2.items(), key=lambda d: d[1], reverse=True) # Sort by wordcount of dictionary. answer_sort_ascll = sorted(answer_list, key=lambda x: x[0]) for word in answer_sort_ascll: word0 = InvertedIndex.str_to_hex(word[0]).replace('/x0', '') sort_dotid = sorted(dict1[word[0]]) position = '' for i in range(len(sort_dotid)): position += str(sort_dotid[i]) if i != (len(sort_dotid) - 1): position += ',' index_con = word0 index_con_str = InvertedIndex.hex_to_str(word0) appear_total = word[1] vulner_info = { 'file_id': file_id, 'file_path': file_path, 'index_con': index_con, 'appear_total': appear_total, 'position': position } result = file_inverted_col.find({ 'file_id': file_id, 'index_con': index_con, 'appear_total': appear_total }) item_list = list(result) if (item_list is None or len(item_list) == 0) and len(index_con) > 0 and len(index_con_str) > 10: file_inverted_col.save(vulner_info) # 对组件列表增加建立 inverted 完成标志 FwFileDO.set_inverted(file_id) return sys_app_ok()