예제 #1
0
    def process_computer(self, hostname, samname, objectsid, entry, results_q):
        """
            Processes a single computer, pushes the results of the computer to the given queue.
        """
        logging.debug('Querying computer: %s', hostname)
        c = ADComputer(hostname=hostname,
                       samname=samname,
                       ad=self.addomain,
                       objectsid=objectsid)
        c.primarygroup = self.get_primary_membership(entry)
        if c.try_connect() == True:
            try:

                if 'session' in self.collect:
                    sessions = c.rpc_get_sessions()
                else:
                    sessions = []
                if 'localadmin' in self.collect:
                    unresolved = c.rpc_get_group_members(544, c.admins)
                    c.rpc_resolve_sids(unresolved, c.admins)
                if 'rdp' in self.collect:
                    unresolved = c.rpc_get_group_members(555, c.rdp)
                    c.rpc_resolve_sids(unresolved, c.rdp)
                if 'dcom' in self.collect:
                    unresolved = c.rpc_get_group_members(562, c.dcom)
                    c.rpc_resolve_sids(unresolved, c.dcom)
                if 'loggedon' in self.collect:
                    loggedon = c.rpc_get_loggedon()
                else:
                    loggedon = []
                if 'experimental' in self.collect:
                    services = c.rpc_get_services()
                    tasks = c.rpc_get_schtasks()
                else:
                    services = []
                    tasks = []

                c.rpc_close()
                # c.rpc_get_domain_trusts()

                results_q.put(
                    ('computer', c.get_bloodhound_data(entry, self.collect)))

                if sessions is None:
                    sessions = []

                # Process found sessions
                for ses in sessions:
                    # For every session, resolve the SAM name in the GC if needed
                    domain = self.addomain.domain
                    if self.addomain.num_domains > 1 and self.do_gc_lookup:
                        try:
                            users = self.addomain.samcache.get(samname)
                        except KeyError:
                            # Look up the SAM name in the GC
                            users = self.addomain.objectresolver.gc_sam_lookup(
                                ses['user'])
                            if users is None:
                                # Unknown user
                                continue
                            self.addomain.samcache.put(samname, users)
                    else:
                        users = [((u'%s@%s' % (ses['user'], domain)).upper(),
                                  2)]

                    # Resolve the IP to obtain the host the session is from
                    try:
                        target = self.addomain.dnscache.get(ses['source'])
                    except KeyError:
                        target = ADUtils.ip2host(ses['source'],
                                                 self.addomain.dnsresolver,
                                                 self.addomain.dns_tcp)
                        # Even if the result is the IP (aka could not resolve PTR) we still cache
                        # it since this result is unlikely to change during this run
                        self.addomain.dnscache.put_single(
                            ses['source'], target)
                    if ':' in target:
                        # IPv6 address, not very useful
                        continue
                    if '.' not in target:
                        logging.debug(
                            'Resolved target does not look like an IP or domain. Assuming hostname: %s',
                            target)
                        target = '%s.%s' % (target, domain)
                    # Put the result on the results queue.
                    for user in users:
                        results_q.put(('session', {
                            'UserName': user[0].upper(),
                            'ComputerName': target.upper(),
                            'Weight': user[1]
                        }))
                if loggedon is None:
                    loggedon = []

                # Put the logged on users on the queue too
                for user in loggedon:
                    results_q.put(('session', {
                        'UserName': ('%s@%s' % user).upper(),
                        'ComputerName': hostname.upper(),
                        'Weight': 1
                    }))

                # Process Tasks
                for taskuser in tasks:
                    try:
                        user = self.addomain.sidcache.get(taskuser)
                    except KeyError:
                        # Resolve SID in GC
                        userentry = self.addomain.objectresolver.resolve_sid(
                            taskuser)
                        # Resolve it to an entry and store in the cache
                        user = ADUtils.resolve_ad_entry(userentry)
                        self.addomain.sidcache.put(taskuser, user)
                    logging.debug('Resolved TASK SID to username: %s',
                                  user['principal'])
                    # Use sessions for now
                    results_q.put(('session', {
                        'UserName': user['principal'].upper(),
                        'ComputerName': hostname.upper(),
                        'Weight': 2
                    }))

                # Process Services
                for serviceuser in services:
                    # Todo: use own cache
                    try:
                        user = self.addomain.sidcache.get(serviceuser)
                    except KeyError:
                        # Resolve UPN in GC
                        userentry = self.addomain.objectresolver.resolve_upn(
                            serviceuser)
                        # Resolve it to an entry and store in the cache
                        user = ADUtils.resolve_ad_entry(userentry)
                        self.addomain.sidcache.put(serviceuser, user)
                    logging.debug('Resolved Service UPN to username: %s',
                                  user['principal'])
                    # Use sessions for now
                    results_q.put(('session', {
                        'UserName': user['principal'].upper(),
                        'ComputerName': hostname.upper(),
                        'Weight': 2
                    }))

            except DCERPCException:
                logging.warning('Querying computer failed: %s' % hostname)
            except Exception as e:
                logging.error(
                    'Unhandled exception in computer %s processing: %s',
                    hostname, str(e))
                logging.info(traceback.format_exc())
        else:
            # Write the info we have to the file regardless
            try:
                results_q.put(
                    ('computer', c.get_bloodhound_data(entry, self.collect)))
            except Exception as e:
                logging.error(
                    'Unhandled exception in computer %s processing: %s',
                    hostname, str(e))
                logging.info(traceback.format_exc())
