Es bastante común llegar a identificar instancias MSSQL en entornos de Active Directory, debido a la fácil integración con LDAP y mecanismos de autenticación respectivos, por lo que estas instancias desplegadas pueden brindar a un atacante distintas maneras de obtener información o alguna manera de comprometer servidores internos.
En este post explicaré algunas maneras de extraer información de bases de datos MSSQL y abusar de ciertas configuraciones para realizar movimiento lateral.
Los escenarios que exploraremos serán los siguientes:
- Listado de directorios internos de un servidor a través de MSSQL, identificando ficheros sensibles.
- Uso de funciones públicas para forzar la autenticación del servidor y de un usuario de dominio hacia el equipo del atacante para ataques de NTLM Relay.
- Ejecución de código remoto a través de funciones propias de MSSQL.
Para emular estos vectores de ataque, necesitaremos desplegar un par de bases de datos MSSQL sobre el dominio de prueba utilizado en posts anteriores.
Instalación de MSSQL en servidores internos.
Para este laboratorio, es suficiente con instalar MSSQL Express, lo podemos hacer directamente desde la página web oficial de Microsoft.
En este caso, utilizare un laboratorio distinto, que desplegué hace unos días, utilizando un NUC como server.
La nueva topología es la siguiente:
![](https://jsec-rt.com/wp-content/uploads/2023/11/jsec.drawio-2-1024x734.png)
Para este ejercicio, desplegaremos dos instancias MSSQL en el dominio hijo internal.jsec.rt y el dominio padre jsec.rt, sin embargo, la configuración de enlaces entre las dos bases de datos sera para un siguiente post.
Los pasos se repiten para ambos equipos, al tratarse de un laboratorio.
*Nota: Asegurarse que se tiene instalado .NET Framework 4.7.2.
![](https://jsec-rt.com/wp-content/uploads/2023/11/image-1024x804.png)
Podemos escoger la opción Basic por temas de simplicidad.
![](https://jsec-rt.com/wp-content/uploads/2023/11/image-1-1024x790.png)
Aceptamos los términos y condiciones.
![](https://jsec-rt.com/wp-content/uploads/2023/11/image-2-1024x795.png)
Escogemos la ruta donde queremos instalar el software y luego click en Install.
El instalador descargara los archivos necesarios y tendremos la base de datos disponible localmente.
Instalando el gestor de base de datos.
Utilizaremos la herramienta recomendada por Microsoft para la gestión de la base de datos. Lo podemos descargar desde la pantalla del instalador, una ves que termine.
![](https://jsec-rt.com/wp-content/uploads/2023/11/image-5-1024x778.png)
La instalación, similar al caso anterior, se la puede hacer por defecto, al tratarse de un laboratorio.
Configuración para acceder remotamente.
La base de datos es accesible únicamente de manera local, para permitir el acceso a través de la red, realizaremos los siguientes pasos.
Accediendo al gestor de configuración de SQL Server.
![](https://jsec-rt.com/wp-content/uploads/2023/11/image-6-824x1024.png)
Modificando las opciones para poder acceder a la base de datos de manera remota, tenemos que acceder a la opción TCP/IP.
![](https://jsec-rt.com/wp-content/uploads/2023/11/image-7-1024x500.png)
Cambiamos la opción Enabled a Yes.
![](https://jsec-rt.com/wp-content/uploads/2023/11/image-8-1024x683.png)
Luego, accedemos a la pestaña IP Addresses y agregamos el puerto en el que queremos que el servicio este a la escucha en el campo TCP Port de la sección IPAll.
![](https://jsec-rt.com/wp-content/uploads/2023/11/image-10-1024x688.png)
Luego, para reiniciar el servicio y que se apliquen los cambios, accedemos al menu SQL Server Services, le damos click derecho al objeto SQL Server y luego click en Restart.
![](https://jsec-rt.com/wp-content/uploads/2023/11/image-11-1024x327.png)
Ahora, para confirmar que el servicio sea accesible, podemos listar los puertos en escucha del servidor a través de Powershell.
![](https://jsec-rt.com/wp-content/uploads/2023/11/image-12-1024x308.png)
Desde el equipo Kali, podemos validar que el servicio esta a la escucha utilizando Impacket-mssqlclient para intentar conectarnos a la base de datos respectiva.
![](https://jsec-rt.com/wp-content/uploads/2023/11/image-13-1024x423.png)
Obtenemos el hostname y la base de datos configurada como respuesta, por lo que se confirma que ya podemos proceder a generar el laboratorio vulnerable.
Preparando el entorno vulnerable.
Recapitulando las vulnerabilidades mencionadas.
- Listado de directorios internos de un servidor a través de MSSQL, identificando ficheros sensibles.
- Uso de funciones públicas para forzar la autenticación del servidor y de un usuario de dominio hacia el equipo del atacante para ataques de NTLM Relay.
- Ejecución de código remoto a través de funciones propias de MSSQL.
Para las primeras dos funciones, no necesitamos hacer mucho, ya que se instalo sobre un dominio de Windows, los usuarios regulares tienen privilegios de consulta, muy reducidos, pero cualquier credencial nos da acceso a funciones publicas.
Pero para replicar el comportamiento en redes corporativas, registraremos tickets SPN en los dominios respectivos para permitir la autenticación por Kerberos al servicio respectivo.
Para esta tarea, en nuestro controlador de dominio utilizaremos el siguiente comando:
season -S MSSQLSvc/coreint.internal.jsec.rt internal.jsec.rt\serveradmin
![](https://jsec-rt.com/wp-content/uploads/2023/11/image-36-1024x321.png)
De esta manera, la instancia podrá ser identificada a través de enumeración de Active Directory.
Para el tercer punto, crearemos un usuario local de base de datos con privilegios de Sysadmin, el cual es uno de los requisitos para habilitar la función “xp_cmdshell”.
En las bases de datos respectivas, accedemos al gestor de base de datos.
![](https://jsec-rt.com/wp-content/uploads/2023/11/image-15-980x1024.png)
Accedemos con el usuario de dominio que instalo el servidor.
![](https://jsec-rt.com/wp-content/uploads/2023/11/image-18-1024x787.png)
Una vez dentro, accedemos al submenu Security y luego a Logins, dandole click derecho y accediendo a New Login.
![](https://jsec-rt.com/wp-content/uploads/2023/11/image-22-1024x1004.png)
Para agregar a un usuario del dominio como un usuario valido con privilegios en la base de datos, le damos click en Search, luego hacemos click en el botón Locations y para poder buscar usuarios del dominio interno, expandimos el dominio padre jsec.rt y seleccionamos el subdominio internal.jsec.rt donde reside nuestro usuario de pruebas.
Escribimos el nombre de usuario al que le queremos dar privilegios, en mi caso Sqluser, y le damos click en Check Names, para asegurarnos que el usuario esta siendo identificado correctamente.
![](https://jsec-rt.com/wp-content/uploads/2023/11/image-20-1024x841.png)
Le damos click a OK y pasamos a la pestaña Server Roles, donde marcaremos a este usuario como Sysadmin
![](https://jsec-rt.com/wp-content/uploads/2023/11/image-21-1024x806.png)
Le podemos dar click a OK y ya tendremos nuestro nuevo usuario de pruebas con posibilidad de acceder a la base de datos respectiva.
Desde nuestro equipo Kali, podemos validar el acceso utilizando impacket-mssqlclient.
![](https://jsec-rt.com/wp-content/uploads/2023/11/image-23-1024x317.png)
Cabe destacar que es necesario utilizar la flag -windows-auth para poder autenticarnos con usuarios del sistema operativo o de dominio.
Para finalizar la configuración, agregaremos al usuario del equipo Coreint como administrador del equipo DBInt para el ataque de Relay.
![](https://jsec-rt.com/wp-content/uploads/2023/11/image-24-1024x617.png)
Ahora podemos proceder a los escenarios de explotación.
Para estos escenarios de explotación, utilizaremos la herramienta PowerUpSQL y un equipo Windows en la red interna, con acceso de bajos privilegios (usuario jsec).
Escenario de explotación 1: Listado de directorios internos a través de MSSQL.
Existen muchos casos donde es posible identificar instancias de MSSQL configuradas en el dominio, para aplicaciones internas y otros, para el caso de aplicaciones Web alojadas en un servidor con MSSQL, es posible descubrir los directorios expuestos y en algunos casos, identificar ficheros sensibles que podrían ser descargados.
Simulando un escenario real, en un servidor con MSSQL instale XAMPP para tener un servidor web, creando una carpeta de backups con un nombre que seria un poco complicado de encontrar sin realizar acciones de bruteforcing sobre directorios.
![](https://jsec-rt.com/wp-content/uploads/2023/11/image-26-1024x345.png)
Ahora utilizaremos PowerUpSQL para realizar el descubrimiento de instancias MSSQL y utilizar la función publica “xp_dirtree” para listar contenidos internos.
Desde un equipo fuera de dominio pero con visibilidad hacia los equipos respectivos, validamos la visibilidad hacia el controlador de dominio.
![](https://jsec-rt.com/wp-content/uploads/2023/11/image-27-1024x525.png)
Luego, importamos el script en una sesión de Powershell estableciendo el estado de la política de ejecución como Bypass.
![](https://jsec-rt.com/wp-content/uploads/2023/11/image-28-1024x264.png)
Ahora, para poder consultar la información al dominio, necesitamos que las funciones importadas se ejecuten desde el contexto de un usuario de dominio, para realizar esto, algunas de las opciones mas sencillas son:
- Utilizar un objeto tipo Credential en Powershell, el cual es aceptado por la herramienta.
- Ejecutar una ventana de Powershell utilizando runas, para forzar el contexto de un usuario distinto.
- Agregar el equipo respectivo al dominio, asumiendo que el parámetro MachineAccountQuota se encuentre con los valores por defecto y que no se haya implementado restricciones sobre los usuarios de dominio.
Las primeras dos opciones son posibles de validar de manera rápida, así que en este caso, utilizaremos runas para levantar una shell en el contexto de un usuario de dominio.
![](https://jsec-rt.com/wp-content/uploads/2023/11/image-30-1024x305.png)
Una vez obtenida la shell respectiva y validado el acceso al dominio interno, procedemos a enumerar las instancias MSSQL registradas en el dominio.
![](https://jsec-rt.com/wp-content/uploads/2023/11/image-37-1024x824.png)
Observamos dos instancias registradas, por lo que podemos utilizar otra función para probar la conectividad a estas.
![](https://jsec-rt.com/wp-content/uploads/2023/11/image-38-1024x714.png)
Confirmando la accesibilidad a estos utilizando un usuario de dominio cualquiera, procedemos a listar los directorios internos utilizando la función publica “xp_dirtree”.
![](https://jsec-rt.com/wp-content/uploads/2023/11/image-39-1024x724.png)
Podemos leer mas de esta función en el siguiente enlace:
What is XP_DIRTREE? What are the alternatives to XP_Dirtree
Ahora, me paso mas de una vez el encontrarme con una aplicación web que tenia una instancia de MSSQL corriendo, por lo que pude utilizar esta función para descubrir directorios y ficheros ocultos.
En este caso, utilizaremos XAMPP por temas de simplicidad.
Podemos listar los contenidos de la carpeta xampp para explorar un poco, pero la ruta conocida donde se alojan las aplicaciones web es en la carpeta htdocs.
![](https://jsec-rt.com/wp-content/uploads/2023/11/image-40-1024x379.png)
Observamos dos carpetas distintas a la estructura por defecto, en este caso podemos explorar la carpeta backups
![](https://jsec-rt.com/wp-content/uploads/2023/11/image-41-1024x319.png)
Observamos la existencia de la carpeta backups-old-2023-migracion, la cual seria muy difícil de encontrar utilizando métodos tradicionales de descubrimiento de directorios en aplicaciones web.
Al ya no contar con mas carpetas dentro de esta ultima, obtenemos un resultado vacío con la query utilizada anteriormente, sin embargo, podemos agregar un nuevo valor como parámetro en xp_dirtree, para mostrar los archivos.
En este caso, la query ejecutada seria: exec xp_dirtree ‘C:\xampp\htdocs\backups\backups-old-2023-migracion’,1,1′
Donde los dos parámetros después de la ruta definida hacen referencia a la profundidad del listado de archivos en la función y una flag para habilitar el listado de ficheros, el cual viene deshabilitado por defecto.
Podemos descargar el fichero que no se hubiera identificado de manera rápida con métodos tradicionales utilizando un usuario de bajos privilegios y aprovechando una función valida en la instancia MSSQL.
![](https://jsec-rt.com/wp-content/uploads/2023/11/image-42-1024x624.png)
Escenario de explotación 2: Uso de funciones publicas para forzar la autenticación del servidor hacia el equipo atacante para ataques NTLM Relay.
Para este escenario, podemos aprovechar la misma función del anterior punto, o también podemos utilizar otra función llamada xp_fileexist.
Esta segunda función simplemente validara que un archivo especifico existe en la ruta especificada o no.
Como atacante, podemos aprovechar que ambas funciones permiten trabajar con rutas remotas por SMB, por lo que es posible capturar hashes o realizar ataques de relay.
Validando las direcciones IP y que la firma de mensajes SMB no sea requerida.
![](https://jsec-rt.com/wp-content/uploads/2023/11/image-43-1024x212.png)
Podemos hacer la prueba de visibilidad, observando que tipo de hashes y de que usuario se podría capturar utilizando la función xp_dirtree o xp_fileexist
Desplegando un servidor smb por Impacket.
![](https://jsec-rt.com/wp-content/uploads/2023/11/image-44-1024x960.png)
Ejecutando la función xp_dirtree en Coreint hacia el equipo atacante para capturar el hash Netntlmv2 del usuario.
![](https://jsec-rt.com/wp-content/uploads/2023/11/image-45-1024x99.png)
Observamos que el hash obtenido pertenece al usuario coreint$, ya que la instancia MSSQL se ejecuta bajo un usuario de servicio.
![](https://jsec-rt.com/wp-content/uploads/2023/11/image-46-1024x505.png)
Confirmando la posibilidad de capturar el hash del equipo Coreint, podemos desplegar el servidor relay apuntando hacia DBINT, donde agregamos al equipo CoreInt como administrador local.
Ejecutamos nuevamente la query y vemos que los hashes de usuarios locales (SAM) se obtienen.
![](https://jsec-rt.com/wp-content/uploads/2023/11/image-48-1024x536.png)
Ejecutamos nuevamente la query y vemos que los hashes de usuarios locales (SAM) se obtienen.
![](https://jsec-rt.com/wp-content/uploads/2023/11/image-49-1024x480.png)
Similar a posts anteriores, si quisiera ejecutar comandos los podría especificar o también podría desplegar un servidor socks.
![](https://jsec-rt.com/wp-content/uploads/2023/11/image-50-1024x508.png)
De esta manera, logramos utilizar las funciones internas de MSSQL para ejecutar ataques de Relay.
Escenario de explotación 3: Ejecución de código remoto a través de funciones propias de MSSQL.
La ejecución de comandos se realiza a través de xp_cmdshell, una función bastante conocida, por lo que mostraremos la explotación utilizando PowerUpSQL.
En este caso, para explotar este escenario, necesitamos a un usuario privilegiado en la base de datos para poder habilitar la función respectiva, en nuestro caso, sera el usuario de dominio Sqluser, que anteriormente lo agregamos como Sysadmin.
Iniciamos la ventana de Powershell bajo el contexto de este usuario, cuya pass podríamos haber encontrado en el escenario 1 (descarga de un fichero de backup en directorios web ocultos), validando que las credenciales sean correctas al consultar los tickets SPN relacionados a bases de datos MSSQL.
![](https://jsec-rt.com/wp-content/uploads/2023/11/image-51-1024x826.png)
Posteriormente, necesitamos validar si el usuario que tenemos realmente es privilegiado, para lo cual podemos utilizar la función Get-SQLServerLinkCrawl, que consultara bases de datos enlazadas y si tenemos privilegios de Sysadmin.
![](https://jsec-rt.com/wp-content/uploads/2023/11/image-52-1024x756.png)
El siguiente post hablara sobre bases de datos enlazadas, por lo que ahora nos interesa únicamente el valor de Sysadmin que se encuentra en 1, confirmando que somos un usuario privilegiado.
Podriamos habilitar la función xp_cmdshell manualmente, para lo cual existe bastante documentación, pero en resumen, estas serian las consultas que tendríamos que ejecutar sobre la base de datos usando al usuario privilegiado.
- EXECUTE sp_configure ‘show advanced options’, 1;
- RECONFIGURE;
- EXECUTE sp_configure ‘xp_cmdshell’, 1;
- RECONFIGURE;
Afortunadamente, PowerUpSQL tiene una función llamada Invoke-SQLOSCmd, la cual habilita xp_cmdshell de manera automática y nos permite ejecutar comandos respectivos.
![](https://jsec-rt.com/wp-content/uploads/2023/11/image-53-1024x404.png)
Si bien es posible ejecutar comandos, no es una shell interactiva, por lo que obtener resultados o información de comandos llega a ser complicado de entender.
Por ejemplo, si ejecutamos un simple ipconfig, veremos que la respuesta es automáticamente reducida para caber en la pantalla, se podría utilizar la función fl para obtener el resto de la información, pero como se observa en la captura, sigue siendo complicado de entender.
![](https://jsec-rt.com/wp-content/uploads/2023/11/image-54-1024x554.png)
Así que en este caso, lo mas recomendado seria poder desplegar una shell reversa para poder interactuar con el sistema operativo, o agregar a nuevos usuarios al grupo de administradores locales, pero esto puede llegar a ser un poco complicado por temas de antivirus y EDR.
En el siguiente post mostrare un pequeño truco que desarrolle para poder desplegar un servidor SSH “portable” utilizando una base de datos MSSQL y una cuenta de servicio, el cual puede ser utilizado posteriormente como túnel SSH para obtener acceso a redes segmentadas.