Упражнение на переполнение буфера в c

Я изучаю кибербезопасность и выполнял упражнение, в котором мне нужно было получить доступ к функции 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

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

Eric Postpischil 18.04.2024 22:34

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

cucaracha 18.04.2024 22:39

большое спасибо за советы! А еще я не отключал ASLR.

cucaracha 18.04.2024 22:48

Обратите внимание, что gets() больше 12 лет не является частью стандартной библиотеки C.

chux - Reinstate Monica 18.04.2024 22:54

Это упражнение для практики

cucaracha 18.04.2024 22:56

@chux-ReinstateMonica Потому что он допускает переполнение буфера. Это именно то, чего хочет ОП.

Barmar 18.04.2024 22:57

Я предполагаю, что вы должны переполнить data.name в get_user_info, чтобы адрес возврата функции get_user_info изменился на адрес функции vip_queue. Однако большинство современных операционных систем используют ASLR, из-за чего этот эксплойт, вероятно, не сработает. Поскольку вы заявили, что не отключили ASLR, ваш вопрос для меня не имеет смысла, если только ASLR не отключен и вы об этом не знаете.

Andreas Wenzel 19.04.2024 00:03

Когда вы запускаете программу в отладчике, какой у нее адрес data.name? А по какому адресу хранится обратный адрес функции get_user_info? Если разница между обоими адресами не составляет ровно 36 байт, то я считаю, что опубликованные вами эксплойты не сработают.

Andreas Wenzel 19.04.2024 00:24

Вероятно, также необходимо отключить любую защиту стека (например, -fno-stack-protector)

LHLaurini 19.04.2024 00:30

это адрес памяти data.name: 0x7ffffffdce0 и обратный адрес get_user_info: 0x0000000000401272. Я думал, что байты рассчитываются по размеру каждой переменной, я только начал изучать, как работают буферы, извините, если я ошибаюсь.

cucaracha 19.04.2024 00:45

@LHLaurini да! это именно то, что я сделал здесь: gcc -no-pie -fno-stack-protector nice_forums.c -o nice_forums, но до сих пор не знаю, почему это не работает

cucaracha 19.04.2024 00:46

Пожалуйста, добавьте эту команду в вопрос.

LHLaurini 19.04.2024 00:50

@cucaracha: Я тебя спрашивал "at what address is the return address [...] stored?". Итак, я спрашивал у вас адрес обратного адреса в стеке. Кажется, вместо этого вы сообщили мне значение обратного адреса. Я не об этом просил. Вы сможете увидеть структуру памяти, запустив программу в отладчике.

Andreas Wenzel 19.04.2024 02:03

Когда я тестирую ваш код в онлайн-отладчике www.onlinegdb.com, устанавливаю точку останова в начале функции get_user_info, а затем использую команду GDB x/16ag &data для проверки памяти в стеке, я обнаруживаю, что между адресом data и адресом www.onlinegdb.com находится 56 байтов. адрес обратного адреса. Ваше решение, похоже, предполагает, что существует разница в 36 байт, что, по моему мнению, будет правдоподобно только на 32-битной платформе (из-за выравнивания) и когда указатель кадра не используется.

Andreas Wenzel 19.04.2024 02:42

@Barmar Вместо устаревшего gets(), сегодняшний эксплойт может использовать scanf("%s", ...) или scanf("%[^\n]", ...), которые все еще действительны в C. ИМХО, эксплойт gets() отражает старые планы уроков и не очень энергичных преподавателей, которые практически не пытаются оставаться в курсе событий.

chux - Reinstate Monica 19.04.2024 05:14

@chux-ReinstateMonica Правда. Вы также можете использовать fgets() с размером > размером буфера. Интересно, что когда они объявили устаревшими/удалили gets(), они ничего не сделали с другими конструкциями, которые столь же опасны и распространены.

Barmar 19.04.2024 17:15
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
16
125
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы идете в правильном направлении, но делаете неверные предположения о местонахождении обратного адреса. Мы можем взглянуть на дизассемблированную функцию, используя 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?

  1. В стек помещается регистр rbp — 8 байт;
  2. sizeof(user_data) == 36 — итак еще 36 байт;
  3. AFAIK, ABI x86-64 требует, чтобы указатель стека был выровнен по 16 байтам (кратно 16), поэтому 36 байтов становятся 48.

8 + 48 = 56.

ох, понятно, я не знал о 20 дополнительных байтах. Как вы пришли к такому выводу? И почему 56 байт?

cucaracha 19.04.2024 14:32

Другие вопросы по теме