예제 #2
0
    def process_computer(self, hostname, samname, objectsid, entry, results_q):
        """
            Processes a single computer, pushes the results of the computer to the given queue.
        """
        logging.debug('Querying computer: %s', hostname)
        c = ADComputer(hostname=hostname,
                       samname=samname,
                       ad=self.addomain,
                       addc=self.addc,
                       objectsid=objectsid)
        c.primarygroup = self.get_primary_membership(entry)
        if c.try_connect() == True:
            try:

                if 'session' in self.collect:
                    sessions = c.rpc_get_sessions()
                else:
                    sessions = []
                if 'localadmin' in self.collect:
                    unresolved = c.rpc_get_group_members(544, c.admins)
                    c.rpc_resolve_sids(unresolved, c.admins)
                if 'rdp' in self.collect:
                    unresolved = c.rpc_get_group_members(555, c.rdp)
                    c.rpc_resolve_sids(unresolved, c.rdp)
                if 'dcom' in self.collect:
                    unresolved = c.rpc_get_group_members(562, c.dcom)
                    c.rpc_resolve_sids(unresolved, c.dcom)
                if 'psremote' in self.collect:
                    unresolved = c.rpc_get_group_members(580, c.psremote)
                    c.rpc_resolve_sids(unresolved, c.psremote)
                if 'loggedon' in self.collect:
                    loggedon = c.rpc_get_loggedon()
                else:
                    loggedon = []
                if 'experimental' in self.collect:
                    services = c.rpc_get_services()
                    tasks = c.rpc_get_schtasks()
                else:
                    services = []
                    tasks = []

                c.rpc_close()
                # c.rpc_get_domain_trusts()

                if sessions is None:
                    sessions = []

                # Should we use the GC?
                use_gc = self.addomain.num_domains > 1 and self.do_gc_lookup

                # Process found sessions
                for ses in sessions:
                    # For every session, resolve the SAM name in the GC if needed
                    domain = self.addomain.domain
                    try:
                        users = self.addomain.samcache.get(samname)
                    except KeyError:
                        # Look up the SAM name in the GC
                        entries = self.addomain.objectresolver.resolve_samname(
                            ses['user'], use_gc=use_gc)
                        if entries is not None:
                            users = [
                                user['attributes']['objectSid']
                                for user in entries
                            ]
                        if entries is None or users == []:
                            logging.warning(
                                'Failed to resolve SAM name %s in current forest',
                                samname)
                            continue
                        self.addomain.samcache.put(samname, users)

                    # Resolve the IP to obtain the host the session is from
                    try:
                        target = self.addomain.dnscache.get(ses['source'])
                    except KeyError:
                        # TODO: also use discovery based on port 445 connections similar to sharphound
                        target = ADUtils.ip2host(ses['source'],
                                                 self.addomain.dnsresolver,
                                                 self.addomain.dns_tcp)
                        # Even if the result is the IP (aka could not resolve PTR) we still cache
                        # it since this result is unlikely to change during this run
                        self.addomain.dnscache.put_single(
                            ses['source'], target)
                    if ':' in target:
                        # IPv6 address, not very useful
                        continue
                    if '.' not in target:
                        logging.debug(
                            'Resolved target does not look like an IP or domain. Assuming hostname: %s',
                            target)
                        target = '%s.%s' % (target, domain)
                    # Resolve target hostname
                    try:
                        hostsid = self.addomain.computersidcache.get(
                            target.lower())
                    except KeyError:
                        logging.warning(
                            'Could not resolve hostname to SID: %s', target)
                        continue

                    # Put the result on the results queue.
                    for user in users:
                        c.sessions.append({
                            'ComputerId': hostsid,
                            'UserId': user
                        })
                if loggedon is None:
                    loggedon = []

                # Put the logged on users on the queue too
                for user, userdomain in loggedon:
                    # Construct fake UPN to cache this user
                    fupn = '%s@%s' % (user.upper(), userdomain.upper())
                    try:
                        users = self.addomain.samcache.get(fupn)
                    except KeyError:
                        entries = self.addomain.objectresolver.resolve_samname(
                            user, use_gc=use_gc)
                        if entries is not None:
                            if len(entries) > 1:
                                for resolved_user in entries:
                                    edn = ADUtils.get_entry_property(
                                        resolved_user, 'distinguishedName')
                                    edom = ADUtils.ldap2domain(edn).lower()
                                    if edom == userdomain.lower():
                                        users = [
                                            resolved_user['attributes']
                                            ['objectSid']
                                        ]
                                        break
                                    logging.debug(
                                        'Skipping resolved user %s since domain does not match (%s != %s)',
                                        edn, edom, userdomain.lower())
                            else:
                                users = [
                                    resolved_user['attributes']['objectSid']
                                    for resolved_user in entries
                                ]
                        if entries is None or users == []:
                            logging.warning(
                                'Failed to resolve SAM name %s in current forest',
                                samname)
                            continue
                        self.addomain.samcache.put(fupn, users)
                    for resultuser in users:
                        c.sessions.append({
                            'ComputerId': objectsid,
                            'UserId': resultuser
                        })

                # Process Tasks
                for taskuser in tasks:
                    c.sessions.append({
                        'ComputerId': objectsid,
                        'UserId': taskuser
                    })

                # Process Services
                for serviceuser in services:
                    try:
                        user = self.addomain.sidcache.get(serviceuser)
                    except KeyError:
                        # Resolve UPN in GC
                        userentry = self.addomain.objectresolver.resolve_upn(
                            serviceuser)
                        # Resolve it to an entry and store in the cache
                        self.addomain.sidcache.put(
                            serviceuser, userentry['attributes']['objectSid'])
                        user = userentry['attributes']['objectSid']
                    logging.debug('Resolved Service UPN to SID: %s',
                                  user['objectsid'])
                    c.sessions.append({
                        'ComputerId': objectsid,
                        'UserId': user
                    })

                results_q.put(
                    ('computer', c.get_bloodhound_data(entry, self.collect)))

            except DCERPCException:
                logging.debug(traceback.format_exc())
                logging.warning('Querying computer failed: %s', hostname)
            except Exception as e:
                logging.error(
                    'Unhandled exception in computer %s processing: %s',
                    hostname, str(e))
                logging.info(traceback.format_exc())
        else:
            # Write the info we have to the file regardless
            try:
                results_q.put(
                    ('computer', c.get_bloodhound_data(entry, self.collect)))
            except Exception as e:
                logging.error(
                    'Unhandled exception in computer %s processing: %s',
                    hostname, str(e))
                logging.info(traceback.format_exc())