def add_or_update(username=None, password=None, password_type=None, tag=None, source_module=None, host_ipaddress=None, desc=None): if tag is None: tag = {} if isinstance(tag, dict) is not True: logger.warning('数据类型检查错误,数据 {}'.format(tag)) tag = {} if password is '' or password.find('n.a.(') > 0 or len(password) > 100: return False # 没有此主机数据时新建 default_dict = { 'username': username, 'password': password, 'password_type': password_type, 'tag': tag, 'source_module': source_module, 'host_ipaddress': host_ipaddress, 'desc': desc } CredentialModel.objects.update_or_create(username=username, password=password, password_type=password_type, tag=tag, defaults=default_dict) return True
def deal_path(path=None): """处理成linux路径""" tmppath = path.replace('\\\\', '/').replace('\\', '/') if re.match("^/[a-zA-Z]:/", tmppath) is not None: tmppath = tmppath[1:] # 只支持最后加/..和/../ if tmppath.startswith('/'): # linux路径 if tmppath.endswith('/..') or tmppath.endswith('/../'): parts = PurePosixPath(tmppath).parent.parent.parts if len(parts) == 1: tmppath = '/' elif len(parts) == 0: tmppath = '/' else: tmppath = "/".join(parts) else: if tmppath.endswith('/..') or tmppath.endswith('/../'): parts = PurePosixPath(tmppath).parent.parent.parts if len(parts) == 1: tmppath = parts[0] + '/' elif len(parts) == 0: tmppath = '/' else: tmppath = "/".join(parts) tmppath = tmppath.replace('//', '/') if tmppath == '' or tmppath is None: logger.warning('输入错误字符') tmppath = '/' return tmppath
def send_text(token, chat_id, proxy, msg): if isinstance(chat_id, str): chat_id = [chat_id] elif isinstance(chat_id, list): pass else: return [] send_result = [] if proxy is None or proxy == "": try: bot = Bot(token=token) except Exception as E: logger.exception(E) return [] else: proxy_url = proxy request = telegram.utils.request.Request(proxy_url=proxy_url) try: bot = Bot(token=token, request=request) except Exception as E: logger.exception(E) return [] for one_chat_id in chat_id: try: bot.send_message(chat_id=one_chat_id, text=msg, timeout=1) send_result.append(one_chat_id) except Exception as E: logger.exception(E) logger.warning("无效的chat_id: {}".format(one_chat_id)) return send_result
def delete_job_by_uuid(self, task_uuid=None): req = Xcache.get_module_task_by_uuid(task_uuid=task_uuid) Xcache.del_module_task_by_uuid(task_uuid=task_uuid) # 清理缓存信息 # 删除后台任务 try: self.ModuleJobsScheduler.remove_job(task_uuid) except Exception as E: logger.error(E) try: module_common_instance = req.get("module") except Exception as E: logger.error(E) return False # 存储已经生成的结果 try: module_common_instance.log_status("用户手动删除任务") module_common_instance._store_result_in_history() except Exception as E: logger.error("删除多模块实例异常:{} 异常信息: {}".format(module_common_instance.NAME, E)) Notice.send_exception("模块: {} 执行异常,异常信息: {}".format(module_common_instance.NAME, E)) logger.error(E) return False # 发送通知 Notice.send_info( "模块: {} {} 手动删除".format(module_common_instance.NAME, module_common_instance.target_str)) logger.warning("多模块实例手动删除:{}".format(module_common_instance.NAME)) return True
def _set_advanced_info(self, result_dict=None): try: if result_dict.get('status'): self.is_in_admin_group = result_dict.get('data').get( 'IS_IN_ADMIN_GROUP') # self.is_admin = result_dict.get('data').get('IS_ADMIN') self.tmpdir = result_dict.get('data').get('TEMP') self.is_uac_enable = result_dict.get('data').get( 'IS_UAC_ENABLE') self.uac_level = result_dict.get('data').get('UAC_LEVEL') if self.uac_level is None: self.uac_level = -1 self.integrity = self.SID_TO_INTEGERITY_LEVEL.get( result_dict.get('data').get('INTEGRITY')) self.pid = result_dict.get('data').get('PID') self.pname = result_dict.get('data').get('PNAME') self.ppath = result_dict.get('data').get('PPATH') self.puser = result_dict.get('data').get('PUSER') self.parch = result_dict.get('data').get('PARCH') self.processes = result_dict.get('data').get('PROCESSES') self.update_time = result_dict.get('update_time') else: logger.warning("模块执行错误") except Exception as E: logger.warning(E)
def create(sessionid=None, filename=None, dirpath=None, operation=None): if operation == 'create_dir' and sessionid is not None and dirpath is not None: # 新建文件夹 formatdir = FileSession.deal_path(dirpath) opts = {'OPERATION': 'create_dir', 'SESSION': sessionid, 'SESSION_DIR': formatdir} result = MSFModule.run('post', 'multi/manage/file_system_operation_api', opts, runasjob=False, timeout=12) if result is None: context = data_return(301, FileSession_MSG.get(301), []) return context try: result = json.loads(result) except Exception as E: logger.warning(E) context = data_return(302, FileSession_MSG.get(302), {}) return context if result.get('status') is not True: context = data_return(303, FileSession_MSG.get(303), []) return context else: context = data_return(201, FileSession_MSG.get(201), result.get('data')) return context # 上传文件 elif operation == 'upload_file' and sessionid is not None and filename is not None and dirpath is not None: formatdir = FileSession.deal_path(dirpath) opts = {'OPERATION': 'upload', 'SESSION': sessionid, 'SESSION_DIR': formatdir, 'MSF_FILE': filename} result = MSFModule.run('post', 'multi/manage/file_system_operation_api', opts, runasjob=True, timeout=12) if result is None: context = data_return(301, FileSession_MSG.get(301), {}) return context else: context = data_return(201, FileSession_MSG.get(201), result) return context else: context = data_return(306, FileSession_MSG.get(306), []) return context
def putin_post_python_module_queue(self, post_module_intent=None): try: # 存储uuid tmp_self_uuid = str(uuid.uuid1()) # 清空历史记录 post_module_intent.clean_log() logger.warning("模块放入列表:{} job_id: {} uuid: {}".format(post_module_intent.NAME, None, tmp_self_uuid)) post_module_intent.module_self_uuid = tmp_self_uuid self.ModuleJobsScheduler.add_job(func=post_module_intent._thread_run, max_instances=1, id=tmp_self_uuid) # 放入缓存队列,用于后续删除任务,存储结果等 req = { 'broker': post_module_intent.MODULE_BROKER, 'uuid': tmp_self_uuid, 'module': post_module_intent, 'time': int(time.time()), 'job_id': None, } Xcache.create_module_task(req) Notice.send_info( "模块: {} {} 开始执行".format(post_module_intent.NAME, post_module_intent.target_str)) return True except Exception as E: logger.error(E) return False
def to_dict(self): """将参数对象转化为json格式数据""" _dict = { 'name': self._name, 'name_tag': self._name_tag, 'type': self._type, 'required': self._required, 'desc': self._desc, 'default': self._default, 'extra_data': self._extra_data, } # 处理option_length参数的兼容性 if self._option_length is None: _dict['option_length'] = option_type_default_length.get(self._type) else: _dict['option_length'] = self._option_length # 处理enum_list参数的兼容性,请注意,此处无法处理handler和凭证等动态参数 tmp_enmu_list = [] for one_enmu in self._enum_list: if isinstance(one_enmu, str) or isinstance(one_enmu, bytes): tmp_enmu_list.append({'name': one_enmu, 'value': one_enmu}) else: if one_enmu.get('name') is not None and one_enmu.get( 'value') is not None: tmp_enmu_list.append(one_enmu) else: logger.warning("参数错误, name: {} name_tag:{}".format( self._name, self._name_tag)) _dict['enum_list'] = tmp_enmu_list return _dict
def create(portfwdtype=None, lhost=None, lport=None, rhost=None, rport=None, sessionid=None): # 获取不同转发的默认参数 flag, context = PortFwd._check_host_port(portfwdtype, lhost, lport, rhost, rport) if flag is not True: return context # flag, lportsstr = is_empty_ports(lportint) # if flag is not True: # # 端口已占用 # context = dict_data_return(CODE, CODE_MSG.get(CODE), {}) # return context opts = {'TYPE': portfwdtype, 'LHOST': lhost, 'LPORT': lport, 'RHOST': rhost, 'RPORT': rport, 'SESSION': sessionid, 'CMD': 'add'} result = MSFModule.run(module_type="post", mname="multi/manage/portfwd_api", opts=opts) if result is None: context = data_return(308, PORTFWD_MSG.get(308), {}) return context try: result_dict = json.loads(result) except Exception as E: logger.warning(E) context = data_return(301, PORTFWD_MSG.get(301), []) return context if result_dict.get('status') is True: Notice.send_success(f"新增端口转发 SID:{sessionid} {portfwdtype} {lhost}/{lport} {rhost}/{rport}") context = data_return(201, PORTFWD_MSG.get(201), result_dict.get('data')) return context else: context = data_return(301, PORTFWD_MSG.get(301), []) return context
def destory(subnet=None, netmask=None, sessionid=None): opts = { 'CMD': 'delete', 'SUBNET': subnet, 'NETMASK': netmask, 'SESSION': sessionid } result = MSFModule.run(module_type="post", mname="multi/manage/routeapi", opts=opts) if result is None: context = data_return(505, CODE_MSG.get(505), []) return context try: result_dict = json.loads(result) except Exception as E: logger.warning(E) context = data_return(306, Route_MSG.get(306), {}) return context if result_dict.get('status') is True: Notice.send_info(f"删除路由,SID:{sessionid} {subnet}/{netmask}") context = data_return(204, Route_MSG.get(204), {}) return context else: context = data_return(304, Route_MSG.get(304), {}) return context
def get_result_connection(): """用于订阅类操作,无需使用连接池""" try: rcon = redis.Redis.from_url(url=f"{REDIS_URL}5") return rcon except Exception as E: logger.warning(E) return None
def get_by_hid(hid=None): try: model = HostModel.objects.get(id=hid) result = HostSerializer(model).data return result except Exception as E: logger.warning(E) return None
def store_result_from_sub(message=None): # 回调报文数据格式 # { # 'job_id': None, # 'uuid': '1b1a1ac0-95db-0137-5103-000c2966078a', # 'status': True, # 'message': None, # 'data': {'WHOAMI': 'nt authority\\system', 'IS_SYSTEM': True, } # } body = message.get('data') # 解析报文 try: msf_module_return_dict = json.loads(body) except Exception as E: logger.error(E) return False # 获取对应模块实例 try: req = Xcache.get_module_task_by_uuid(task_uuid=msf_module_return_dict.get("uuid")) except Exception as E: logger.error(E) return False if req is None: logger.error("未找到请求模块实例") logger.error(msf_module_return_dict) return False module_intent = req.get('module') if module_intent is None: logger.error("获取模块失败,body: {}".format(msf_module_return_dict)) return False # 调用回调函数 try: logger.warning(f"模块回调:{module_intent.NAME} " f"job_id: {msf_module_return_dict.get('job_id')} " f"uuid: {msf_module_return_dict.get('uuid')}") module_intent._clean_log() # 清理历史结果 except Exception as E: logger.error(E) return False try: module_intent.callback(status=msf_module_return_dict.get("status"), message=msf_module_return_dict.get("message"), data=msf_module_return_dict.get("data")) except Exception as E: Notice.send_error("模块 {} 的回调函数callhack运行异常".format(module_intent.NAME)) logger.error(E) try: module_intent._store_result_in_history() # 存储到历史记录 except Exception as E: logger.error(E) Xcache.del_module_task_by_uuid(task_uuid=msf_module_return_dict.get("uuid")) # 清理缓存信息 Notice.send_success("模块: {} {} 执行完成".format(module_intent.NAME, module_intent._target_str))
def is_empty_ports(useport=None): try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.bind(("0.0.0.0", useport)) sock.close() return True, "" except socket.error: logger.warning(f"端口: {useport},已占用") return False, ""
def sub_msf_module_log_thread(): """这个函数必须以线程的方式运行,监控msf发送的redis消息,获取job类任务推送的消息""" rcon = RedisClient.get_result_connection() if rcon is None: return ps = rcon.pubsub(ignore_subscribe_messages=True) ps.subscribe(**{MSF_RPC_LOG_CHANNEL: MSFModule.store_log_from_sub}) for message in ps.listen(): if message: logger.warning("不应获取非空message {}".format(message))
def sub_send_sms_thread(): """这个函数必须以线程的方式运行,监控msf发送的redis消息,获取job类任务推送的数据""" rcon = RedisClient.get_result_connection() if rcon is None: return ps = rcon.pubsub(ignore_subscribe_messages=True) ps.subscribe(**{VIPER_SEND_SMS_CHANNEL: Settings._send_bot_msg}) for message in ps.listen(): if message: logger.warning("不应获取非空message {}".format(message))
def upload_file_to_msf(file=None): try: filename = file.name filepath = os.path.join(MSFLOOT, filename) with open(filepath, "wb+") as f: for chunk in file.chunks(): f.write(chunk) return True except Exception as E: logger.warning(E) return False
def add_vulnerability(self, ipaddress=None, extra_data=None, desc=''): """增加一个漏洞信息""" if extra_data is None: extra_data = {} if isinstance(extra_data, dict) is not True: logger.warning('数据类型检查错误,数据 {}'.format(extra_data)) extra_data = {} result = Vulnerability.add_or_update(ipaddress, self.loadpath, extra_data, desc) return result
def tabs(line=None): cid = Xcache.get_console_id() if cid is None: return False, {} params = [cid, line] result = RpcClient.call(Method.ConsoleTabs, params) if result is None or result.get("result") == "failure": logger.warning("Cid: {}错误".format(cid)) return False, {} else: return True, result
def deal_powershell_json_result(result): result_without_error = re.sub('ERROR:.+\s', '', result) result_without_empty = result_without_error.replace('\r', '').replace( '\n', '').replace('\t', '') try: result_json = json.loads(result_without_empty) return result_json except Exception as E: logger.warning(E) logger.warning("解析powershell结果失败") return None
def create_bot(ipportlist=None, custom_param=None, loadpath=None): module_config = Xcache.get_moduleconfig(loadpath) # 获取模块配置 if module_config is None: context = data_return(305, PostModuleActuator_MSG.get(305), {}) return context # 处理模块参数 try: custom_param = json.loads(custom_param) except Exception as E: logger.warning(E) custom_param = {} # 获取模块实例 group_uuid = str(uuid.uuid1()).replace('-', "") class_intent = importlib.import_module(loadpath) for ipport in ipportlist: post_module_intent = class_intent.PostModule( ip=ipport.get("ip"), port=ipport.get("port"), protocol=ipport.get("protocol"), custom_param=custom_param) # 模块前序检查,调用check函数 try: flag, msg = post_module_intent.check() if flag is not True: # 如果检查未通过,返回未通过原因(msg) Notice.send_warning( f"模块:{post_module_intent.NAME} IP:{ipport.get('ip')} 检查未通过,原因:{msg}" ) continue except Exception as E: logger.warning(E) Notice.send_warning( f"模块:{post_module_intent.NAME} IP:{ipport.get('ip')} 检查函数执行异常" ) continue tmp_self_uuid = str(uuid.uuid1()) req = { 'uuid': tmp_self_uuid, 'group_uuid': group_uuid, 'broker': post_module_intent.MODULE_BROKER, 'module': post_module_intent, 'time': int(time.time()), } Xcache.putin_bot_wait(req) context = data_return(201, PostModuleActuator_MSG.get(201), {}) return context
def session_kill(): cid = Xcache.get_console_id() if cid is None: return False, {} params = [cid] result = RpcClient.call(Method.ConsoleSessionKill, params) if result is None: return False, {} elif result.get("result") == "failure": logger.warning("Cid: {}错误".format(cid)) return False, {} else: return True, result
def add_portservice(self, ipaddress, port, banner=None, service=""): """增加一个端口/服务信息""" if banner is None: banner = {} if isinstance(banner, dict) is not True: logger.warning('数据类型检查错误,数据 {}'.format(banner)) banner = {} result = PortService.add_or_update(ipaddress=ipaddress, port=port, banner=banner, service=service) return result
def create_post(loadpath=None, sessionid=None, hid=None, custom_param=None): module_config = Xcache.get_moduleconfig(loadpath) # 获取模块配置 if module_config is None: context = data_return(305, PostModuleActuator_MSG.get(305), {}) return context # 处理模块参数 try: custom_param = json.loads(custom_param) except Exception as E: logger.warning(E) custom_param = {} # 获取模块实例 class_intent = importlib.import_module(loadpath) post_module_intent = class_intent.PostModule(sessionid, hid, custom_param) # 模块前序检查,调用check函数 try: flag, msg = post_module_intent.check() if flag is not True: # 如果检查未通过,返回未通过原因(msg) context = data_return(405, msg, {}) return context except Exception as E: logger.warning(E) context = data_return(301, PostModuleActuator_MSG.get(301), {}) return context try: broker = post_module_intent.MODULE_BROKER except Exception as E: logger.warning(E) context = data_return(305, PostModuleActuator_MSG.get(305), {}) return context if broker == BROKER.post_python_job: # 放入多模块队列 if aps_module.putin_post_python_module_queue(post_module_intent): context = data_return(201, PostModuleActuator_MSG.get(201), {}) return context else: context = data_return(306, PostModuleActuator_MSG.get(306), {}) return context elif broker == BROKER.post_msf_job: # 放入后台运行队列 if MSFModule.putin_post_msf_module_queue(post_module_intent): context = data_return(201, PostModuleActuator_MSG.get(201), {}) return context else: context = data_return(306, PostModuleActuator_MSG.get(306), {}) return context else: logger.warning("错误的broker")
def compile_c(self, src, arch="x64"): bindata = None exe_file = os.path.join(TMP_DIR, f"{self.file_name}.exe") cmd = self.build_cmd(src, arch) ret = subprocess.run(cmd, capture_output=True, text=True) if ret.returncode != 0: logger.warning(ret.stdout) logger.warning(ret.stderr) else: try: with open(exe_file, 'rb') as f: bindata = f.read() except Exception as E: logger.exception(E) self.cleanup_files() return bindata
def get_group_member(self, group): module_type = 'post' mname = 'windows/manage/powershell/exec_powershell_function_mem' opts = { 'SESSION': self._sessionid, 'SCRIPT': 'PowerView_dev.ps1', 'EXECUTE_STRING': ' \'{}\' | Get-DomainGroupMember'.format(group), 'CHECK_FUNCTION': False, } result = MsfModule.run_with_output(module_type, mname, opts) try: result_json = json.loads( result.replace('\r', '').replace('\n', '').replace('\t', '')) return result_json except Exception as E: logger.warning(E) return None
def find_local_admin_access(self): module_type = 'post' mname = 'windows/manage/powershell/exec_powershell_function_mem' opts = { 'SESSION': self._sessionid, 'SCRIPT': 'PowerView_dev.ps1', 'EXECUTE_STRING': 'Find-LocalAdminAccess -Delay 1', 'CHECK_FUNCTION': False, } result = MsfModule.run_with_output(module_type, mname, opts) try: result_json = json.loads( result.replace('\r', '').replace('\n', '').replace('\t', '')) return result_json except Exception as E: logger.warning(E) return None
def send_serverchan_message(msg=None, conf=None): if conf is None: conf = Xcache.get_serverchan_conf() if conf is None: return False if conf.get("alive"): pass else: return False sendkey = conf.get("sendkey") serverchan = ServerChan(sendkey=sendkey) try: result = serverchan.send_text(msg) return result except Exception as E: logger.warning(E) return False
def list(sessionid=None): result_list = PortFwd.list_portfwd() if sessionid is None or sessionid == -1: context = data_return(200, CODE_MSG.get(200), result_list) return context else: tmplist = [] try: for one in result_list: if one.get('sessionid') == sessionid: tmplist.append(one) except Exception as E: logger.warning(E) context = data_return(200, CODE_MSG.get(200), tmplist) return context
def is_in_domain(self): if self.platform == "windows": if self.user is not None: try: session_domain = self.user.split('\\')[0] if session_domain.lower() == self.domain.lower(): return True if session_domain.lower() == self.computer.lower(): return False if session_domain.lower( ) == "nt authority": # system权限默认在域中 return True return False except Exception as E: logger.warning(E) return False else: return False