35

バッファオーバーフローを使用して、関数を明示的に呼び出さずに呼び出すように求める宿題を受け取りました。コードは基本的に次のとおりです。

#include <stdio.h>
#include <stdlib.h>

void g()
{
    printf("now inside g()!\n");
}


void f()
{   
    printf("now inside f()!\n");
    // can only modify this section
    // cant call g(), maybe use g (pointer to function)
}

int main (int argc, char *argv[])
{
    f();
    return 0;
}

どのように進めればよいかわかりませんが。プログラムカウンタのリターンアドレスをg()のアドレスに直行するように変更しようと思ったのですが、アクセス方法がわかりません。とにかく、ヒントは素晴らしいでしょう。

4

5 に答える 5

14

基本的な考え方は、関数の戻りアドレスを変更して、関数が戻ったときにハッキングされた新しいアドレスで実行を継続することです。回答の1つでNilsが行ったように、メモリの一部(通常は配列)を宣言し、リターンアドレスも上書きされるようにオーバーフローさせることができます。

実際にどのように機能するかを理解せずに、ここに記載されているプログラムを盲目的に使用しないことをお勧めします。この記事は非常によく書かれており、非常に役立つことがわかります。

バッファ オーバーフローの脆弱性に関するステップバイステップ

于 2010-02-25T12:53:11.960 に答える
12

これはコンパイラに依存するため、単一の答えを与えることはできません。

次のコードは、gcc 4.4.1 で必要なことを行います。最適化を無効にしてコンパイルする (重要!)

#include <stdio.h>
#include <stdlib.h>

void g()
{
    printf("now inside g()!\n");
}


void f()
{   
  int i;
  void * buffer[1];
  printf("now inside f()!\n");

  // can only modify this section
  // cant call g(), maybe use g (pointer to function)

  // place the address of g all over the stack:
  for (i=0; i<10; i++)
     buffer[i] = (void*) g;

  // and goodbye..
}

int main (int argc, char *argv[])
{
    f();
    return 0;
}

出力:

nils@doofnase:~$ gcc overflow.c
nils@doofnase:~$ ./a.out
now inside f()!
now inside g()!
now inside g()!
now inside g()!
now inside g()!
now inside g()!
now inside g()!
Segmentation fault
于 2010-02-25T12:39:06.640 に答える
8

これは宿題なので、バッファ オーバーフローが実際にどのように機能するかを理解するという codeaddict の提案を繰り返したいと思います。

私は、バッファオーバーフローの脆弱性を悪用することに関する優れた (少し古い場合) 記事/チュートリアルを読んでテクニックを学びましたSmashing The Stack For Fun And Profit

于 2010-02-25T15:07:31.770 に答える
4

これを試してください:

void f()
{   
    void *x[1];
    printf("now inside f()!\n");
    // can only modify this section
    // cant call g(), maybe use g (pointer to function)
    x[-1]=&g;
}

またはこれ:

void f()
{   
    void *x[1];
    printf("now inside f()!\n");
    // can only modify this section
    // cant call g(), maybe use g (pointer to function)
    x[1]=&g;
}
于 2010-02-25T12:30:12.543 に答える
4

このソリューションでは、オーバーフロー手法を使用してスタック上の関数の戻りアドレスを上書きしませんが、直接呼び出さずに変更するだけで、に戻る途中でg()呼び出される原因になります。f()main()f()g()

関数エピローグのようなインライン アセンブリを追加しf()て、スタック上のリターン アドレスの値を変更し、 をf()介してリターンするようにしg()ます。

#include <stdio.h>

void g()
{
    printf("now inside g()!\n");
}

void f()
{   
    printf("now inside f()!\n");
    // can only modify this section
    // cant call g(), maybe use g (pointer to function)

    /* x86 function epilogue-like inline assembly */
    /* Causes f() to return to g() on its way back to main() */
    asm(
        "mov %%ebp,%%esp;"
        "pop %%ebp;"
        "push %0;"
        "ret"
        : /* no output registers */
        : "r" (&g)
        : "%ebp", "%esp"
       );
}

int main (int argc, char *argv[])
{
    f();
    return 0;
}

このコードがどのように機能するかを理解すると、関数のスタック フレームが特定のアーキテクチャでどのようにセットアップされ、バッファ オーバーフロー手法の基礎を形成するかについての理解が深まります。

于 2010-06-18T20:42:35.850 に答える