web-dev-qa-db-ja.com

メイン関数の戻りアドレスの上書き

私はCTFを初めて使い、これを解決するように求められました。

#include <cstdio>

// g++ pwn2.cpp -o pwn2 -static

void ilocamp() {
     char flaga[1024] = {0};
     FILE *f = fopen("flag2.txt", "r");
     fread(flaga, 1, 1024, f);
     fclose(f);
     printf("flaga: ILOCAMP{%s}\n", flaga);
}


int main() {

     int tab[100] = {0};
     int dwa = 2;
     int n,i,min,x;

     scanf("%d",&n);
     for (i=0;i<n;i++) {
        scanf("%d", &x);
        scanf("%d", &tab[x]);
     }

     min = 1000000000;
     for (i=0;i<n;i++) {
        if (tab[i] && tab[i] < min) {
           min = tab[i];
        }
     }

     printf("najmniejsza liczba: %d a dwa wynosi: %d\n", min, dwa);
}

ポイントは、メイン関数の戻りアドレスをilocamp()エントリアドレスで上書きすることであり、これを行うには、ループ内でその単純な脆弱性を使用することになっていますが、これを行う方法がわかりません。私はバイナリも持っていますが、gdbで何かをしようとしましたが、どうすればよいかわかりません。ヒントをください。バイナリがあります: http://www48.zippyshare.com/v/b7OaWQeW/file.html (ファイル "flag2.txt"はローカルサーバーにあります)

1
nullifier

時間がないので、今のところ大まかな説明です。 一般的な考え方は、ターゲット関数のアドレスと、スタック上の戻りアドレスの正確な位置を決定することです。

差出人住所を上書きする場合は、最初に正しい位置を見つける必要があります。これを行うには、おそらくプログラムをデバッグし、ブレークポイントをメイン関数の可能な最後のステップに設定し、そこから単一の命令をステップ実行することによってレジスターが変化するのを観察します。簡単なヒント:プログラムを開いた後、起動するたびに1バイト長い文字列をプログラムに挿入すると、ある時点でプログラムがクラッシュするのを確認できます。スタックカナリアまたはシャドウスタックがないか、ターゲットアドレスが見つかったと仮定します。あなたは(デバッグしながら)例えばたくさんの 'A'を供給し、デバッガーで0x41を監視します。

次に、ターゲット関数のアドレスを決定します。かなり簡単です。たとえば、次のことができます。 info symbolinfo address。その後、RIP(Return Instruction Pointer)のアドレスに到達するまで、スタックにゴミ(例:「A」)を書き込んでから、必要な新しいアドレスを書き込みます。

また、EIP/RIPやウィキペディアなどのスタックオーバーフローについても少し読んでください。

1
Ben