バッファーオーバーフローでスタックに書き込むには、常にEIPを上書きする必要がありますか?メモリはどのように構成されていますか?グーグルで適切なグラフが見つかりません
スタックベースのバッファオーバーフロー を利用するために、常に戻りアドレスを上書きする必要はありません(スタックレイアウトの優れた図もあります)。スタックベースのバッファオーバーフローを使用すると、関数のローカルスコープで宣言された他の変数が破損し、興味深い結果が得られます。
たとえば、認証機能があるとしましょう:
//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 ...)に関係なく、まったく同じエクスプロイトが機能する可能性もあります。
(免責事項:このハッキング手法については、「ハッキング:悪用の芸術」で読んだと思います)
それが逆の方法です。スタックバッファをオーバーフローさせます(そのように)関数が戻るときにEIPがロードされるフィールドを上書きします。
通常のアーキテクチャでは、スタックは下向きに成長するため、関数が呼び出されたときにスタックにプッシュされた「戻りアドレス」は数バイトafterローカル変数です。ローカルバッファをオーバーフローさせることにより、RAM内の後にあるもの、つまり戻りアドレスを上書きすることができます。関数が戻ると、対応するret
オペコードが戻りアドレスをEIPにロードします。これは、実行がそのアドレスにジャンプすることを意味します。