2010-02-25 2 views
29

У меня есть задание на домашнее задание с просьбой вызвать функцию без явного вызова ее, используя переполнение буфера. Код в основном такой:Как я могу вызвать переполнение буфера?

#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(), но я не уверен, как получить к нему доступ. Во всяком случае, подсказки будут замечательными.

+9

4 upvotes для домашнего задания! ОП даже не придумал вопрос ... вау, некоторые люди легко впечатлены. – Lazarus

+0

@ Lazarus, я поддержал ваш комментарий. О, о!:-) –

+15

@ Lazarus тот факт, что это вопрос домашней работы, не имеет ничего общего с тем фактом, что я нахожу это интересным. Я также поддержал это, потому что хочу поощрять интересные домашние задания, а не просто «Я закрыл буфер файлов, и теперь, когда я пытаюсь читать из файла, он не работает. Почему?» (Другими словами, я выдвигаю вопросы, на которые я не знаю ответа, но хочу) – Yacoby

ответ

14

Основная идея заключается в том, чтобы изменить обратный адрес функции, так что, когда функция возвращает это продолжает выполняться на новом взломанный адрес. Как это сделал Нилс в одном из ответов, вы можете объявить кусок памяти (обычно массив) и переполнить его таким образом, чтобы и обратный адрес был перезаписан.

Я предлагаю вам не слепо принимать любые из приведенных здесь программ, не понимая, как они работают. Эта статья очень хорошо написана, и вы найдете его очень полезным:

A step-by-step on the buffer overflow vulnerablity

3

Попробуйте это:

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; 
} 
+3

Объяснение было бы здорово, потому что это домашнее задание. –

+2

x - локальная переменная, поэтому она находится в стеке. Поскольку x является массивом размера 1, действителен только x [0]. Написав адрес g в x [-1] или x [1], есть вероятность, что мы перезапишем обратный адрес. Это зависит от организации стека, какая версия работает. –

11

Это зависит компилятор, так что ни один ответ не может быть дан.

Следующий код сделает то, что вы хотите для 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; 
} 

Output (важно!):

[email protected]:~$ gcc overflow.c 
[email protected]:~$ ./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 
+0

Я использую gcc 4.4.1 и не знаю, как отключить оптимизацию: попробовал gcc -O0 -o buff buff.c (это о-ноль) , а также gcc -O1 -fno-defer-pop - fno-thread-jumps -fno-branch-probabilities -fno-cprop-registers -fno-guess-branch-chance -fno-omit-frame-pointer -o buff buff.c не работает. – sa125

+1

Заставьте приложение выйти из функции «g()», чтобы избежать ошибки сегментации =) – Kieveli

+0

sa125, может быть, gcc пытается оптимизировать другую архитектуру процессора. Насколько я знаю, он по умолчанию относится к процессору системы, в которой вы работаете. Это может изменить то, как выглядит стековый фрейм f() и может предотвратить переполнение. –

7

Поскольку это домашнее задание, я хотел бы повторить codeaddict's suggestion понять, как на самом деле работает переполнение буфера.

Я изучил технику, прочитав отличную (если немного устаревшую) статью/учебник об использовании уязвимостей переполнения буфера Smashing The Stack For Fun And Profit.

+2

+1 для ссылки на эту статью. –

3

Хотя это решение не использует технику переполнения перезаписать обратный адрес функции в стеке, он по-прежнему вызывает g() получить колл от f() на обратном пути к main() лишь модификации f() и не вызывая g() непосредственно.

Function epilogue -как рядный узел добавляется в 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; 
}

Понимание того, как этот код работает, может привести к лучшему пониманию того, как кадр стеки функции, является установкой для конкретной архитектуры, которая лежит в основе методов переполнения буфера.

Смежные вопросы