質問:
MS SQLServerによるサーバー側のクエリインターセプト
Hernán
2013-04-06 00:45:12 UTC
view on stackexchange narkive permalink

SQL Server2008プロセスに到着するクエリのインターセプトを調査しています。

SQLOSアーキテクチャは、次のシステムDLLに分割されています。

  • sqlmin .dll :ストレージ、レプリケーション、セキュリティ機能など。
  • sqllang.dll :TransactSQLクエリ実行エンジン、式の評価など。
  • sqldk.dll :タスクのスケジュールとディスパッチ、作業スレッドの作成、メッセージループなど。

SQLSERVR サービスプロセスインスタンスSQLOSコンポーネントは sqlboot.dll および sqldk.dll を介して、ワーカースレッドはサーバー内の選択された接続方法(TCP / IP、ローカル共有メモリ、または名前付きパイプ)を介してクエリを受信します。

テキストクエリを検索するsqlservr.exeプロセスアドレス空間をデバッグしました。クエリ文字列は読み取り可能のようですが、SQLOSスケジューラに入るときにクエリが傍受される可能性のあるポイントを見つけることができませんでした。

パイプまたはTCP / IPをリッスンすることは現時点ではオプションではありません。より高いレベル、できればSQLOSコンポーネントレベルで注入したいと思います。

どこから調査を開始するかについて何か考えはありますか?

最後から2番目の段落で明らかな最初の選択肢を除外しているのはなぜですか?
私は0c00lを使用していますが、私の質問は、シンシムプログラム(たとえば、odbcコネクタ)でクエリを入力して実行トレースを実行しない理由です。ソケットに接続し、実行トレースを実行します(recvなどで開始)。次に、2つのトレース間の結合をチェックして、それらが交差し始める時期を確認し、それが実行可能なアプローチであるかどうかを確認しますか?
プロトコルレベルでのインターセプトは、SQLインジェクションのようなセキュリティの脅威を処理するための最良の方法ではないと思います。脅威を取り除きたい場合は、プロトコルについてもっと知る必要があります。クエリしかない場合は、1つのポイントに集中できます。また、クライアントレベルで傍受すると、サーバー側の攻撃を処理できません。
@sw。:何度か読み直しましたが、これは目的ではないようです。
@0xC0000022LHernanは明らかに他の選択肢を認識しています。彼は、より高いレベルで関数をインターセプトする場所を具体的に知りたいと考えています(つまり、フックを使用します)。他のものをフックすることについての多くのリソースが存在する一方で、私がそれについてのリソースを検索して見つけることができなかったので、それを知ることは興味深いでしょう。 SQLServerをインストルメント化しないというMicrosoftからの推奨事項を見つけました。「サードパーティの迂回路または同様の手法の使用はSQLServerではサポートされていません」http://support.microsoft.com/kb/920925
@sw。:私が言っていたのは、ヘルナンが* xyz *のために傍受について何も言及しなかったということだけです。
@0xC0000022L,失礼だったらごめんなさい。 Hernanが「より高いレベル、できればSQLOSコンポーネントレベルで注入したい」と言っているので、SQLServerをフックする方法を知ることは興味深いと思います。
@sw。:心配しないでください。書面によるコミュニケーションでは、他の方法で証明される前に最善の意図があると思います。失礼だとは思わなかった。
@swが言うように、私はODBCレベルのインターセプトなどの他の代替手段を知っています。より簡潔にするために、複数のポイント(共有メモリ、パイプ、TCP / IP I / Oなど)でパッチを適用したくはありませんが、クライアントに関係なく、すべてのクエリが計画と実行のためにスケジュールされている単一のポイントでパッチを適用します-サーバーインターフェイスまたは通信方法。
WMIは、これを行うための良い可能性ですか?
@Lizz WMIには、すべてのクエリを監視するためのインターフェイスがありません
四 答え:
Brendan Dolan-Gavitt
2013-04-15 06:05:42 UTC
view on stackexchange narkive permalink

