web-dev-qa-db-ja.com

バッファーオーバーフローでスタックに書き込むには、常にEIPを上書きする必要がありますか?

バッファーオーバーフローでスタックに書き込むには、常にEIPを上書きする必要がありますか?メモリはどのように構成されていますか?グーグルで適切なグラフが見つかりません

7
John Smith

スタックベースのバッファオーバーフロー を利用するために、常に戻りアドレスを上書きする必要はありません(スタックレイアウトの優れた図もあります)。スタックベースのバッファオーバーフローを使用すると、関数のローカルスコープで宣言された他の変数が破損し、興味深い結果が得られます。

たとえば、認証機能があるとしましょう:

//I like to think of the return address as sitting on top of every function.
//void * ret;
boolean login(char * password){
  boolean is_logged_in=False;
  char buf[5];
  strcpy(buf,password);
  if(strmp(buf, MASTER_PASSWORD)==0){
     is_Logged_int=True;
  }
  return is_logged_in;
}

スタックレイアウトは、is_logged_inがbufの上になるようになっています。戻りアドレスを含むスタックフレームは、is_logged_inの上のどこかにあります。戻りアドレスは、関数が戻る場合にのみEIPになります。ただし、攻撃者がこのバッファオーバーフローを利用するために、攻撃者がスタックフレームを破損する必要はありません。 is_logged_inの値をTrueと等しい値で上書きするだけで、攻撃者はMASTER_PASSWORDの値を知らなくても認証を受けることができます。

このバッファオーバーフローの脆弱性では、ASLR、NXゾーン、スタックカナリアを使用しても悪用を防ぐことはできません。実際、プラットフォーム(windows/linux/arm/x86 ...)に関係なく、まったく同じエクスプロイトが機能する可能性もあります。

(免責事項:このハッキング手法については、「ハッキング:悪用の芸術」で読んだと思います)

10
rook

それが逆の方法です。スタックバッファをオーバーフローさせます(そのように)関数が戻るときにEIPがロードされるフィールドを上書きします。

通常のアーキテクチャでは、スタックは下向きに成長するため、関数が呼び出されたときにスタックにプッシュされた「戻りアドレス」は数バイトafterローカル変数です。ローカルバッファをオーバーフローさせることにより、RAM内の後にあるもの、つまり戻りアドレスを上書きすることができます。関数が戻ると、対応するretオペコードが戻りアドレスをEIPにロードします。これは、実行がそのアドレスにジャンプすることを意味します。

4
Thomas Pornin