
Windows x86 PoC: стековое переполнение буфера с пользовательским шеллкодом на устаревшей 32-битной Windows.
Это простой, самодостаточный учебник по эксплойтам переполнения буфера на стеке для 32-битных Windows. Внешние руководства не требуются — всё необходимое находится здесь.
vulnerable.c: Простая программа с небезопасной функцией gets().messageBox.asm: Небольшая ассемблерная полезная нагрузка, которая выполняется после переполнения.exploit.c: Пример того, как может быть вызвано переполнение.Этот проект учит одной основной идее: небезопасное чтение ввода может позволить злоумышленнику перезаписать адрес возврата и перенаправить выполнение.
gets() не имеет ограничения по размеруВ vulnerable.c программа делает следующее:
char buffer[32];
gets(buffer);
Программа резервирует 32 байта для buffer, а затем вызывает gets() для чтения ввода.
Проблема: gets() не проверяет размер буфера.
Он продолжает читать символы, пока не встретит символ новой строки.
Если пользователь вводит 40 или 50 символов, лишние символы переполняют 32-байтовый буфер.
Когда выполняется функция на C, стек (область памяти) хранит:
buffer)EBP (базовый указатель вызывающей функции)Выглядит это так:
Lower addresses (top of stack as drawn)
[ buffer (32 bytes) ]
[ saved EBP (4 bytes) ]
[ return address (4 bytes) ]
Higher addresses (bottom)
Когда gets() переполняет buffer слишком большим вводом, лишние байты перезаписывают сохранённый EBP, а затем и адрес возврата.
Если аккуратно сформировать переполнение так, чтобы в поле адреса возврата оказался конкретный адрес, процессор перейдёт по этому адресу, когда функция попытается вернуться.
buffer[32] на стеке.gets(buffer) для чтения строки пользовательского ввода.gets() не проверяет размер, поэтому записывает все 50 байт в буфер.buffer и перезаписывают сохранённый EBP и адрес возврата.Это простейшая форма выполнения кода через переполнение буфера.
messageBox.asm — это небольшой фрагмент кода, предназначенный для выполнения после переполнения.
Он делает следующее:
LoadLibraryA со строкой "USER32.DLL", чтобы гарантировать, что библиотека находится в памяти.ExitProcess для безопасного завершения программы.Ключевой момент: это исполняемый код, который запускается после того, как переполнение перенаправляет выполнение на него. Когда на экране появляется окно сообщения, это доказывает три вещи:
В реальной атаке эта полезная нагрузка могла бы делать что угодно: красть данные, создавать пользователя, загружать вредоносное ПО и т.д. Окно сообщения — это просто видимый, безопасный способ показать, что произошло выполнение произвольного кода.
Эта конкретная полезная нагрузка использует жёстко заданные адреса памяти для MessageBoxA (0x751D8830) и ExitProcess (0x7437ADB0).
Эти адреса специфичны для одной системы. Полезная нагрузка потребует корректировки для другой версии Windows или системы.

Современные Windows имеют несколько функций безопасности, которые предотвращают этот эксплойт:
Для этого учебного примера мы отключаем их все.
Используйте MSVC (Microsoft Visual C++) со специальными флагами:
cl /c /GS- /W3 /Zl vulnerable.c
link /SUBSYSTEM:CONSOLE /DYNAMICBASE:NO /NXCOMPAT:NO vulnerable.obj /OUT:vulnerable.exe
Значения флагов:
/GS- отключает защиту от переполнения буфера стека./DYNAMICBASE:NO отключает Address Space Layout Randomization (ASLR)./NXCOMPAT:NO отключает DEP, позволяя выполнять код на стеке.Если исполняемый файл уже существует, можно отключить защиту с помощью editbin:
editbin /NXCOMPAT:NO /DYNAMICBASE:NO vulnerable.exe
vulnerable.exe.В этом README объясняется:
gets() и почему он небезопасен (нет ограничения по размеру).Теперь вы понимаете весь процесс эксплойта переполнения буфера. Прочитайте файлы с кодом и сравните их с этим объяснением, чтобы закрепить понимание.
Этот пример предназначен только для обучения. Не используйте эту технику против систем, которыми вы не владеете или на тестирование которых у вас нет явного разрешения. Несанкционированный доступ к компьютерным системам незаконен.