これは日曜日の午後の楽しいプロジェクトのようだったので、試してみました。要点を簡単に説明すると、クエリを解析して実行するSQL Serverの関数の呼び出しスタックは次のとおりです(Windows 7 SP132ビットで実行されているSQLServer 2008 R2から取得したアドレスとオフセット):

  0x7814500a msvcr80.i386!memcpyの+ 0x5a0x013aa370 SQLSERVR!CWCharStream :: CwchGetWChars + 0x5c0x013a9db5 SQLSERVR!CSQLStrings :: CbGetChars + 0x350x012ffa50 SQLSERVR!CParser :: FillBuffer + 0x3d0x0138bbfd SQLSERVR!CParser :: CParser + 0x3c80x01352e96 SQLSERVR!sqlpars + 0x7b0x013530f2 SQLSERVR !CSQLSource :: FParse + 0x16d0x013531ed sqlservr!CSQLSource :: FParse + 0x2680x012ff9e8 sqlservr! `string '+ 0x3c0x015894b8 sqlservr!CSQLSource :: Execute!serv5!8serv + 0x2c80x0158ad31 sqlservr!process_request + 0 0xdd0x015cf9ea sqlservr!SOS_Scheduler :: RunTask + 0xb40x015cf575 sqlservr!SOS_Scheduler :: IsShrinkWorkersNecessary + 0x480x77f06854 ntdll!ZwSignalAndWaitForSingleObject + 0xc0x77e479e2 kernel32!これについては、おそらく CSQLSource クラス、特にその Execute メソッドを詳しく調べたいと思うでしょう。 

この情報を武器に、私はまた、SQL Serverのメモリダンプからクエリ文字列を抽出する方法について、Microsoftの誰かによるブログ投稿をいくつか掘り下げることもできます。その投稿は、私たちが正しい方向に進んでいることを確認しているようで、介入する場所とクエリ文字列を抽出する方法を提供します。

方法論

これは、何らかの形式のDynamic Binary Instrumentation(DBI)を使用して最も簡単に対処できると感じました。クエリ文字列はSQLServerプロセスのどこかで処理されると思われるため、プロセスによって行われたメモリの読み取りと書き込みを調べて、クエリ文字列を読み書きするポイントを検索できます。次に、その時点でコールスタックをダンプして、どの興味深いアドレスが表示されるかを確認し、それらをシンボルにマップし直すことができます(Rolfが指摘しているように、SQL Serverにはデバッグシンボルがあります)。基本的にはそれと同じくらい簡単でした!

もちろん、コツは、プロセスを簡単に計測できる何かを身に付けることです。 QEMUに基づく(できれば間もなくリリースされる)システム全体の動的分析フレームワークを使用して、これを解決しました。これにより、SQLServerを PINなどで実行することに伴う不快感を回避できます。フレームワークには記録と再生のサポートが含まれているため、インストルメンテーションを使用してサーバープロセスの速度を低下させることも心配する必要はありませんでした。コールスタックを取得したら、 PDBParseを使用して関数名を取得しました。

明確にするために:あなたのメソッドはサーバーがQEMU内で実行されている場合にのみ機能しますか?副次的な質問:実際にクエリを変更できますか?
私が使用した特定の方法は、サーバーがQEMUで実行されている場合にのみ機能します。ただし、メモリの読み取り/書き込みをインストルメント化することで、PINなどでも同じことができます。この時点でクエリを変更できるかどうかはわかりません。クエリ文字列を使用してMD5ハッシュ(CSQLStrings :: GenerateDurableSqlHandle + 0x40)を構築する場所が少なくとも1つあるので、その時点より前に変更する必要があります。
洗練された、非常に興味深いアプローチで、技術的に正しい。お時間を割いてご協力いただきありがとうございます。
デバッグシンボルに関する注意:SQL Server 2012 RTM(11.0.2100.60)には、パブリックデバッグシンボルがあります。現時点では、11.0.3128.0のPDBを入手できませんでした。さらに、SP1(11.0.3000)で利用できるかどうかもわかりません。したがって、SQL 2012システムDLLを使用する場合は、このことに注意してください。ビルド情報については、http://sqlserverbuilds.blogspot.com.ar/を参照してください。
ブレンダンの回答に続いて、ヘルナンの作業例はhttps://github.com/nektra/SQLSvrInterceptで入手できます。
0xC0000022L
2013-04-17 05:43:34 UTC
view on stackexchange narkive permalink

トラフィックのみをスニッフィングするのは簡単です

トラフィックをスニッフィングしたいだけの場合は、 WireShark aに付属の TDSプロトコルスニファーを使用できます。 >。

怠惰があなたを導きましょう-怠惰はリバーサーの友達

パイプやTCP / IPを聞くことはこのオプションではありません瞬間;より高いレベル、できればSQLOSコンポーネントレベルで注入したいと思います。

すべての情報がすぐに利用可能で、すべてがすぐに利用できるのに、なぜこれを特定の方法で行うことを主張するのかわかりません。あなたがする必要があるのはジグソーピースを一緒にすることです。これは、最も簡単で最速の、つまり最も怠惰な方法のように思われます。 TCP / IPに加えて、 より高いレベルです。これは、SQLサーバーのIP /名前を乗っ取って、実際のSQLサーバーマシンに到達する前でも、TCP / IPを傍受できるためです。間に「プロキシ」を置きます。どのくらい高レベルにしますか?あなたが主張しているのは、実際にはMS SQLServerの下位レベルの内臓にドリルダウンすることです。

MSSQL Serverは、文書化されたプロトコルを使用し、 LSPを使用しますそのトラフィックをスニッフィング、傍受、さらには操作できるはずです。私が覚えている限り、LSPは、トラフィックをフィルタリングしているアプリケーションのプロセススペース内で実行されます。文字通り、それらをその場しのぎのアプリケーションレベルファイアウォールと見なすことができます。

あるいは、おそらく、とにかくより良い選択ですが、既存の無料の FreeTDS(ライセンス供与済み)に基づいてプロキシを作成できます。 LGPLの下で)。 tdspool プログラムは、この取り組みを開始するための良いポイントです。はい、これは転送されたトラフィックをスニッフィングするだけでなく、実際の傍受にも適しているはずです。ライブラリ(FreeTDS)を使用して、クエリをデコードおよび再エンコードできます。そのライブラリは、明らかにLSP内で使用するライブラリでもあります。

MS SQL Server 2008をインストールし、IDA Proで簡単に確認しましたが、逆アセンブリの詳細に入る時間を節約します。 ブレンダンの答えは、簡単な方法が利用できるこの過度に複雑な方法に同意できない場合でも、優れた概要を提供します。しかし、その後、あなた(ヘルナン)がそれを求めました。

Rolf Rolles
2013-04-13 05:19:48 UTC
view on stackexchange narkive permalink

一般的に言って、このような問題はアプリケーション固有のものです。したがって、ユーザーのブロードウェイが彼の答えに反対票を投じたという事実にもかかわらず、問題に固有の素晴らしい特別な解決策を知らなかった場合に私が与えるアドバイスとまったく同じでした。あなたがしなければならないことは、データがプロセスに入ってくるのを見て、それがプログラム全体でコピーされ操作されるときにそれに従うことです。このタスクは、SQL Serverでデバッグシンボルを使用できるため、一般的な場合よりも簡単です。これらの線に沿って何かを試みましたか?たとえば、SQL Serverのコンテキストでネットワーク受信タイプの関数にブレークポイントを設定し、ネットワーク経由で受信するデータにハードウェアRWブレークポイントを設定してから、データが大量のコードをどのように移動するかを監視しますか?

ええ、誰かがこのケースについてすでに持っているアプリケーション固有の知識がある場合、おそらく彼らはそれを明らかにするでしょうが、それは不足していますが、これは調査の明白な道です。ただし、SQLサーバーにはSQLステートメントを実行するかなり複雑なシステムがある場合があるため、元に戻すには時間がかかる場合があります。または多分それは簡単です。 SQLステートメントを入力として受け入れる関数を*想像*します;)。
broadway
2013-04-11 19:34:56 UTC
view on stackexchange narkive permalink

そのターゲットについて具体的な知識はありませんが、おそらく私が取るアプローチは、パイプ、tcp、および共有メモリを介して同じメッセージを送信し、ピンでそれらをトレースして、基本ブロックがヒットした場所を探すことです。すべてのトレースに収束すると、適切な注入ポイントを微調整するためのいくつかの開始点が得られるはずです。

多分それは私だけですが、私はあなたの解決策に従うことができません。おそらく、リンク、詳細情報、説明、および詳細でこれを具体化することができますか?
彼は、SQLコマンドを実行し、実行されているように見えるコードをメモし、そのコードに飛び込んで、SQLコマンド実行のチェーンの最初の関数までさかのぼると言っているだけだと思います。もちろん、それが「それほど単純」であるかどうかを知っている人は、おそらくかなり複雑な実行システムを持っています。とにかく、私の答えではなく、私が読んだと思うものを明確にするだけです。
ではない正確に。それぞれの入力タイプを使用して同じクエリを入力し、プログラムのパスを調べると言っています。ピンは、この種のことを行うための非常にアクセスしやすいツールです(もちろん、それだけではありませんが)。


このQ&Aは英語から自動的に翻訳されました。オリジナルのコンテンツはstackexchangeで入手できます。これは、配布されているcc by-sa 3.0ライセンスに感謝します。
Loading...