トップ回答者
アプリケーション(EXE)におけるATL の脆弱性について

質問
-
VC++2008
現在、Windowsファイアウォールの制御を行うアプリケーション(拡張子がEXE)の開発を行っています。この、アプリケーションを実行すると「ATL.DLL」がロードされているのでATL の脆弱性(MS09-035)に該当するか調査を行っています。
このアプリケーションを開発するにあたってCOMのOCXやActiveX,コンポーネントは使用せずにPlatformSDKのクラスやAPIを直接使用しています。ATLのクラスを使用しているのは、CComBSTR(BSTRのラッパークラス)くらいです。
以下のサイトの影響をうけるかどうかのフローを見ると該当しないように思います。
http://msdn.microsoft.com/ja-jp/visualc/ee309358.aspx
アプリケーションの場合も脆弱性に該当するのでしょうか?
ご存じの方がいらっしゃいましたらアドバイスをお願いします。
よろしくお願いします。
回答
-
ATLだけの話のように書かれていますが,
修正されたソースと前のものを比べてみると,
脆弱性の本質はATLの仕組みそのものではなく,
ATL を使っていなくても
Variant型でIStreamインタフェースを扱っている 場合で,
型 や CLSID を,前もって想定したものと比べてから扱う
ようにしていない場合は,
外部から(COMで言うところの)ストリームを受け取る場合は
影響を受ける可能性がありそうですね。
そもそもATLの実装だけに限って起きる話ではないので,
ActiveXコントロールに限った話ではないです。
なので,
COM仕様を公開していない,平のアプリでも
実装しだいでは影響がありますね。
COM仕様になっているもので,
IE上にロードされるものは,危険が高いってだけです。
稍丼 / yayadon -
> IStreamインタフェース のreadメソッドにてデータを読み取るというような
> イメージで考えればよいのでしょうか?
そのタイミングです。
ストリームを送る側は,
IPersistStream::GetClassID -> WriteClassStm関数 -> IPersistStream::Save
の流れか,
ヘルパー関数の OleSaveToStream を呼び出して,
COMオブジェクトの CLSID をストリーム(に埋め込ん)で渡せます。
で,
ATL での今回該当するマクロやメソッドを使っていないとしても,
読み出すときに,楽をするために,
ヘルパー関数の OleLoadFromStream を呼び出している場合があります。
※void** ppvObj ポインタのポインタは,このときに受け取りに指定できるのは
受け取りに使用するインタフェースポインタの REFIID だけということに注目
呼び出しの結果,
ストリームから,実際に作成されたCOMオブジェクトのインスタンスからの
指定したインタフェースへのポインタを取得できます。
で,よく考えてみると,
そのインタフェースの REFIID が
IUnknown や IDispatch インタフェースの場合,
ストリームから作成されたインスタンスが
自分が想定していたクラスのインスタンスからの インタフェースポインタとは限らないですよね?
なので,
ヘルパー関数 OleLoadFromStream を使っている場合は,
呼び出す前に,
ReadClassStm関数 でストリームから CLSID を取得して,
想定した CLSID になっているか?を確認する必要があります。
ヘルパー関数を使っていない場合でも,
ストリームから ReadClassStm関数 を呼び出したときに,
想定した CLSID か?を確認して
CoCreateInstance(Ex)
(or CoGetClassObject -> IClassFactory::CreateInstance)
へ進まないといけません。
このことは,以下のことに似ています。
メモリ上のバッファをぺろ~んとコピーする時,
今は,サイズを指定しないといけないですよね?
それと同じで
ストリームからCOMをインスタンス化する時は,
CLSID の確認がいつでも必要ってことです。
ATL に限った話ではないのはそのためです。
> もしそうであれば、修正前と修正後のソースを参照することができるのでしょうか?
ATL のソースは,ヘッダーの中に実装も書かれています。
ふつうに使っているヘッダーの中を見ればわかります。
すでにパッチをあててしまっていると思うので
修正前のものはわからないですが,
vtExpected
cclsidAllowed
ClassesAllowedInStream (これは クラス(union))
を検索すれば,該当箇所は分かります。
(たぶん,漏れはないと思うけど確認したわけではありません)
旧ソースを取ってある場合は,
WinDiff で違いを確認できます。
追記&修正:
上でVariant型と書きましたが,
Variant型 を使用しているかどうかは,
よく考えてみると,今回の件とは直接は関係なかったです。
一番上のレスでの発言を訂正しておきます。
稍丼 / yayadon -
あと,
MS09-04
http://www.microsoft.com/japan/technet/security/bulletin/ms09-034.mspx
の方もATLの脆弱性絡みと書かれていますが,
こちらは,
MS内部だけで使われているATLのプライベートバージョンの
タイプミスから来ているという話
http://blogs.msdn.com/sdl/archive/2009/07/28/atl-ms09-035-and-the-sdl.aspx
だそう なので
公開されているATLとは関係ないんじゃないかと思います。
稍丼 / yayadon- 回答としてマーク 高橋 春樹 2009年8月12日 2:23
すべての返信
-
ATLだけの話のように書かれていますが,
修正されたソースと前のものを比べてみると,
脆弱性の本質はATLの仕組みそのものではなく,
ATL を使っていなくても
Variant型でIStreamインタフェースを扱っている 場合で,
型 や CLSID を,前もって想定したものと比べてから扱う
ようにしていない場合は,
外部から(COMで言うところの)ストリームを受け取る場合は
影響を受ける可能性がありそうですね。
そもそもATLの実装だけに限って起きる話ではないので,
ActiveXコントロールに限った話ではないです。
なので,
COM仕様を公開していない,平のアプリでも
実装しだいでは影響がありますね。
COM仕様になっているもので,
IE上にロードされるものは,危険が高いってだけです。
稍丼 / yayadon -
yayadonさん 貴重な情報ありがとうございます。
開発中のアプリは、Variant型のIStreamインタフェースは使用していないということと、ファイアウォールからのポート情報の読み込み,書き込みを行うアプリであることから影響を受ける確率としては低いと考えています。
外部からストリームを受け取るというのは、IStreamインタフェースのreadメソッドにてデータを読み取るというようなイメージで考えればよいのでしょうか?IStreamインタフェースについては使用したことがない為、イメージがよくつかめませんでした。
>修正されたソースと前のものを比べてみると,
>脆弱性の本質はATLの仕組みそのものではなく,
これは、パッチで修正される部分についての修正前と修正後のソースということでしょうか?もしそうであれば、修正前と修正後のソースを参照することができるのでしょうか?
度々、ご質問してしまい申し訳ありませんが、よかったら情報の提供をお願いします。 -
> IStreamインタフェース のreadメソッドにてデータを読み取るというような
> イメージで考えればよいのでしょうか?
そのタイミングです。
ストリームを送る側は,
IPersistStream::GetClassID -> WriteClassStm関数 -> IPersistStream::Save
の流れか,
ヘルパー関数の OleSaveToStream を呼び出して,
COMオブジェクトの CLSID をストリーム(に埋め込ん)で渡せます。
で,
ATL での今回該当するマクロやメソッドを使っていないとしても,
読み出すときに,楽をするために,
ヘルパー関数の OleLoadFromStream を呼び出している場合があります。
※void** ppvObj ポインタのポインタは,このときに受け取りに指定できるのは
受け取りに使用するインタフェースポインタの REFIID だけということに注目
呼び出しの結果,
ストリームから,実際に作成されたCOMオブジェクトのインスタンスからの
指定したインタフェースへのポインタを取得できます。
で,よく考えてみると,
そのインタフェースの REFIID が
IUnknown や IDispatch インタフェースの場合,
ストリームから作成されたインスタンスが
自分が想定していたクラスのインスタンスからの インタフェースポインタとは限らないですよね?
なので,
ヘルパー関数 OleLoadFromStream を使っている場合は,
呼び出す前に,
ReadClassStm関数 でストリームから CLSID を取得して,
想定した CLSID になっているか?を確認する必要があります。
ヘルパー関数を使っていない場合でも,
ストリームから ReadClassStm関数 を呼び出したときに,
想定した CLSID か?を確認して
CoCreateInstance(Ex)
(or CoGetClassObject -> IClassFactory::CreateInstance)
へ進まないといけません。
このことは,以下のことに似ています。
メモリ上のバッファをぺろ~んとコピーする時,
今は,サイズを指定しないといけないですよね?
それと同じで
ストリームからCOMをインスタンス化する時は,
CLSID の確認がいつでも必要ってことです。
ATL に限った話ではないのはそのためです。
> もしそうであれば、修正前と修正後のソースを参照することができるのでしょうか?
ATL のソースは,ヘッダーの中に実装も書かれています。
ふつうに使っているヘッダーの中を見ればわかります。
すでにパッチをあててしまっていると思うので
修正前のものはわからないですが,
vtExpected
cclsidAllowed
ClassesAllowedInStream (これは クラス(union))
を検索すれば,該当箇所は分かります。
(たぶん,漏れはないと思うけど確認したわけではありません)
旧ソースを取ってある場合は,
WinDiff で違いを確認できます。
追記&修正:
上でVariant型と書きましたが,
Variant型 を使用しているかどうかは,
よく考えてみると,今回の件とは直接は関係なかったです。
一番上のレスでの発言を訂正しておきます。
稍丼 / yayadon -
あと,
MS09-04
http://www.microsoft.com/japan/technet/security/bulletin/ms09-034.mspx
の方もATLの脆弱性絡みと書かれていますが,
こちらは,
MS内部だけで使われているATLのプライベートバージョンの
タイプミスから来ているという話
http://blogs.msdn.com/sdl/archive/2009/07/28/atl-ms09-035-and-the-sdl.aspx
だそう なので
公開されているATLとは関係ないんじゃないかと思います。
稍丼 / yayadon- 回答としてマーク 高橋 春樹 2009年8月12日 2:23
-
yayadon様
レスが遅くなり申し訳ありません。自宅からしかレスできないので今の時間になってしまいました。
丁寧に情報をいただき本当にありがとうございます。
Windowsファイアウォールからのデータの取得やデータの書き込みは、SDKのクラスのメソッドで行っている為、そのメソッドの中で同様な処理が行われているかは不明です。
現状では、自分が作成した箇所にストリーム経由の入出力はない為、影響がでる確率はあまり高くないと考えています。どうするかについては、上司と話し合いあいたいと思っています。
yayadonさんからいただいた情報は、今後ストリームを使用する場合にとても役にたつ情報だと思います。
ATLのソースの確認方法もわかりました。パッチはまだインストールしていませんでしたので新ソースとの違いまではわかりませんでしたがインストール後に確認するつもりです。 -
こんにちは、フォーラムオペレータの高橋春樹です。
yayadonさん、初めまして。アドバイスありがとうございました。
しのさん、初めまして。MSDNフォーラムのご利用ありがとうございます。
yayadonさんから、アドバイスを頂いたと思うのですが、問題解決に繋がりましたでしょうか?
今回yayadonさんから頂いた情報が有用なものだと思いましたので、
勝手ながら、回答マークを付けさせてもらいました。
また、ご質問がありましたら、新たに投稿して頂ければと思います。今後ともMSDNフォーラムを、よろしくお願いします。
マイクロソフト株式会社 フォーラム オペレータ 高橋春樹