開発者/エンジニアの観点から問題を説明する答えを探しています。正確に何が悪用され、なぜ機能するのですか?
私はではなく悪用方法の説明を探しているわけではないことに注意してください。その背後にある技術的な背景に興味があるだけです。
いくつかの関連リンク:
マイクロソフトセキュリティアドバイザリ275776
MITREのCVE-20012-4969
NVDのCVE-20012-4969
CVE詳細のCVE-20012-4969
CVE-2012-4969 、別名最新IE 0-day、IEのレンダリングエンジンの解放後使用バグに基づいています。使用後-freeは、メモリが動的に割り当てられたブロックが破棄(つまり、解放)された後に使用された場合に発生します。このようなバグは、内部構造に機密性の高いメモリの場所(スタックや実行可能ヒープなど)へのポインタが含まれている状況を作成することで悪用できますブロック)プログラムがシェルコードを実行可能領域にコピーするようにします。
この場合、問題はCMshtmlEd::Exec
のmshtml.dll
関数にあります。 CMshtmlEd
オブジェクトが予期せず解放され、その後、解放操作の後にExec
メソッドが呼び出されます後。
最初に、私はいくつかの理論をカバーしたいと思います。解放後使用のしくみがわかっている場合は、先に進んでください。
低レベルでは、クラスは、その状態(フィールド、プロパティ、内部変数など)とそれを操作する一連の関数を含むメモリ領域と同等と見なすことができます。関数は実際には、インスタンスの状態を含むメモリ領域を指す「隠し」パラメータを取ります。
たとえば(excuse myterriblepseudo-C++):
class Account
{
int balance = 0;
int transactionCount = 0;
void Account::AddBalance(int amount)
{
balance += amount;
transactionCount++;
}
void Account::SubtractBalance(int amount)
{
balance -= amount;
transactionCount++;
}
}
上記は、実際には次のように表すことができます。
private struct Account
{
int balance = 0;
int transactionCount = 0;
}
public void* Account_Create()
{
Account* account = (Account*)malloc(sizeof(Account));
account->balance = 0;
account->transactionCount = 0;
return (void*)account;
}
public void Account_Destroy(void* instance)
{
free(instance);
}
public void Account_AddBalance(void* instance, int amount)
{
((Account*)instance)->balance += amount;
((Account*)Account)->transactionCount++;
}
public void Account_SubtractBalance(void* instance, int amount)
{
((Account*)instance)->balance -= amount;
((Account*)instance)->transactionCount++;
}
public int Account_GetBalance(void* instance)
{
return ((Account*)instance)->balance;
}
public int Account_GetTransactionCount(void* instance)
{
return ((Account*)instance)->transactionCount;
}
参照の不透明な性質を示すためにvoid*
を使用していますが、それはそれほど重要ではありません。重要なのは、誰かがAccount
構造体を手動で変更できるようにしたくないということです。そうしないと、勝手にお金を追加したり、トランザクションカウンターを増やすことなく残高を変更したりできます。
ここで、次のようなことを想像してください。
void* myAccount = Account_Create();
Account_AddBalance(myAccount, 100);
Account_SubtractBalance(myAccount, 75);
// ...
Account_Destroy(myAccount);
// ...
if(Account_GetBalance(myAccount) > 1000) // <-- !!! use after free !!!
ApproveLoan();
これで、Account_GetBalance
に到達するまでに、myAccount
のポインター値は、実際には不確定な状態のメモリを指します。ここで、次のことができると想像してください。
Account_Destroy
の呼び出しを確実にトリガーします。Account_Destroy
を実行しますが、beforeAccount_GetBalance
を実行して、私たちが選択した内容で、合理的な量のメモリ。通常、これらの呼び出しはさまざまな場所でトリガーされるため、これを実現することはそれほど難しくありません。さて、ここで何が起こるかです:
Account_Create
は、8バイトのメモリブロック(各フィールドに4バイト)を割り当て、そのポインタを返します。このポインタはmyAccount
変数に格納されています。Account_Destroy
はメモリを解放します。 myAccount
変数は、引き続き同じメモリアドレスを指します。39 05 00 00 01 00 00 00
の繰り返しブロックを含むメモリ割り当てをトリガーします。このパターンは、balance = 1337
およびtransactionCount = 1
に相関します。古いメモリブロックが空きとしてマークされているため、メモリマネージャが古いメモリブロックの上に新しいメモリを上書きする可能性が非常に高くなります。Account_GetBalance
が呼び出され、Account
構造体を指すことが期待されます。実際には、上書きされたメモリブロックを指しているため、実際の残高は1337なので、ローンが承認されます。もちろん、これはすべて単純化されたものであり、実際のクラスはかなり鈍い複雑なコードを作成します。ポイントは、クラスインスタンスは実際にはデータのブロックへの単なるポインタであり、クラスメソッドは他の関数とまったく同じですが、インスタンスへのポインタをパラメータとして「黙って」受け入れます。
この原則は、スタック上の値を制御するように拡張できます。これにより、プログラムの実行が変更されます。通常、目標はシェルコードをスタックにドロップし、次に戻りアドレスを上書きしてjmp esp
命令をポイントするようにして、シェルコードを実行することです。
このトリックは非DEPマシンで機能しますが、DEPが有効になっていると、スタックの実行が妨げられます。代わりに、シェルコードは Return-Oriented Programming(ROP) を使用して設計する必要があります。これは、DEPをバイパスするために、アプリケーションとそのモジュールからの正当なコードの小さなブロックを使用してAPI呼び出しを実行します。
とにかく、少し話題から外れるので、CVE-2012-4969のジューシーな詳細について見ていきましょう。
実際には、ペイロードは パックされたFlashファイル を介してドロップされ、Java脆弱性と新しいIEバグを悪用するように設計されています興味深い点もいくつかあります AlienVaultによる分析 。
metasploit module は次のように述べています:
このモジュールは、Microsoft Internet Explorer(MSIE)にある脆弱性を悪用します。 HTMLページをレンダリングするとき、CMshtmlEdオブジェクトは予期しない方法で削除されますが、同じメモリが後でCMshtmlEd :: Exec()関数で再利用され、解放後使用状態になります。
バグについては興味深い ブログ投稿 もありますが、英語はかなり貧弱ですが、著者は中国人だと思います。とにかく、ブログの投稿はいくつかの詳細に行きます:
IEの
execCommand
関数がコマンドイベントを実行すると、対応するCMshtmlEd
オブジェクトがAddCommandTarget
関数によって割り当てられ、mshtml@CMshtmlEd::Exec()
関数の実行。ただし、対応するイベントを追加するexecCommand
関数の直後に、対応するイベント関数がトリガーされて呼び出されます。document.write("L")
関数を使用して、対応するイベントのhtmlを書き換えます関数が呼び出されます。これにより、リードIECHTMLEditor::DeleteCommandTarget
を呼び出して、CMshtmlEd
の元の適用オブジェクトを解放し、msheml!CMshtmlEd::Exec()
関数。
それを解析して、もう少し読みやすいものにしてみましょう。
execCommand
を介して実行され、CMshtmlEd
関数を介してAddCommandTarget
オブジェクトを割り当てます。document.write
を使用してページを変更します。CMshtmlEd
オブジェクトはCHTMLEditor::DeleteCommandTarget
によって解放されます。execCommand
は後でそのオブジェクトに対してCMshtmlEd::Exec()
を呼び出し、after解放されました。クラッシュサイトのコードの一部は次のようになります。
637d464e 8b07 mov eax,dword ptr [edi]
637d4650 57 Push edi
637d4651 ff5008 call dword ptr [eax+8]
解放後使用により、攻撃者はedi
の値を制御できます。これは、攻撃者が制御するメモリを指すように変更できます。メモリ割り当てを介して、01234f00
のメモリに任意のコードを挿入できるとしましょう。次のようにデータを入力します。
01234f00: 01234f08
01234f04: 41414141
01234f08: 01234f0a
01234f0a: cccccccc // int3 breakpoint
edi
を01234f00
に設定します。mov eax,dword ptr [edi]
を使用すると、eax
のアドレスにあるメモリがedi
に入力されます(つまり、01234f00
)。Push edi
は01234f00
をスタックにプッシュします。call dword ptr [eax+8]
はeax
(01234f00
)を取り、それに8を追加して01234f08
を与えます。次に、そのメモリアドレスを逆参照し、01234f0a
を提供します。最後に、01234f0a
を呼び出します。01234f0a
のデータは命令として扱われます。 cc
はint3
に変換され、デバッガーがブレークポイントを発生させます。コードを実行しました!これにより、eip
を制御できるため、プログラムのフローを独自のシェルコードまたはROPチェーンに変更できます。
上記は例であり、実際にはこのバグの悪用には他にも多くの課題があることに注意してください。これはかなり標準的な解放後使用ですが、JavaScriptの性質上、興味深いタイミングとヒープスプレーのトリックが発生します。DEPはROPを使用して実行可能メモリブロックを取得するように強制します。
とにかく、これは研究するのが楽しかったです。
CVE-2012-4969 への参照が表示されるtechnetの記事を見ると、 CVEページにはいくつかの参照がありますが、最も役立つ(IMHO)は これ です。英語は素晴らしくありませんが、それは読みやすいです。
よりわかりやすい言語の説明については El Reg も参照してください。
ここでは、他の人の作業を引き裂くだけなので、ここでは大きな説明はしませんが、要約すると、任意のコードが実行される死んだオブジェクトの処理に関するコーディングエラーです。