#c #buffer-overflow
#c #переполнение буфера
Вопрос:
Я начинаю возиться с переполнением буфера и написал следующую программу:
#include <unistd.h>
void g() {
execve("/bin/sh", NULL, NULL);
}
void f() {
long *return_address;
char instructions[] = "xb8x01x00x00x00xcdx80"; // exit(1)
return_address = (long*) (amp;return_address 2);
*return_address = (long)amp;g; // or (long)instructions
}
int main() {
f();
}
Он делает то, что я ожидаю от него: return_address
перезаписывает обратный адрес f
с адресом g
, который открывает оболочку. Однако, если я установлю адрес возврата instructions
равным, я получу ошибку сегментации, и ни одна из инструкций instructions
не будет выполнена.
Я компилирую с помощью GCC, используя -fno-stack-protector
.
Как я мог предотвратить возникновение этой ошибки сегментации?
Комментарии:
1. Не эксперт, но может быть,
instructions
это сохраняется в сегменте данных и, следовательно, отключает предотвращение выполнения данных (или его название в Linux), и поэтому программа завершается? Если я правильно понимаю, это не то же самое, что переполнение стека, и оно не отключается-fno-stack-protector
. Но я совсем не уверен!2. @FabioTurati
instructions
хранится в стеке, я проверил с помощью GDB
Ответ №1:
По крайней мере, одна проблема не связана с переполнением буфера.
execve("/bin/sh", NULL, NULL);
Этот первый NULL становится argv процесса, который вы запускаете. argv должен быть массивом строк, который заканчивается НУЛЕМ. Таким образом, segfault может произойти при /bin/sh
запуске, попытке чтения argv[0]
и разыменовании NULL.
void g(void) {
char *argv[] = { "/bin/sh", NULL };
execve(argv[0], argv, NULL);
}
Вы также можете добавить -z execstack
в командную строку gcc, которая сообщит компоновщику разрешить исполняемый стек. Вы также должны убедиться, что имеющиеся у вас инструкции exit(1)
соответствуют тем, которые компилируются в вашей системе, если вы получили их из какого-то руководства.