web-dev-qa-db-ja.com

技術的な観点から、2012年9月に発見されたゼロデイInternet Explorerの脆弱性はどのように機能しますか?

開発者/エンジニアの観点から問題を説明する答えを探しています。正確に何が悪用され、なぜ機能するのですか?

私はではなく悪用方法の説明を探しているわけではないことに注意してください。その背後にある技術的な背景に興味があるだけです。

いくつかの関連リンク:

マイクロソフトセキュリティアドバイザリ275776
MITREのCVE-20012-4969
NVDのCVE-20012-4969
CVE詳細のCVE-20012-4969

20
Mahn

CVE-2012-4969 、別名最新IE 0-day、IEのレンダリングエンジンの解放後使用バグに基づいています。使用後-freeは、メモリが動的に割り当てられたブロックが破棄(つまり、解放)された後に使用された場合に発生します。このようなバグは、内部構造に機密性の高いメモリの場所(スタックや実行可能ヒープなど)へのポインタが含まれている状況を作成することで悪用できますブロック)プログラムがシェルコードを実行可能領域にコピーするようにします。

この場合、問題はCMshtmlEd::Execmshtml.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のポインター値は、実際には不確定な状態のメモリを指します。ここで、次のことができると想像してください。

  1. Account_Destroyの呼び出しを確実にトリガーします。
  2. afterAccount_Destroyを実行しますが、beforeAccount_GetBalanceを実行して、私たちが選択した内容で、合理的な量のメモリ。

通常、これらの呼び出しはさまざまな場所でトリガーされるため、これを実現することはそれほど難しくありません。さて、ここで何が起こるかです:

  1. Account_Createは、8バイトのメモリブロック(各フィールドに4バイト)を割り当て、そのポインタを返します。このポインタはmyAccount変数に格納されています。
  2. Account_Destroyはメモリを解放します。 myAccount変数は、引き続き同じメモリアドレスを指します。
  3. 39 05 00 00 01 00 00 00の繰り返しブロックを含むメモリ割り当てをトリガーします。このパターンは、balance = 1337およびtransactionCount = 1に相関します。古いメモリブロックが空きとしてマークされているため、メモリマネージャが古いメモリブロックの上に新しいメモリを上書きする可能性が非常に高くなります。
  4. 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を書き換えます関数が呼び出されます。これにより、リードIE CHTMLEditor::DeleteCommandTargetを呼び出して、CMshtmlEdの元の適用オブジェクトを解放し、msheml!CMshtmlEd::Exec()関数。

それを解析して、もう少し読みやすいものにしてみましょう。

  1. イベントがドキュメントの要素に適用されます。
  2. イベントはexecCommandを介して実行され、CMshtmlEd関数を介してAddCommandTargetオブジェクトを割り当てます。
  3. ターゲットイベントは、document.writeを使用してページを変更します。
  4. イベントは不要になったため、CMshtmlEdオブジェクトはCHTMLEditor::DeleteCommandTargetによって解放されます。
  5. 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
  1. 解放後使用のバグにより、edi01234f00に設定します。
  2. mov eax,dword ptr [edi]を使用すると、eaxのアドレスにあるメモリがediに入力されます(つまり、01234f00)。
  3. Push edi01234f00をスタックにプッシュします。
  4. call dword ptr [eax+8]eax01234f00)を取り、それに8を追加して01234f08を与えます。次に、そのメモリアドレスを逆参照し、01234f0aを提供します。最後に、01234f0aを呼び出します。
  5. 01234f0aのデータは命令として扱われます。 ccint3に変換され、デバッガーがブレークポイントを発生させます。コードを実行しました!

これにより、eipを制御できるため、プログラムのフローを独自のシェルコードまたはROPチェーンに変更できます。

上記はであり、実際にはこのバグの悪用には他にも多くの課題があることに注意してください。これはかなり標準的な解放後使用ですが、JavaScriptの性質上、興味深いタイミングとヒープスプレーのトリックが発生します。DEPはROPを使用して実行可能メモリブロックを取得するように強制します。

とにかく、これは研究するのが楽しかったです。

50
Polynomial

CVE-2012-4969 への参照が表示されるtechnetの記事を見ると、 CVEページにはいくつかの参照がありますが、最も役立つ(IMHO)は これ です。英語は素晴らしくありませんが、それは読みやすいです。

よりわかりやすい言語の説明については El Reg も参照してください。

ここでは、他の人の作業を引き裂くだけなので、ここでは大きな説明はしませんが、要約すると、任意のコードが実行される死んだオブジェクトの処理に関するコーディングエラーです。

2
GdD