|
| 1 | +#!/usr/bin/env python3 |
| 2 | +# -*- coding: utf-8 -*- |
| 3 | + |
| 4 | +class CMEModule: |
| 5 | + ''' |
| 6 | + Extract all Trust Relationships, Trusting Direction, and Trust Transitivity |
| 7 | + Module by Brandon Fisher @shad0wcntr0ller |
| 8 | + ''' |
| 9 | + name = 'enum_trusts' |
| 10 | + description = 'Extract all Trust Relationships, Trusting Direction, and Trust Transitivity' |
| 11 | + supported_protocols = ['ldap'] |
| 12 | + opsec_safe = True |
| 13 | + multiple_hosts = True |
| 14 | + |
| 15 | + def options(self, context, module_options): |
| 16 | + pass |
| 17 | + |
| 18 | + def on_login(self, context, connection): |
| 19 | + domain_dn = ','.join(['DC=' + dc for dc in connection.domain.split('.')]) |
| 20 | + search_filter = '(&(objectClass=trustedDomain))' |
| 21 | + attributes = ['flatName', 'trustPartner', 'trustDirection', 'trustAttributes'] |
| 22 | + |
| 23 | + context.log.debug(f'Search Filter={search_filter}') |
| 24 | + resp = connection.ldapConnection.search(searchBase=domain_dn, searchFilter=search_filter, attributes=attributes, sizeLimit=0) |
| 25 | + |
| 26 | + trusts = [] |
| 27 | + context.log.debug(f'Total of records returned {len(resp)}') |
| 28 | + for item in resp: |
| 29 | + if isinstance(item, ldapasn1_impacket.SearchResultEntry) is not True: |
| 30 | + continue |
| 31 | + flat_name = '' |
| 32 | + trust_partner = '' |
| 33 | + trust_direction = '' |
| 34 | + trust_transitive = [] |
| 35 | + try: |
| 36 | + for attribute in item['attributes']: |
| 37 | + if str(attribute['type']) == 'flatName': |
| 38 | + flat_name = str(attribute['vals'][0]) |
| 39 | + elif str(attribute['type']) == 'trustPartner': |
| 40 | + trust_partner = str(attribute['vals'][0]) |
| 41 | + elif str(attribute['type']) == 'trustDirection': |
| 42 | + if str(attribute['vals'][0]) == '1': |
| 43 | + trust_direction = 'Inbound' |
| 44 | + elif str(attribute['vals'][0]) == '2': |
| 45 | + trust_direction = 'Outbound' |
| 46 | + elif str(attribute['vals'][0]) == '3': |
| 47 | + trust_direction = 'Bidirectional' |
| 48 | + elif str(attribute['type']) == 'trustAttributes': |
| 49 | + trust_attributes_value = int(attribute['vals'][0]) |
| 50 | + if trust_attributes_value & 0x1: |
| 51 | + trust_transitive.append('Non-Transitive') |
| 52 | + if trust_attributes_value & 0x2: |
| 53 | + trust_transitive.append('Uplevel-Only') |
| 54 | + if trust_attributes_value & 0x4: |
| 55 | + trust_transitive.append('Quarantined Domain') |
| 56 | + if trust_attributes_value & 0x8: |
| 57 | + trust_transitive.append('Forest Transitive') |
| 58 | + if trust_attributes_value & 0x10: |
| 59 | + trust_transitive.append('Cross Organization') |
| 60 | + if trust_attributes_value & 0x20: |
| 61 | + trust_transitive.append('Within Forest') |
| 62 | + if trust_attributes_value & 0x40: |
| 63 | + trust_transitive.append('Treat as External') |
| 64 | + if trust_attributes_value & 0x80: |
| 65 | + trust_transitive.append('Uses RC4 Encryption') |
| 66 | + if trust_attributes_value & 0x100: |
| 67 | + trust_transitive.append('Cross Organization No TGT Delegation') |
| 68 | + if trust_attributes_value & 0x2000: |
| 69 | + trust_transitive.append('PAM Trust') |
| 70 | + if not trust_transitive: |
| 71 | + trust_transitive.append('Other') |
| 72 | + trust_transitive = ', '.join(trust_transitive) |
| 73 | + |
| 74 | + if flat_name and trust_partner and trust_direction and trust_transitive: |
| 75 | + trusts.append((flat_name, trust_partner, trust_direction, trust_transitive)) |
| 76 | + except Exception as e: |
| 77 | + context.log.debug(f'Cannot process trust relationship due to error {e}') |
| 78 | + pass |
| 79 | + |
| 80 | + if trusts: |
| 81 | + context.log.success('Found the following trust relationships:') |
| 82 | + for trust in trusts: |
| 83 | + context.log.highlight(f'{trust[1]} -> {trust[2]} -> {trust[3]}') |
| 84 | + else: |
| 85 | + context.log.display('No trust relationships found') |
| 86 | + |
| 87 | + return True |
| 88 | + |
0 commit comments