Как я могу вызвать переполнение буфера?
У меня было задание домашней работы, предлагающее мне вызвать функцию без явного вызова ее, используя переполнение буфера. Код в основном таков:
#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(), но я не уверен, как получить к нему доступ. Во всяком случае, советы будут отличными.
Ответы
Ответ 1
Основная идея состоит в том, чтобы изменить адрес возврата функции, чтобы при возврате функции продолжает выполняться на новом взломанном адресе. Как это сделал Нилс в одном из ответов, вы можете объявить кусок памяти (обычно массив) и переполнить его таким образом, чтобы и обратный адрес был перезаписан.
Я предлагаю вам не слепо принимать какие-либо из приведенных здесь программ, не понимая, как они работают. Эта статья очень хорошо написана, и вы найдете ее очень полезной:
Шаг за шагом по уязвимости переполнения буфера
Ответ 2
Это зависит от компилятора, поэтому нет однозначного ответа.
Следующий код сделает то, что вы хотите для 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;
}
Вывод:
[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
Ответ 3
Так как это домашнее задание, я хотел бы эхо предложение codeaddict понять, как работает переполнение буфера.
Я изучил технику, прочитав отличную (если немного устаревшую) статью/урок об использовании уязвимостей переполнения буфера Smashing The Stack For Fun And Прибыль.
Ответ 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;
}
Ответ 5
В то время как это решение не использует метод переполнения для перезаписывания адреса возврата функции в стеке, оно все равно вызывает g()
для вызова из f()
на обратном пути к main()
путем изменения f()
и не вызывая непосредственно g()
.
Функция 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;
}
Понимание того, как работает этот код, может привести к лучшему пониманию того, как устанавливается фрейм стека функций для конкретной архитектуры, которая составляет основу методов переполнения буфера.