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 stop_running_tasks_of_pack(pack_id): tasks_list = TasksDAO.search_by_pack(pack_id) for task_info in tasks_list: task_status = task_info['task_status'] # 没有执行完成的任务状态,用缓存中任务信息代替 if task_status == TaskStatus.START or task_status == TaskStatus.RUNNING: MyTask.stop_task(task_info['task_id'])
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 _proc_func_info(file_id, func_addr, task_id): # 通过 project 快速解析文件 angr_proj = AngrProj(file_id, progress_callback=run_percent_cb, task_id=task_id) # 生成函数解析对象 func_parse = FwFuncParse(angr_proj) # 读取函数的汇编代码 asm = func_parse.func_asm(func_addr) # print(asm) # 读取函数的中间代码 vex = func_parse.func_vex(func_addr) # print(vex) # 获取函数的后继调用 successors = func_parse.func_successors(func_addr) # print(successors) # 保存执行完成后的状态和结果集 MyTask.save_exec_info( task_id, 100.0, { 'asm': str(asm), 'vex': str(vex), 'successors_count': len(successors), 'successors': successors }) return
def async_fw_functions_list(request): # 从请求中取参数:文件 ID file_id = req_get_param(request, 'file_id') # 启动分析任务 task = MyTask(_proc_fw_functions_list, (file_id, )) task_id = task.get_task_id() # 返回响应:任务初始化的信息 return sys_app_ok_p(MyTask.fetch_exec_info(task_id))
def auto_cfg_task(): cfg_analyze = CfgAnalyzeService('') extra_info = { 'task_type': TaskType.CFG_ANALYZE, 'task_name': '控制流分析', 'task_desc': '进行控制流分析,保存 CFG graph 和函数列表。' } task = MyTask(cfg_analyze.analyze_cfg_proc_auto, extra_info=extra_info) # task = MyTask(cfg_analyze.analyze_cfg_proc_auto,) return task.get_task_id()
def start_detect_task(file_id): detect = OverflowDetectService(file_id) extra_info = { 'file_id': file_id, 'task_type': TaskType.DETECT_OVERFLOW, 'task_name': '检测漏洞溢出', 'task_desc': '检测漏洞溢出,保存 缓冲区 整数 命令注入溢出输入数据。' } task = MyTask(detect.detect_overflow_proc, (file_id, ), extra_info=extra_info) return task.get_task_id()
def start_remove_packs_task(pack_id): pack_proc_serv = PackProcessService() extra_info = { 'pack_id': pack_id, 'task_type': TaskType.REMOVE_FW_PACKS, 'task_name': '清空固件包', 'task_desc': '清空指定固件包(ID: {})下的所有文件项,并删除其文件内容。'.format(pack_id) } task = MyTask(pack_proc_serv.remove_pack_proc, (pack_id, ), extra_info=extra_info) return task.get_task_id()
def start_cfg_task(file_id): cfg_analyze = CfgAnalyzeService(file_id) extra_info = { 'file_id': file_id, 'task_type': TaskType.CFG_ANALYZE, 'task_name': '控制流分析', 'task_desc': '进行控制流分析,保存 CFG graph 和函数列表。' } task = MyTask(cfg_analyze.analyze_cfg_proc, (file_id, ), extra_info=extra_info) return task.get_task_id()
def async_fwdownload(request): # 获取下载URL downloadurl = req_get_param(request, 'url') print(downloadurl) # 启动下载任务 task = MyTask(_proc_func_download, (downloadurl, settings.FW_PATH, )) task_id = task.get_task_id() # 返回响应:任务初始化的信息 return sys_app_ok_p(MyTask.fetch_exec_info(task_id))
def async_function_call_graph(request): # 从请求中取参数:文件 ID,函数地址 file_id, func_addr = _req_params(request) # 启动分析任务 task = MyTask(_proc_func_call_graph, ( file_id, func_addr, )) task_id = task.get_task_id() # 返回响应:任务初始化的信息 return sys_app_ok_p(MyTask.fetch_exec_info(task_id))
def run_percent_cb(self, percentage, **kwargs): if self.task_id is None: return task_id = self.task_id # 调试信息打印 # info = 'Func-list({}): {}%'.format(task_id, percentage) # print(info) # print(self.task_id) # 只在运行百分比变化时才更新任务状态 MyTask.save_task_percentage(task_id, percentage)
def async_funcs_fetch(request): # 获取固件ID firmware_id = req_get_param(request, 'firmware_id') # 启动任务 存储桶读取固件内容 task = MyTask(_proc_fetch, (firmware_id, settings.FW_PATH)) task_id = task.get_task_id() # 保存操作日志 LogRecords.save({'task_id': task_id, 'file_id': firmware_id}, category='fetch', action='下载固件', desc='存储桶读取固件保存并进行文件抽取') # 返回响应:任务初始化的信息 return sys_app_ok_p(MyTask.fetch_exec_info(task_id))
def _proc_compile_tasks(arch, pack_id, task_id): # 1 DB中导出源码文件/目录 path, file_name = export_files(pack_id) print(path) if path is None: print("export_files error") MyTask.save_exec_info(task_id, 0, {'compile': "组件源码编译失败,导出组件库源码失败"}) PackCOMFileDO.set_compile_flag(pack_id, CompileStatus.failed) return MyTask.save_exec_info_name(task_id, file_name) # cmd = 'tar -xzvf ' + file_name # runcmd(cmd) # 2 make if arch == 'x86': build_path, exit_code = compile_x86(file_name, task_id) elif arch == 'arm': build_path, exit_code = compile_arm(file_name, task_id) if exit_code != 0: MyTask.save_exec_info(task_id, 100, {'compile': "组件源码编译操作失败"}) return # 3 save make file to db save_make_files(pack_id, build_path, arch) # 4 set compile flag PackCOMFileDO.set_compile_flag(pack_id, CompileStatus.success) total_percentage = 100.0 MyTask.save_exec_info(task_id, total_percentage, {'compile': "组件源码编译操作完成"})
def start_fs_image_extract_task(pack_id): fs_image = FsImage(pack_id) # if fs_image.image is None: # return extra_info = { 'pack_id': pack_id, 'task_type': TaskType.FS_EXTRACT, 'task_name': '文件系统解析', 'task_desc': '从文件系统镜像包中提取文件,判断文件类型,并保存文件内容到数据库中。' } task = MyTask(fs_image.fs_image_extract, (pack_id, ), extra_info=extra_info) return task.get_task_id()
def _proc_func_call_graph(file_id, func_addr, task_id): # 生成 project 对象,但不做 cfg_fast 解析 angr_proj = AngrProj(file_id, cfg_mode='cfg_emu', progress_callback=run_percent_cb, task_id=task_id) # 解析并生成调用流程图的数据 func_parse = FwFuncParse(angr_proj) graph = func_parse.call_graph(func_addr) # 保存执行完成后的状态和结果集 b64_graph = base64.b64encode(graph).decode() MyTask.save_exec_info(task_id, 100.0, {'call_graph': b64_graph})
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 async_com_download(request): com_download_url = ReqParams.one(request, 'url', protocol='POST') # 启动下载任务 extra_info = {'task_type': TaskType.REMOTE_DOWNLOAD, 'task_name': '组件源码下载', 'task_desc': '下载组件源码入库存储桶'} task = MyTask(_proc_component_tasks, (com_download_url, MyPath.component()), extra_info=extra_info) task_id = task.get_task_id() # 保存操作日志 LogRecords.save({'task_id': task_id}, category='download', action='组件源码下载', desc='下载组件源码入库存储桶') # 返回响应:任务初始化的信息 return sys_app_ok_p(MyTask.fetch_exec_info(task_id))
def _proc_fw_functions_list(file_id, task_id): cfg_progress = CfgProgress(task_id=task_id) # 通过 project 快速解析文件 angr_proj = AngrProj(file_id, progress_callback=cfg_progress.run_percent_cb, task_id=task_id) # 获取代码中的函数列表 func_parse = FwFuncParse(angr_proj) functions = func_parse.func_list() # 保存执行完成后的状态和结果集 MyTask.save_exec_info(task_id, 100.0, { 'functions_count': len(functions), 'functions': functions })
def auto_vuler_association(request): pack_id = ReqParams.one(request, 'pack_id') task_id = start_check_component_task(pack_id) if task_id is None: return sys_app_ok_p("自动组件漏洞关联正在运行中") return sys_app_ok_p(MyTask.fetch_exec_info(task_id))
def fs_image_extract(self, pack_id, task_id): self.task_id = task_id image, image_file_name, fs = self.open_image() PackFileDO.savefs(self.pack_id, fs) # 任务关联文件名 MyTask.save_exec_info_name(task_id, image_file_name) # 在主进程或任务中,采用预订的文件系统抽取文件 if image.extract_files(extract_func=self.save_proc): # 正常处理完毕后,保存任务完成状态 MyTask.save_exec_info(task_id, 100.0) # 完成抽取后,启动任务检验该包中所有可执行二进制文件的验证 PackFiles.start_exec_bin_verify_task(self.pack_id, image_file_name)
def get_task_result(request): # 从请求中取参数:文件 ID task_id = req_get_param(request, 'task_id') # 从缓存中读取任务执行信息 task_info = MyTask.fetch_exec_info(task_id) return sys_app_ok_p(task_info)
def async_fwdownload(request): # 获取下载URL fw_download_url, ftp_user, ftp_password = ReqParams.many(request, ['url', 'user', 'password'], protocol='POST') # 启动下载任务 extra_info = {'task_type': TaskType.REMOTE_DOWNLOAD, 'task_name': '固件下载', 'task_desc': '下载固件入库存储桶并进行文件抽取操作'} task = MyTask(_proc_tasks, (fw_download_url, settings.FW_PATH, ftp_user, ftp_password), extra_info=extra_info) task_id = task.get_task_id() # 保存操作日志 LogRecords.save({'task_id': task_id}, category='download', action='固件下载', desc='下载固件入库存储桶并进行文件抽取操作') # 返回响应:任务初始化的信息 return sys_app_ok_p(MyTask.fetch_exec_info(task_id))
def _proc_tasks(fw_download_url, g_fw_save_path, ftp_user, ftp_password, task_id): print("download task_id", task_id) # 检查本地保存路径 没有则创建 SysUtils.check_filepath(g_fw_save_path) # 1 时间消耗总占比30 执行下载操作 total_percentage = 30.0 ret_download_info = fw_filename = "" file_list = [] if 'ftp://' in fw_download_url: ret_download_info, fw_filename, file_list = Mydownload.ftp_download(fw_download_url, g_fw_save_path, ftp_user, ftp_password, task_id, total_percentage) else: ret_download_info, fw_filename, file_list = Mydownload.http_download(fw_download_url, g_fw_save_path, task_id, total_percentage) print(ret_download_info, fw_filename) MyTask.save_exec_info_name(task_id, fw_filename) # 2 时间消耗总占比0 保存到 pack_file to mongodb pack_id, pack_file_id = _save_pack_db(fw_download_url, os.path.join(g_fw_save_path, fw_filename), ret_download_info, task_id) MyTask.save_exec_info_pack_id(task_id, pack_id) # 3 时间消耗总占比0 解压缩固件包->系统镜像文件,提取文件到mongo img_filename = _proc_uncompress(os.path.join(g_fw_save_path, fw_filename), g_fw_save_path, task_id) if len(img_filename) == 0: print("package uncompress error") img_filename = fw_filename # bin文件做为包名(文件名) # return "package uncompress error" # 4 时间消耗总占比0 保存系统镜像文件 to mongodb file_id = _save_file_db(os.path.join(g_fw_save_path, img_filename), pack_id) # 5 时间消耗总占比40 BIN提取子文件 total_percentage = 70.0 extract_bin_files = MyBinwalk.binwalk_file_extract(os.path.join(g_fw_save_path, img_filename)) MyTask.save_exec_info(task_id, total_percentage, {'binwalk_file_extract': extract_bin_files}) for file in extract_bin_files: # binwalk解包返回的文件名带全路径 # 对变量类型进行判断 list 值带[] 如: ['C:\\GIT\\firmware_analyze_serv\\files\\firmware\\_CF-EW71-V2.6.0.bin-2.extracted\\40'] if isinstance(file, list): file_id = _save_file_db(file[0], pack_id) else: file_id = _save_file_db(file, pack_id) # 6 时间消耗总占比30 提取文件系统 FsImage.start_fs_image_extract_task(pack_id) total_percentage = 100.0 MyTask.save_exec_info(task_id, total_percentage, {'download': "固件下载、提取、入库操作完成"}) # 7 clear temp files return 'ERROR_OK'
def run_percent_cb(self, percentage, **kwargs): # 由于大于50%进程后没有 project 可以获取,需要做进度百分比转换 # if 'cfg' in kwargs: # if 'cfg' in kwargs: # 从动态参数中获取 project 中保存的任务 ID # task_id = kwargs['cfg'].project.my_task_id task_id = self.task_id # 调试信息打印 info = 'Func-list({}): {}%'.format(task_id, percentage) print(info) print(self.task_id) # 只在运行百分比变化时才更新任务状态 new_percentage = self.translate_percent(percentage) exec_info = MyTask.fetch_exec_info(task_id) old_percentage = exec_info['percentage'] if new_percentage != old_percentage: MyTask.save_exec_info(task_id, new_percentage)
def stop_task(request): # 从请求中取参数:任务 ID task_id = req_get_param(request, 'task_id') task_info = MyTask.stop_task(task_id) # 保存操作日志 LogRecords.save(task_info, category='task', action='停止任务', desc='停止指定的任务(ID=%s)' % task_id) return sys_app_ok_p(task_info)
def start_check_component_task(pack_id): # 检查组件关联是否运行,运行中则跳过 isrun = MyRedis.get('running_check_com_flag') if isrun: return None # # 检查组件关联 # 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() return task_id
def test(request): value = ReqParams.one(request, 'value', protocol='GET') # 启动下载任务 extra_info = { 'task_type': TaskType.REMOTE_DOWNLOAD, 'task_name': 'test组件源码下载', 'task_desc': 'test下载组件源码入库存储桶' } task = MyTask(_proc_inverted_tasks, (value, MyPath.component()), extra_info=extra_info) task_id = task.get_task_id() # 保存操作日志 LogRecords.save({'task_id': task_id}, category='download', action='test组件源码下载', desc='test下载组件源码入库存储桶') # 返回响应:任务初始化的信息 return sys_app_ok_p(MyTask.fetch_exec_info(task_id))
def get_task_result(request): # 从请求中取参数:任务 ID task_id = req_get_param(request, 'task_id') # 从缓存中读取任务执行信息 task_info = MyTask.fetch_exec_info(task_id) # 保存操作日志 LogRecords.save(task_info, category='query_task', action='查询任务状态', desc='读取任务(ID=%s)当前执行状态及结果信息' % task_id) return sys_app_ok_p(task_info)
def inverted(request): # 获取参数 file_id = req_get_param(request, 'file_id') # 启动编译任务 extra_info = { 'task_type': TaskType.INVERTED, 'task_name': '倒排索引', 'task_desc': '建立倒排索引' } task = MyTask(_proc_inverted_tasks, (file_id, ), extra_info=extra_info) task_id = task.get_task_id() # 保存操作日志 LogRecords.save({'task_id': task_id}, category='compile', action='倒排索引', desc='建立倒排索引') # 返回响应:任务初始化的信息 return sys_app_ok_p(MyTask.fetch_exec_info(task_id))