# PWN

## Эксплуатация race conditions

Race condition — это когда результат программы зависит от того, в каком порядке или с какой скоростью выполняются несколько потоков/процессов/операций, и ты можешь специально «вклиниться» между ними, чтобы изменить поведение.\
В CTF эта тема относится в первую очередь к категориям **Pwn**, **Kernel** и иногда **Web/Misc**.\
Чаще всего race conditions встречаются в задачах с многопоточными бинарниками, сетевыми сервисами, файловыми операциями и особенно в kernel-эксплойтах (pwnable kernel модули).\
Новичку важно хотя бы понимать, что это такое, потому что race condition — один из немногих способов обойти защиты, которые кажутся «неуязвимыми» в однопоточном коде.\
Когда ты научишься видеть места, где между проверкой и использованием есть окно — сможешь решать задачи, которые большинство участников пропускают как «невозможные».

### Словарь терминов

| Термин          | Что это простыми словами                                            |
| --------------- | ------------------------------------------------------------------- |
| race condition  | Состояние гонки — когда порядок выполнения потоков меняет результат |
| многопоточность | Когда программа одновременно выполняет несколько потоков            |
| mutex           | Замок, который позволяет только одному потоку работать с данными    |
| TOCTOU          | Time-of-check to time-of-use — проверка, а потом использование      |
| symlink race    | Гонка при работе с символическими ссылками на файлы                 |
| file descriptor | Число, которым программа обращается к открытому файлу/сокету        |
| double-fetch    | Дважды чтение данных из пользовательского пространства в kernel     |
| kernel race     | Гонка внутри ядра операционной системы                              |
| thread          | Отдельный поток выполнения внутри процесса                          |
| atomic          | Операция, которая выполняется целиком и не может быть прервана      |
| spinlock        | Очень быстрый замок, который просто крутится в цикле                |

### Race condition в многопоточных программах

Многопоточная программа запускает несколько потоков одновременно.\
Если два потока работают с одной и той же переменной/структурой без защиты (mutex, lock) — один поток может изменить данные в тот момент, когда второй их читает или использует.

Классические паттерны в CTF:

* два потока: один проверяет «достаточно ли денег», второй снимает деньги → можно снять больше, чем есть
* один поток выделяет память, другой её освобождает → use-after-free или double-free
* гонка при установке/сбросе флага «админ» или «успех»

В CTF многопоточные race чаще всего эксплуатируют через многократные параллельные подключения к серверу или запуск множества потоков в скрипте.

### TOCTOU (Time-of-check to time-of-use)

TOCTOU — это когда программа сначала проверяет условие (check), а потом использует результат (use), и между этими двумя шагами проходит время.

Примеры:

* проверка, существует ли файл и принадлежит ли он пользователю → потом открытие файла → за это время кто-то может подменить файл
* проверка длины строки → потом копирование строки → за это время другой поток может изменить длину

В CTF TOCTOU чаще всего встречается в файловых операциях и в kernel-модулях (проверка указателя из userspace, потом использование).

Эксплуатация простая: многократно повторять операцию в цикле, пока гонка не сработает (race win).

### File descriptor race, symlink race

**File descriptor race**\
Программа открывает файл по пути, получает file descriptor (fd), потом использует этот fd.\
Между open и использованием fd другой процесс может подменить файл по этому пути.

**Symlink race**\
Программа проверяет файл по пути /tmp/secret → потом открывает его.\
За время между проверкой и открытием ты создаёшь символическую ссылку, которая указывает на настоящий флаг.

Типичная эксплуатация в CTF:

* многократно создавать/удалять symlink в /tmp
* параллельно запускать уязвимую программу много раз
* ждать, пока она откроет не тот файл

Это классика в задачах с setuid-байнарями или временными файлами.

### Kernel race и double-fetch bugs

В kernel-модулях race condition встречается, когда syscall читает данные из userspace дважды.

**Double-fetch bug**\
Kernel дважды копирует структуру из userspace:

1. первый раз — проверяет размер/права
2. второй раз — использует данные\
   Между этими копированиями пользователь может изменить память → kernel использует другие данные, чем проверил.

Примеры:

* первый fetch — размер буфера маленький → проверка проходит
* второй fetch — размер буфера огромный → копируется слишком много → heap overflow в kernel

В CTF kernel race часто эксплуатируют через многократные вызовы ioctl или syscall в разных потоках, чтобы попасть в нужное окно времени.

### Итог

Главное, что нужно запомнить: race condition возникает всегда, когда между проверкой и использованием или между двумя операциями есть окно, и несколько потоков/процессов могут вмешаться именно в это окно.

Ключевые слова и термины для запоминания:\
race condition, многопоточность, TOCTOU, symlink race, file descriptor race, double-fetch, kernel race, mutex, atomic.

Эти знания помогают:

* увидеть в коде места вида «if (check()) { use(); }» и понять, что это потенциальная гонка
* запускать несколько потоков/подключений параллельно, чтобы увеличить шанс выиграть race
* эксплуатировать symlink race для чтения флага через временные файлы
* понять double-fetch в kernel-модулях и подменять данные между двумя копированиями
* комбинировать race с другими уязвимостями (UAF, overflow) для повышения шансов

Начни замечать в коде проверки перед использованием — и многие «странные» задачи перестанут казаться магией, а станут просто гонками, которые нужно выиграть многократными попытками.

***

## Эксплуатация use-after-free

Use-after-free (UAF) — это когда программа после освобождения памяти (free/delete) продолжает использовать указатель на уже освобождённый кусок.\
В CTF эта тема относится в первую очередь к категории **Pwn** (бинарная эксплуатация, heap exploitation).\
Чаще всего встречается в задачах medium–hard уровня, где дают C/C++ программу с динамической памятью (new/delete, malloc/free) или JavaScript-движок в браузерных задачах.\
Новичку важно её понять, потому что UAF — один из самых мощных и частых примитивов для получения произвольного чтения/записи и выполнения кода, особенно когда классические переполнения закрыты.\
Когда освоишь базовые сценарии UAF и vtable hijacking — сможешь решать многие heap-задачи, которые на первый взгляд кажутся слишком сложными.

### Словарь терминов

| Термин            | Что это простыми словами                                        |
| ----------------- | --------------------------------------------------------------- |
| use-after-free    | Использование указателя после того, как память уже освобождена  |
| UAF               | Коротко от use-after-free                                       |
| dangling pointer  | Указатель, который смотрит на уже освобождённую память          |
| vtable            | Таблица виртуальных функций объекта в C++                       |
| vtable hijacking  | Подмена адреса vtable на свою фейковую таблицу                  |
| fake vtable       | Поддельная таблица виртуальных функций, которую мы контролируем |
| double-free       | Дважды освободить один и тот же кусок памяти                    |
| tcache            | Кэш маленьких освобождённых блоков в современной glibc          |
| freed chunk       | Блок памяти, который уже отдали free, но ещё не переиспользован |
| realloc           | Функция, которая может перевыделить память на том же адресе     |
| JavaScript engine | Движок, который выполняет JS-код в браузере (V8, SpiderMonkey)  |

### UAF в C/C++ программах

В C/C++ программе выделяется память через new или malloc, потом на неё ставится указатель.\
Если вызвать delete/free, память возвращается в кучу, но указатель остаётся тем же (dangling pointer).\
Если дальше через этот указатель читать или писать — программа может работать с уже переиспользованной памятью.

Типичные сценарии в CTF:

* после free вызывается метод объекта → если память занял другой объект, можно вызвать чужие методы
* после free пишут в структуру → можно подменить указатели внутри
* после free читают → можно увидеть данные другого объекта (leak)

Самый частый паттерн:

1. new объект
2. free объект
3. new другой объект на то же место
4. через старый указатель пишем/читаем в новый объект

В CTF UAF в C/C++ почти всегда сочетается с контролем над выделяемыми объектами (размер, содержимое).

### Vtable hijacking, fake vtable

В C++ почти все классы с виртуальными функциями имеют vtable — таблицу указателей на методы.\
Первый 8-байтный член объекта — это указатель на vtable.\
Если через UAF перезаписать этот указатель на свою фейковую vtable — при следующем вызове виртуального метода программа прыгнет на наш адрес.

Как это делают:

* выделяют объект класса A
* free объект
* выделяют буфер того же размера и заполняют его фейковой vtable (адреса гаджетов или one\_gadget)
* через dangling pointer вызывают виртуальный метод → прыжок на наш код

В CTF vtable hijacking — один из самых надёжных способов получить RIP-контроль (управление потоком выполнения) в C++ heap-задачах.

### Use-after-free в браузерах и JavaScript engines

В браузерных задачах (чаще всего V8 — движок Chrome) UAF возникает, когда JS-объект освобождается, но ссылка на него остаётся в коде.\
Самые частые места:

* ArrayBuffer / TypedArray после detach
* объекты после delete в WeakMap / WeakSet
* объекты после GC (garbage collection), но с сохранённой ссылкой

Типичная цепочка:

1. Создаём объект
2. Делаем так, чтобы он освободился (например через optimization / deoptimization)
3. Выделяем на его место контролируемый объект (ArrayBuffer)
4. Через старую ссылку читаем/пишем в новый объект → leak / arbitrary read/write

В CTF браузерные UAF часто дают arbitrary read/write примитив, а дальше уже переписывают vtable или JIT-код.

### UAF с double-free комбинацией

Double-free + UAF — очень мощная комбинация.\
Сначала дважды free один chunk → он попадает в tcache дважды.\
Потом через UAF используем dangling pointer для чтения/записи, пока chunk ещё не переиспользован.

Типичные сценарии:

* double-free → tcache poisoning → UAF на старом указателе → пишем в \_\_free\_hook или GOT
* UAF → читаем fd из tcache → double-free → poisoning на другой адрес

В CTF эта комбинация встречается в задачах, где дают delete + free или несколько new/delete в цикле.

### Итог

Главное, что нужно запомнить: use-after-free — это когда указатель остаётся после free, и ты можешь читать/писать в память, которая уже отдана обратно в кучу и, скорее всего, переиспользована.

Ключевые слова и термины для запоминания:\
use-after-free, UAF, dangling pointer, vtable hijacking, fake vtable, double-free, tcache, freed chunk, JavaScript engine, realloc.

Эти знания помогают:

* получить контроль над виртуальной функцией через подмену vtable в C++
* слить адреса libc или кучи через чтение после UAF
* комбинировать double-free с UAF для tcache poisoning и arbitrary alloc
* понять, почему в задаче дают delete, а потом снова используют объект
* эксплуатировать браузерные UAF для arbitrary read/write примитивов

Начни с простых C++ UAF + vtable hijacking — это решает большинство классических heap-задач на delete/new. Дальше добавляй double-free и браузерные сценарии, когда обычные способы не работают.

***

## Форматные строки

Форматные строки — это когда программа использует printf-подобные функции неправильно: вместо printf("строка") вызывают printf(пользовательский\_ввод), и тогда ты можешь через свою строку управлять тем, что программа читает или пишет в память.\
В CTF эта тема относится в первую очередь к категории **Pwn** (бинарная эксплуатация).\
Чаще всего встречается в задачах, где дают программу с уязвимым printf, sprintf или fprintf, и нужно либо слить важные адреса, либо переписать что-то в памяти (GOT, return address), чтобы получить shell или прочитать флаг.\
Новичку это одна из самых полезных тем после stack overflow, потому что format string даёт очень мощные примитивы: чтение и запись почти в любую память почти без ограничений.\
Когда освоишь %x, %s, %n и direct parameter access — сможешь решать почти все классические format-string задачи уровня easy–medium.

### Словарь терминов

| Термин                  | Что это простыми словами                                                           |
| ----------------------- | ---------------------------------------------------------------------------------- |
| format string           | Строка с плейсхолдерами (%s, %d, %x), которую printf читает и подставляет значения |
| %x                      | Выводит значение в шестнадцатеричном виде (обычно со стека)                        |
| %s                      | Выводит строку, начиная с адреса, который лежит на стеке                           |
| %n                      | Записывает количество уже выведенных символов в адрес на стеке                     |
| direct parameter access | Доступ к аргументу по номеру: %7$x — берёт 7-й аргумент                            |
| GOT                     | Таблица, где хранятся адреса функций из библиотек (printf, puts и т.д.)            |
| leak                    | Получение значения из памяти (адреса libc, стека, PIE) через вывод                 |
| arbitrary write         | Запись произвольного значения в произвольный адрес                                 |
| one-shot write          | Одноразовая запись через %n за один вызов printf                                   |
| PIE                     | Защита: база программы каждый раз загружается по случайному адресу                 |
| ASLR                    | Случайное расположение libc, стека, кучи при каждом запуске                        |
| stack offset            | Сколько аргументов нужно пропустить, чтобы достать до нужного значения на стеке    |

### Format string vulnerabilities (%n, %s, %x, direct parameter access)

Функция printf ожидает форматную строку и потом аргументы.\
Если передать пользовательский ввод как форматную строку — printf начнёт читать со стека всё подряд как аргументы.

Основные спецификаторы в CTF:

* %x — берёт 4 байта со стека и выводит как hex
* %s — берёт 8 байт со стека как адрес и пытается вывести строку оттуда
* %n — берёт 8 байт со стека как адрес и записывает туда количество уже выведенных символов
* %7$x — берёт именно 7-й аргумент (direct parameter access, работает почти всегда)

Пример: если ввести "%7$x %8$x %9$x" — программа выведет три значения со стека, начиная с 7-го аргумента.\
Это самый простой способ посмотреть, что лежит на стеке.

В CTF чаще всего используют %x для поиска смещения до нужного значения и %s для чтения строк по адресам.

### GOT overwrite через format string

GOT — это таблица, куда при первом вызове функции (puts, printf) записывается её настоящий адрес из libc.\
Если через %n перезаписать запись в GOT — следующий вызов этой функции прыгнет на твой адрес.

Классическая цепочка:

1. Слить адрес GOT (через %s или %x на нужном offset)
2. Посчитать, сколько символов нужно вывести, чтобы %n записал нужное значение
3. С помощью %n перезаписать GOT на адрес system или win-функции

В CTF это один из самых надёжных способов получить shell, когда нет переполнения буфера, но есть format string.

### Leak стека, libc, PIE base через format string

Format string — лучший способ слить адреса в CTF.

Что обычно сливают:

* адреса со стека (через %x или %p) — чтобы найти return address, canary, сохранённый rbp
* строки со стека или .rodata (через %s) — часто там лежит "/bin/sh"
* адреса GOT (через %s на offset до GOT) — чтобы вычислить базу libc
* базу программы (PIE) — если в GOT или на стеке лежит адрес из .text

Типичный процесс:

* выводим много %x или %p → ищем знакомые адреса (заканчиваются на 000 или содержат строки)
* считаем offset до нужного значения
* потом используем этот offset для точного %s или %n

В 90% format-string задач сначала делают leak, а уже потом write.

### One-shot write и arbitrary write

**One-shot write**\
Один вызов printf, который через %n записывает нужное значение в нужный адрес.\
Обычно используют, когда нужно переписать один байт или короткое значение (например GOT на system).

**Arbitrary write**\
Несколько вызовов printf, чтобы записать любое 8-байтное значение в любой адрес.\
Обычно комбинируют:

* %n для записи младших байт
* %hn, %hhn для записи по 2 или 1 байту
* несколько %n с разными значениями и смещениями

В CTF arbitrary write через format string — один из самых мощных примитивов: можно переписать \_\_free\_hook, \_\_malloc\_hook, GOT, даже return address на стеке.

### Итог

Главное, что нужно запомнить: format string — это когда printf читает пользовательскую строку как формат, и ты можешь читать и писать почти в любую память через %x, %s, %n и direct parameter access.

Ключевые слова и термины для запоминания:\
format string, %n, %s, %x, direct parameter access, GOT overwrite, leak, arbitrary write, one-shot write, stack offset, PIE, ASLR.

Эти знания позволяют:

* слить адрес libc и базу программы за один запрос
* прочитать флаг или строку "/bin/sh" прямо из памяти
* перезаписать GOT на system и получить shell при следующем вызове puts/printf
* сделать точную запись одного байта или слова через %hhn/%hn
* обойти ASLR и NX без переполнения буфера

Освой сначала поиск offset через %p.%p.%p..., потом leak адресов, а затем %n-запись — и большинство format-string задач превратятся в рутину. Это одна из самых сильных и элегантных техник в pwn.

***

## Heap exploitation техники

Heap exploitation — это когда ты используешь ошибки в работе с динамической памятью (malloc/free), чтобы заставить программу выделить память по твоему адресу, перезаписать важные указатели или получить контроль над выполнением кода.\
В CTF эта тема относится в первую очередь к категории **Pwn** (бинарная эксплуатация, heap exploitation).\
Чаще всего такие техники встречаются в задачах уровня medium–hard, где стековые переполнения уже закрыты защитами, а уязвимости лежат именно в malloc/free (overflow, UAF, double-free).\
Новичку это нужно изучать после базового стека и format string, потому что heap даёт самые мощные примитивы: arbitrary alloc, arbitrary write, leak libc без format string.\
Когда освоишь tcache poisoning и unsorted bin leak — сможешь решать 60–70% всех heap-задач на соревнованиях.

### Словарь терминов

| Термин                 | Что это простыми словами                                           |
| ---------------------- | ------------------------------------------------------------------ |
| chunk                  | Один блок памяти в куче (заголовок + данные)                       |
| unsorted bin           | Список недавно освобождённых больших кусков                        |
| large bin              | Список очень больших освобождённых кусков (сортировка по размеру)  |
| tcache                 | Кэш маленьких кусков (до \~1 КБ), ускоряет выделение/освобождение  |
| fastbin                | Кэш для очень маленьких кусков (до 128 байт)                       |
| tcache poisoning       | Подмена указателя в tcache, чтобы malloc вернул произвольный адрес |
| double-free            | Дважды освободить один и тот же chunk                              |
| fastbin dup            | Повторное использование одного чанка через double-free в fastbin   |
| fastbin dup into stack | Перенос fastbin на стек, чтобы контролировать return address       |
| house of spirit        | Техника использования фейкового chunk на стеке или в .bss          |
| house of force         | Атака на top chunk с переполнением размера                         |
| house of einherjar     | Техника с fake chunk и unsafe unlink в tcache                      |

### Unsorted bin attack, large bin attack

**Unsorted bin attack**\
Когда программа освобождает большой chunk → он попадает в unsorted bin.\
При следующем malloc большого размера unsorted bin сканируется → если подделать fd/bk чанка, можно записать адрес libc в произвольное место (обычно в GOT или \_\_free\_hook).

**Large bin attack**\
Large bin — отсортированный список больших кусков.\
При вставке нового чанка в large bin происходит unlink → можно подменить bk\_nextsize и fd\_nextsize, чтобы записать произвольное значение по произвольному адресу.

В CTF unsorted bin чаще всего используют для первого leak libc (fd указывает на main\_arena), а large bin — для arbitrary write после получения контроля.

### Tcache double-free и tcache poisoning

**Double-free в tcache**\
Если дважды free один chunk → он попадает в tcache дважды (tcache не проверяет дубликаты).\
При следующем malloc ты получишь тот же адрес два раза → второй раз можно подменить fd на нужный адрес.

**Tcache poisoning**\
Через UAF или double-free подменяешь fd указатель freed-чанке в tcache.\
Следующий malloc того же размера вернёт тебе произвольный адрес (GOT, \_\_free\_hook, stack, heap metadata).

Это самая популярная и простая техника в современных libc (2.26+).\
Обычно цепочка: double-free → poison fd → malloc → пишешь в \_\_free\_hook адрес one\_gadget или system.

### Fastbin dup и fastbin dup into stack

**Fastbin dup**\
Fastbin — односвязный список без проверок на размер.\
Double-free кладёт chunk дважды → следующий malloc того же размера вернёт его снова → можно подменить fd на фейковый chunk.

**Fastbin dup into stack**\
Подменяешь fd в fastbin на адрес на стеке (например перед return address).\
Malloc вернёт кусок памяти на стеке → следующий malloc позволит перезаписать return address или saved rbp.

В CTF fastbin техники используются, когда tcache отключён или заблокирован (очень старые libc или специальные патчи).

### House of spirit, house of force, house of einherjar

**House of spirit**\
Создаёшь фейковый chunk на стеке или в .bss (с правильными размерами и флагами).\
Free на указатель, который смотрит на фейковый chunk → он попадает в fastbin/unsorted → потом malloc возвращает контролируемый адрес.

**House of force**\
Переполняешь top chunk (последний кусок кучи), меняешь его размер на огромное отрицательное число.\
Следующий большой malloc думает, что top огромный → выделяет память по любому адресу (arbitrary alloc).

**House of einherjar**\
Комбинация fake chunk + unsafe unlink в tcache.\
Создаёшь фейковый chunk, free на него → он попадает в tcache → poisoning + unlink позволяет записать по произвольному адресу.

Эти house-техники встречаются в hard-задачах, когда обычные tcache/fastbin заблокированы, и нужно обходить проверки glibc.

### Итог

Главное, что нужно запомнить: куча — это связанные списки (tcache, fastbin, unsorted, large), и почти все атаки сводятся к подмене указателей fd/bk в этих списках, чтобы malloc вернул нужный адрес или произошла запись при unlink.

Ключевые слова и термины для запоминания:\
tcache poisoning, double-free, unsorted bin attack, large bin attack, fastbin dup, house of spirit, house of force, house of einherjar, chunk, top chunk, fastbin, unsorted bin.

Эти знания помогают:

* отравить tcache и получить malloc на GOT или \_\_free\_hook
* слить libc base через unsorted bin fd
* перезаписать return address через fastbin dup into stack
* обойти проверки tcache с помощью house-техник
* понять, почему в задаче дают несколько malloc/free подряд и UAF

Начни с tcache poisoning и unsorted bin leak — это решает большинство heap-задач. House-техники оставь на потом, когда обычные способы не работают.

***

## Инструменты для pwn задач

Инструменты для pwn — это специальные программы и библиотеки, которые сильно ускоряют написание эксплойтов, отладку бинарников, поиск гаджетов и анализ защит.\
В CTF эта тема относится в первую очередь к категории **Pwn** (бинарная эксплуатация).\
Они используются практически в каждой pwn-задаче: от простого ret2win до сложных heap-атак и kernel-эксплойтов.\
Новичку важно знать хотя бы основные из них, потому что без правильных инструментов ты будешь тратить часы там, где можно уложиться в 10 минут.\
Когда освоишь pwntools, gdb с плагинами и libc-database — скорость решения задач вырастет в разы, а количество ошибок упадёт.

### Словарь терминов

| Термин        | Что это простыми словами                                          |
| ------------- | ----------------------------------------------------------------- |
| pwntools      | Библиотека на Python для быстрого написания эксплойтов            |
| gdb           | Отладчик, который показывает, что происходит внутри программы     |
| gef           | Плагин к gdb, который делает отладку намного удобнее              |
| pwndbg        | Ещё один мощный плагин к gdb для pwn-задач                        |
| ROPgadget     | Программа, которая ищет гаджеты (кусочки кода с ret) в бинарнике  |
| one\_gadget   | Готовый адрес в libc, который сразу даёт shell                    |
| libc-database | База, где можно найти версию libc по её утечке                    |
| checksec      | Утилита, которая показывает, какие защиты включены в бинарнике    |
| patchelf      | Программа для изменения заголовков ELF-файла (например NX)        |
| seccomp       | Фильтр системных вызовов, который ограничивает, что можно вызвать |
| exploit       | Готовый скрипт/программа, которая использует уязвимость           |
| gadget        | Короткий кусок кода, заканчивающийся ret                          |

### pwntools (Python framework для эксплойтов)

pwntools — это главная библиотека для pwn на Python.\
Она умеет почти всё, что нужно для написания эксплойтов: подключаться к удалённому серверу, отправлять и получать данные, упаковывать/распаковывать адреса, генерировать циклические паттерны, работать с ROP.

Основные возможности:

* remote('host', port) — подключение к серверу
* p64(addr), u64(bytes) — упаковка/распаковка 64-битных адресов (little-endian)
* cyclic(200) — генерирует уникальную строку для поиска offset
* flat(\[junk, pop\_rdi, addr]) — удобная сборка ROP-цепочки
* interactive() — переключает в ручной режим после отправки payload

В CTF pwntools используют в 90% всех pwn-задач.\
Без него писать эксплойты на чистом socket — это очень долго и с кучей ошибок.

### gdb, gef, pwndbg, pwndbg++ для отладки

gdb — это классический отладчик для Linux.\
Сам по себе он не очень удобный, поэтому ставят плагины.

**gef** и **pwndbg** — два самых популярных плагина для pwn.\
Они добавляют:

* красивый вывод стека, регистров, кучи
* команды heap, vmmap, telescope, checksec
* подсветку ROP-гаджетов
* автоматический поиск offset до return address

**pwndbg++** — более новый вариант pwndbg с улучшенным интерфейсом.

В CTF отладка нужна почти всегда: понять, где краш, посчитать точный offset, посмотреть, что лежит на стеке после переполнения.

### ROPgadget, Ropper, one\_gadget, libc-database

**ROPgadget / Ropper** — ищут гаджеты в бинарнике и libc (pop rdi; ret, mov rax, rbx; ret и т.д.).\
Очень нужны, когда собираешь ROP-цепочку.

**one\_gadget** — база адресов в разных версиях libc, где один гаджет сразу вызывает execve("/bin/sh", NULL, NULL).\
Если знаешь базу libc — можно сразу прыгнуть на one\_gadget и получить shell без аргументов.

**libc-database** — огромная коллекция разных libc.\
По утечке нескольких байт (например \_\_libc\_start\_main+243) можно определить точную версию libc и скачать её.

В CTF эти инструменты спасают часы: вместо ручного поиска гаджетов — одна команда, вместо угадывания libc — автоматический поиск.

### checksec, patchelf, seccomp-tools

**checksec** — показывает все защиты бинарника за одну команду:

* NX — можно ли исполнять стек
* Canary — есть ли защита стека
* PIE — случайная база программы
* RELRO — уровень защиты GOT

**patchelf** — позволяет патчить бинарник:

* отключить NX для отладки
* изменить интерпретатор
* поменять rpath

**seccomp-tools** — анализирует seccomp-фильтры (какие системные вызовы разрешены).\
Очень полезно в задачах, где запрещены execve, open, read и т.д.

В CTF сначала запускаешь checksec, чтобы понять, с чем имеешь дело, потом смотришь seccomp, если нужно — патчишь бинарник для локальной отладки.

### Итог

Главное, что нужно запомнить: в pwn-задачах 50% успеха — это умение быстро пользоваться правильными инструментами, а не только знать теорию эксплуатации.

Ключевые слова и термины для запоминания:\
pwntools, gdb, gef, pwndbg, ROPgadget, one\_gadget, libc-database, checksec, patchelf, seccomp-tools, gadget, exploit.

Эти знания помогают:

* за 5 строк на pwntools подключиться к серверу и отправить payload
* в gdb с gef мгновенно увидеть стек и понять offset
* найти гаджеты и one\_gadget за секунды вместо часов
* сразу понять, какие защиты включены и что можно обойти
* определить версию libc по утечке и скачать точную копию

Освой сначала pwntools + checksec + gdb с gef/pwndbg — это база, без которой почти невозможно комфортно решать pwn. Остальные инструменты добавляй по мере роста сложности задач.

***

## Основы бинарной эксплуатации

Бинарная эксплуатация — это когда ты заставляешь уже скомпилированную программу (бинарник) делать то, что ты хочешь, хотя автор этого не планировал: читать память, запускать свой код, получать shell.\
В CTF эта тема в первую очередь относится к категории **Pwn** (pwnable / binary exploitation).\
Чаще всего встречается в задачах, где дают исполняемый файл (ELF на Linux или PE на Windows) и удалённый сервер, а нужно либо получить флаг, либо запустить команду на сервере.\
Новичку понимать эти основы критически важно, потому что без знания, как устроен бинарник и память, ты просто не поймёшь, почему твой payload не работает и куда писать адрес.\
Когда разберёшься в структуре ELF/PE, секциях и стеке — большинство классических stack overflow и ret2win задач станут понятными и решаемыми.

### Словарь терминов

| Термин        | Что это простыми словами                                                   |
| ------------- | -------------------------------------------------------------------------- |
| ELF           | Формат исполняемых файлов в Linux                                          |
| PE            | Формат исполняемых файлов в Windows (.exe, .dll)                           |
| заголовок     | Начальная часть файла, где описано, как его загружать в память             |
| секция        | Кусок файла, который содержит код, данные или другую информацию            |
| .text         | Секция, где лежит машинный код программы (инструкции)                      |
| .data         | Секция с инициализированными глобальными переменными                       |
| .bss          | Секция для неинициализированных глобальных переменных (заполняется нулями) |
| .rodata       | Секция только для чтения — обычно строки и константы                       |
| GOT           | Таблица, куда во время работы записываются адреса библиотечных функций     |
| PLT           | Таблица, через которую программа вызывает функции из библиотек             |
| стек          | Область памяти для локальных переменных и адресов возврата                 |
| куча          | Область памяти для динамически выделяемых данных (malloc)                  |
| mmap          | Способ выделить память по произвольному адресу (часто для shellcode)       |
| little-endian | Младший байт числа лежит по меньшему адресу                                |
| alignment     | Выравнивание данных по определённому размеру (обычно 8 или 16 байт)        |

### Формат ELF и PE файлов, структура заголовков

**ELF** (Executable and Linkable Format) — стандартный формат для Linux.\
Начинается с magic bytes 7f 45 4c 46.\
Основные части:

* ELF Header — общая информация (32/64 бит, little/big endian, точка входа)
* Program Headers — говорит, какие куски грузить в память и куда
* Section Headers — описывает все секции (.text, .data и т.д.)

**PE** (Portable Executable) — формат Windows.\
Начинается с MZ (4D 5A), потом идёт PE-сигнатура (50 45).\
Основные части:

* DOS Header
* PE Header
* Optional Header
* Section Table

В CTF почти всегда дают 64-битный ELF на Linux — это самый частый случай.\
Знать структуру заголовков нужно, чтобы понимать, где начинается код, где данные и где можно найти полезные строки или адреса.

### Секции .text, .data, .bss, .rodata, GOT, PLT

**.text**\
Здесь лежит исполняемый код — все функции программы.\
Обычно имеет права только на чтение и выполнение (no write).

**.data**\
Инициализированные глобальные переменные (int x = 1337;).\
Читается и пишется.

**.bss**\
Неинициализированные глобальные переменные (int y;).\
При запуске заполняется нулями.\
Тоже читается и пишется.

**.rodata**\
Только для чтения: строки, константы, форматные строки printf.\
Очень часто именно здесь лежат строки типа "/bin/sh" или "flag.txt".

**GOT** (Global Offset Table)\
Таблица, куда динамический линкователь записывает реальные адреса функций из библиотек (printf, system и т.д.).\
Если удаётся переписать GOT — можно подменить, какую функцию вызовет программа.

**PLT** (Procedure Linkage Table)\
Кусок кода, через который идут все вызовы внешних функций.\
PLT → GOT → настоящая функция.

В CTF эти знания нужны, чтобы:

* найти строку "/bin/sh" в .rodata
* понять, куда писать адрес system
* использовать PLT для вызова нужных функций без знания их адресов

### Адресация памяти, стек, куча, mmap

Когда программа запускается, операционная система выделяет ей виртуальную память.\
Основные области:

* **стек** — растёт вниз (от высоких адресов к низким). Здесь локальные переменные, аргументы функций, адрес возврата.
* **куча** — растёт вверх (от низких к высоким). Здесь всё, что выделено через malloc/new.
* **mmap** — область для отображения файлов или произвольного выделения памяти (часто используется для shellcode).
* **библиотеки** (libc) — загружаются в середину адресного пространства.

Типичный порядок адресов (64-bit Linux):\
0x0000… → низкие адреса\
библиотеки → mmap → куча → … → стек → 0x7fff… высокие адреса

В CTF чаще всего эксплуатируют именно стек (stack overflow), потому что там лежит return address — адрес, куда программа вернётся после функции.

### Endianness (little/big), alignment и padding

**Endianness**\
Little-endian (x86/x64): младший байт по младшему адресу.\
Число 0x41424344 лежит как 44 43 42 41.\
Big-endian: старший байт первым (почти не встречается в CTF на Linux).

**Alignment**\
Данные обычно выравниваются по 8 или 16 байтам.\
Например, int64 должен лежать по адресу, кратному 8.

**Padding**\
Дополнительные байты, которые добавляют, чтобы соблюсти alignment.\
В структурах между полями часто бывают «мусорные» байты.

В CTF это важно при:

* упаковке адресов в payload (p64 в pwntools — little-endian)
* понимании, почему после локальной переменной идёт мусор перед return address
* расчёте точного смещения для переполнения

### Итог

Главное, что нужно запомнить: программа — это просто набор байтов в памяти, и если ты знаешь, где лежит код, данные, стек и адреса возврата — ты можешь заставить её выполнять то, что хочешь.

Ключевые слова и термины для запоминания:\
ELF, PE, .text, .data, .bss, .rodata, GOT, PLT, стек, куча, mmap, little-endian, alignment, padding, return address.

Эти знания позволяют:

* понять, сколько байт нужно отправить, чтобы достать до return address
* найти адрес строки "/bin/sh" в бинарнике
* посчитать смещение до GOT и подменить функцию
* правильно упаковать 64-битные адреса в payload
* отличать stack-based атаки от heap-based

Освой эти базовые понятия — и классические pwn-задачи типа ret2win, call system, write-what-where перестанут быть магией и станут понятной механикой.

***

## Переполнение буфера на куче

Переполнение буфера на куче — это когда программа позволяет записать больше данных, чем выделено в динамической памяти (куче), и это портит метаданные или другие куски данных, которые там лежат.\
В CTF эта тема относится в первую очередь к категории **Pwn** (бинарная эксплуатация, heap exploitation).\
Чаще всего такие задачи встречаются на уровне medium–hard, когда классический stack overflow уже закрыт защитами (canary, NX, ASLR), и авторы дают уязвимости именно в работе с malloc/free.\
Новичку это нужно изучать после стека, потому что heap гораздо сложнее, но именно здесь прячутся самые интересные и мощные примитивы для получения произвольного чтения/записи и выполнения кода.\
Когда разберёшься в базовых атаках на tcache и fastbin — сможешь решать многие задачи, которые раньше казались невозможными.

### Словарь терминов

| Термин           | Что это простыми словами                                            |
| ---------------- | ------------------------------------------------------------------- |
| куча             | Динамическая память, из которой программа берёт память через malloc |
| chunk            | Один кусок памяти в куче (заголовок + данные)                       |
| use-after-free   | Использование указателя после того, как память уже freed            |
| double-free      | Дважды освободить один и тот же кусок памяти                        |
| heap overflow    | Переполнение буфера внутри выделенного куска на куче                |
| tcache           | Кэш маленьких кусков (до \~1 КБ), ускоряет malloc/free              |
| fastbin          | Кэш для очень маленьких кусков (до 128 байт на 64-бит)              |
| unsorted bin     | Список больших освобождённых кусков, которые ещё не отсортированы   |
| large bin        | Список очень больших кусков (> 512 байт)                            |
| tcache poisoning | Подмена указателя в tcache, чтобы malloc вернул нужный адрес        |
| fastbin attack   | Атака на fastbin, похожая на tcache poisoning                       |
| unsafe-unlink    | Эксплуатация unlink без проверок (старая техника)                   |
| house of orange  | Техника для атаки на top chunk и получения произвольного выделения  |
| heap spraying    | Заполнение кучи большим количеством одинаковых объектов             |

### Heap overflow, use-after-free, double-free

**Heap overflow**\
Когда в выделенный кусок (например 0x100 байт) пишут больше, чем выделили — перезаписывают заголовок следующего чанка или его данные.\
Можно испортить размер следующего чанка, указатель prev\_size, fd/bk в freed-чанке.

**Use-after-free (UAF)**\
Программа сохраняет указатель на freed память и продолжает с ним работать.\
После free память может быть выделена заново → ты контролируешь, что там лежит, и можешь подменить указатели или vtable.

**Double-free**\
Дважды вызвать free на один и тот же указатель.\
В tcache это кладёт один и тот же chunk дважды в один список → при следующем malloc можно получить один и тот же адрес два раза → очень мощный примитив для подмены указателей.

В CTF эти три уязвимости — самые частые начальные примитивы.\
Обычно дают одну из них + возможность читать/писать в выделенные куски.

### Heap spraying, tcache poisoning, fastbin attack

**Heap spraying**\
Создаём много одинаковых объектов на куче, чтобы увеличить шанс, что нужный адрес будет занят нашим контролируемым чанком.

**Tcache poisoning**\
Tcache — это односвязный список для маленьких кусков (до 0x408 байт).\
Если через UAF или overflow подменить указатель fd в freed-чанке на адрес, который мы хотим → следующий malloc вернёт нам произвольный адрес (например GOT, \_\_free\_hook, stack).

**Fastbin attack**\
Fastbin похож на tcache, но без проверки размера и с двойным освобождением.\
Можно заставить fastbin указывать на фейковый chunk, а потом выделить память по контролируемому адресу.

Tcache poisoning — самая популярная техника в современных 64-бит Linux libc (с версии 2.26).\
Обычно цепочка выглядит так: UAF / double-free → подмена fd → malloc → пишем в нужное место (GOT, free\_hook).

### Unsafe-unlink, house of orange, house of botcake

**Unsafe-unlink**\
Старая техника (до проверок в glibc 2.3.4).\
Если подделать fd и bk в freed-чанке → при unlink можно записать адрес чанка в произвольное место (Pwn классика прошлого).

**House of Orange**\
Атака на top chunk (последний большой кусок кучи).\
Через overflow или unlink заставляем \_int\_malloc думать, что top маленький → он вызывает sysmalloc → можно перехватить контроль над heap metadata и получить arbitrary alloc.

**House of Botcake**\
Современная вариация house-техник, работает с tcache и large bin consolidation.\
Обычно используется, когда нужно обойти проверки tcache и получить контроль над unsorted bin или large bin.

Эти house-атаки встречаются в hard-задачах, где обычный tcache poisoning заблокирован фильтрами или проверками.

### Tcache, fastbin, unsorted bin, large bin атаки

**Tcache**\
Самый простой и популярный кэш. Односвязный список. Нет проверок на дубликаты. Очень легко отравить.

**Fastbin**\
Для кусков до 128 байт. Двойной free работает, но есть проверка на повторное добавление. Атаки похожи на tcache, но сложнее.

**Unsorted bin**\
Список освобождённых кусков, которые не попали в маленький кэш. При выделении большого куска unsorted bin сканируется → можно заставить записать адрес libc в контролируемое место (fd/bk overwrite).

**Large bin**\
Для очень больших кусков. Имеет сортировку. Атаки через large bin attack позволяют подменять указатели и получать произвольную запись.

В CTF чаще всего побеждает tcache poisoning → unsorted bin leak → large bin attack для arbitrary write.

### Итог

Главное, что нужно запомнить: куча — это не хаос, а набор связанных списков (tcache, fastbin, unsorted, large), и большинство атак сводится к подмене указателей в этих списках, чтобы malloc вернул нужный адрес.

Ключевые слова и термины для запоминания:\
heap overflow, use-after-free, double-free, tcache poisoning, fastbin attack, unsorted bin, large bin, house of orange, unsafe-unlink, chunk, top chunk, heap spraying.

Эти знания помогают:

* получить произвольное выделение памяти через tcache poisoning
* слить адрес libc через unsorted bin fd/bk
* переписать \_\_free\_hook или GOT для выполнения system("/bin/sh")
* обойти маленькие буферы и сложные проверки через double-free + UAF
* понять, почему в задаче дают именно malloc/free и несколько выделений подряд

Освой сначала tcache poisoning и unsorted bin leak — это откроет тебе 60–70% всех heap-задач среднего уровня. Дальше house-техники и large bin — для hard и expert.

***

## Переполнение буфера на стеке

Переполнение буфера на стеке — это когда программа позволяет записать в маленький массив (буфер) больше данных, чем он может вместить, и лишние байты начинают затирать важные вещи дальше по памяти, в том числе адрес возврата из функции.\
В CTF эта тема в первую очередь относится к категории **Pwn** (бинарная эксплуатация).\
Чаще всего встречается в классических задачах, где дают программу с уязвимым gets/scanf/ strcpy и нужно либо прочитать флаг, либо получить shell на удалённом сервере.\
Новичку обязательно нужно это понять, потому что stack overflow — самая первая и самая понятная уязвимость, с которой начинают учить эксплуатацию.\
Когда освоишь перезапись return address и обход простых защит — ты сможешь решать 70–80% всех beginner и easy pwn-задач.

### Словарь терминов

| Термин              | Что это простыми словами                                                       |
| ------------------- | ------------------------------------------------------------------------------ |
| буфер               | Массив фиксированного размера для хранения данных                              |
| переполнение буфера | Запись за пределы буфера, затирание того, что лежит дальше                     |
| стек                | Область памяти сверху вниз: локальные переменные + адрес возврата              |
| return address      | Адрес в памяти, куда программа вернётся после завершения функции               |
| stack smashing      | Переполнение буфера на стеке с перезаписью return address                      |
| canary              | Случайное секретное значение перед return address для обнаружения переполнения |
| GS / stack canary   | Защита, которая проверяет canary перед возвратом из функции                    |
| leak                | Получение значения из памяти (например canary) через уязвимость                |
| ROP                 | Цепочка коротких кусочков кода из программы (gadgets), заканчивающихся ret     |
| gadget              | Короткая последовательность инструкций, заканчивающаяся ret                    |
| stack pivot         | Изменение указателя стека rsp, чтобы использовать другой стек                  |
| fake stack          | Поддельный стек, который мы контролируем и на который переключаемся            |
| NX                  | Защита: память, помеченная как исполняемая или нет (no eXecute)                |

### Stack smashing и перезапись return address

Программа выделяет на стеке буфер, например char buf\[100].\
Если ввести 150 символов — лишние 50 байт затирают то, что лежит выше по стеку.

Порядок на стеке (снизу вверх, адреса уменьшаются):

* локальные переменные (buf)
* сохранённый rbp (frame pointer)
* return address (куда вернуться после функции)

Если переполнить buf и записать свой адрес вместо return address — при ret программа прыгнет туда, куда ты указал.

В CTF чаще всего:

* ret2win — прыгаем на функцию win() / print\_flag()
* ret2shellcode — если NX выключен, прыгаем на свой shellcode в стеке
* ret2system — прыгаем на system("/bin/sh")

Простейший случай без защит: считаешь offset от начала buf до return address (обычно 104–120 байт в 64-бит) и пишешь junk + адрес цели.

### Canary/GS protection и bypass (leak, brute-force)

Canary — это случайное 8-байтное значение (часто заканчивается 00), которое программа кладёт между буфером и return address.\
Перед ret она проверяет: canary всё ещё то же? Если нет — программа крашится (stack smashing detected).

Как обойти:

* **leak** — если есть другая уязвимость (format string, off-by-one, read после переполнения), сначала вытекает canary, потом используешь его в payload
* **brute-force** — если сервер форкается (fork server) и canary не меняется между соединениями — перебираешь байты canary по одному (256 вариантов на байт, всего \~2¹⁶–2²⁴ попыток)
* **bypass через другую уязвимость** — иногда можно перезаписать canary тем же значением, которое там уже лежит

В CTF без canary-задач почти не бывает на уровне выше beginner.

### ROP (Return-Oriented Programming), гаджеты

Когда NX включён — свой код (shellcode) на стеке не запустится.\
ROP — способ обойти это: используем уже существующие куски кода в программе или libc, которые заканчиваются инструкцией ret.

Gadget — короткая последовательность инструкций вида: pop rdi; ret\
mov rax, rbx; ret\
add rsp, 0x20; ret

Типичная ROP-цепочка:

* pop rdi; ret → кладём "/bin/sh" в rdi
* pop rsi; ret → 0 в rsi
* pop rdx; ret → 0 в rdx
* system → вызов system("/bin/sh")

В CTF чаще всего:

* ищешь гаджеты в бинарнике и libc
* строишь цепочку для вызова system, execve, read/write
* используешь один гаджет для ret2csu (если нет прямых pop)

### Stack pivot и fake stack

Иногда буфер слишком маленький, чтобы уместить всю ROP-цепочку.\
Или return address перезаписывается, но гаджеты лежат далеко.

Stack pivot — меняем значение rsp (указатель стека) на адрес, который мы контролируем (например в .bss, heap, mmap).

Популярные гаджеты для pivot:

* leave; ret → mov rsp, rbp; pop rbp; ret
* add rsp, N; ret
* pop rsp; ret

Fake stack — создаём свой контролируемый стек в .bss / heap и переключаемся на него.

В CTF это встречается, когда:

* маленький буфер + большая цепочка
* нужно вызвать несколько функций подряд
* ASLR + частичный leak → pivot на известный адрес

### Итог

Главное, что нужно запомнить: переполнение буфера на стеке — это про контроль return address, а современные защиты заставляют либо обходить canary, либо собирать ROP-цепочки из существующих гаджетов.

Ключевые слова и термины для запоминания:\
stack smashing, return address, canary, leak, brute-force, ROP, gadget, stack pivot, fake stack, NX, ret2win, ret2system.

Эти знания позволяют:

* посчитать точный offset и перезаписать return address на win-функцию
* слить canary через format string и потом использовать в payload
* собрать простую ROP-цепочку для system("/bin/sh")
* обойти маленький буфер через stack pivot на контролируемую область
* понять, почему без NX можно вставить shellcode прямо в стек

Освой эти техники шаг за шагом — и большинство классических stack-based pwn-задач перестанут быть страшными, а станут логичной головоломкой.

***

## Return-to-libc и ROP

Return-to-libc и ROP — это способы заставить программу выполнить чужой код, когда нельзя просто вставить свой shellcode из-за защиты NX (no-execute).\
Вместо записи своего кода ты используешь уже существующие функции из библиотеки libc (system, execve) или короткие кусочки кода (gadgets) из самой программы и libc.\
В CTF эта тема относится в первую очередь к категории **Pwn** (бинарная эксплуатация).\
Чаще всего встречается в задачах уровня easy–medium-hard, где есть переполнение буфера, но NX включён, а иногда и ASLR.\
Новичку это нужно освоить сразу после простого stack overflow, потому что ret2libc и ROP — основа почти всех современных pwn-задач без исполняемого стека.\
Когда научишься собирать простые цепочки и вызывать system("/bin/sh") — откроется огромный пласт решаемых задач.

### Словарь терминов

| Термин        | Что это простыми словами                                                      |
| ------------- | ----------------------------------------------------------------------------- |
| ret2libc      | Техника: прыгаем на функцию из libc (обычно system)                           |
| system        | Функция libc, которая выполняет команду в shell                               |
| one\_gadget   | Готовый адрес в libc, который сразу даёт shell без аргументов                 |
| ROP           | Return-Oriented Programming — цепочка гаджетов, заканчивающихся ret           |
| gadget        | Короткий кусок кода, заканчивающийся инструкцией ret                          |
| pop rdi       | Гаджет, который кладёт значение со стека в регистр rdi                        |
| ret2csu       | Техника использования \_\_libc\_csu\_init для установки регистров             |
| libc          | Стандартная библиотека C, где лежат system, execve, puts и т.д.               |
| ASLR          | Защита: адреса libc и программы каждый раз разные                             |
| NX            | Защита: стек и куча не могут исполняться как код                              |
| dlresolve     | Механизм динамической линковки, который можно использовать для вызова функций |
| ret2dlresolve | Атака через подделку структур динамической линковки                           |
| PLT           | Таблица, через которую вызываются функции libc                                |
| GOT           | Таблица, куда записываются реальные адреса функций libc                       |

### ret2libc (system, execve, one\_gadget)

**ret2libc** — самый простой и классический способ.\
Идея: вместо своего кода прыгаем на уже существующую функцию system из libc и передаём ей строку "/bin/sh".

Шаги:

* найти адрес строки "/bin/sh" (в libc или в программе)
* найти адрес функции system (через leak или частичный brute)
* в payload: junk + адрес system + адрес возврата + адрес "/bin/sh"

**execve** — похож, но требует больше аргументов (pop rdi → "/bin/sh", pop rsi → 0, pop rdx → 0).

**one\_gadget** — специальные адреса в libc, где один ret сразу вызывает execve("/bin/sh", NULL, NULL).\
Очень удобно, потому что не нужно готовить аргументы.

В CTF ret2libc — это первая техника, которую учат после базового переполнения.\
Если знаешь offset до return address — просто кладешь адрес system и "/bin/sh".

### ROP chains (pop rdi, pop rsi, pop rdx)

Когда одной функции недостаточно — собираем цепочку гаджетов.

Типичная цепочка для system("/bin/sh"):

* pop rdi; ret → кладём "/bin/sh" в rdi (первый аргумент)
* pop rsi; ret → 0 в rsi (второй аргумент)
* pop rdx; ret → 0 в rdx (третий аргумент)
* system → вызов system("/bin/sh")

Каждый гаджет заканчивается ret → rsp сдвигается, следующий гаджет берёт свои аргументы со стека.

В CTF почти всегда нужно:

* найти гаджеты pop rdi, pop rsi, pop rdx (они есть почти везде)
* посчитать offset до return address
* собрать payload: junk + гаджет1 + аргумент1 + гаджет2 + аргумент2 + … + system

### Gadget finding (ROPgadget, Ropper, rp++), ret2csu

Gadgets — это любые последовательности инструкций, заканчивающиеся ret (c3).\
Их ищут автоматически по бинарнику и libc.

Самые полезные гаджеты:

* pop rdi; ret
* pop rsi; ret
* pop rdx; ret
* pop rax; ret
* mov rdi, rax; ret
* add rsp, N; ret (для stack pivot)

**ret2csu** — когда в бинарнике нет хороших pop-гаджетов, используют код из \_\_libc\_csu\_init (функция инициализации).\
Там есть мощная последовательность, которая позволяет положить значения в rbx, rbp, r12, r13, r14, r15 и вызвать вызов по адресу.

ret2csu — спасение, когда libc не загружена или гаджетов мало.

В CTF сначала ищут простые pop-гаджеты, если их нет — переходят к ret2csu.

### Ret2dlresolve, ret2dlruntime

**ret2dlresolve** — продвинутая техника, когда не удаётся слить libc или нет "/bin/sh".\
Использует механизм ленивой линковки (lazy binding): программа сама вызывает \_dl\_runtime\_resolve, когда впервые вызывает функцию.

Идея:

* подделать структуру JMPREL / SYMTAB / STRTAB на стеке
* заставить программу думать, что нужно разрешить символ (например system)
* \_dl\_runtime\_resolve вызовет настоящий system

Это позволяет вызвать любую функцию libc без знания её адреса.

В CTF ret2dlresolve встречается в hard-задачах, где ASLR полный, нет утечек и нет строк "/bin/sh".

### Итог

Главное, что нужно запомнить: когда NX запрещает исполнение стека — мы используем уже существующий код: либо готовые функции libc (ret2libc), либо короткие кусочки ret-гаджетов (ROP).

Ключевые слова и термины для запоминания:\
ret2libc, system, one\_gadget, ROP, gadget, pop rdi, pop rsi, pop rdx, ret2csu, dlresolve, libc, ASLR, NX, PLT, GOT.

Эти знания помогают:

* вызвать system("/bin/sh") простым ret2libc без гаджетов
* собрать цепочку для execve с правильными регистрами
* использовать ret2csu, когда обычных гаджетов не хватает
* обойти полное ASLR через ret2dlresolve
* понять, почему в payload после адреса идут ещё 8-байтные значения (аргументы гаджетов)

Освой сначала ret2libc с system, потом простую ROP-цепочку с pop-гаджетами, а затем ret2csu — и большинство pwn-задач с переполнением буфера перестанут быть проблемой. Это основа всей современной бинарной эксплуатации.

***

## Защиты и их обход

Защиты — это механизмы, которые операционная система и компилятор включают в программу, чтобы сделать эксплуатацию уязвимостей (переполнений, format string и т.д.) гораздо сложнее или вообще невозможной.\
В CTF эта тема относится в первую очередь к категории **Pwn** (бинарная эксплуатация).\
Чаще всего защиты встречаются в задачах уровня easy–medium-hard, где без их обхода классическое переполнение буфера просто не сработает.\
Новичку важно понять, какие защиты существуют и как их обойти, потому что на реальных соревнованиях почти никогда не дают программу без хотя бы одной защиты.\
Когда ты научишься определять, какие защиты включены и как их нейтрализовать — ты перестанешь получать «Segmentation fault» и начнёшь получать shell там, где другие сдаются.

### Словарь терминов

| Термин            | Что это простыми словами                                                   |
| ----------------- | -------------------------------------------------------------------------- |
| NX / DEP          | Защита: память стека и кучи нельзя исполнять как код                       |
| ASLR              | Случайное расположение адресов libc, стека, программы при запуске          |
| PIE               | Случайная база адресов самой программы (Position Independent Executable)   |
| Canary            | Случайное значение перед return address, проверяется при выходе из функции |
| RELRO             | Защита таблицы GOT: делает её частично или полностью только для чтения     |
| Partial RELRO     | GOT можно перезаписать до первого вызова функции                           |
| Full RELRO        | GOT только для чтения с самого начала                                      |
| info leak         | Утечка адресов через format string, UAF, heap overflow и т.д.              |
| partial overwrite | Перезапись только младших байт адреса (например последние 2 байта)         |
| brute-force       | Перебор возможных значений (чаще всего canary или младших байт адреса)     |

### NX (DEP), ASLR, PIE, Canary, RELRO

**NX / DEP**\
No-eXecute / Data Execution Prevention — стек и куча помечены как неисполняемые.\
Твой shellcode на стеке просто не запустится — программа упадёт с SIGSEGV.

**ASLR**\
Address Space Layout Randomization — каждый запуск программы libc, стек, куча и mmap-области лежат по случайным адресам.\
Без утечки адресов ты не знаешь, куда прыгать.

**PIE**\
Position Independent Executable — сама программа (не только библиотеки) загружается по случайному базовому адресу.\
Адреса функций main, win и гаджетов каждый раз разные.

**Canary**\
Случайное 8-байтное значение (часто заканчивается нулевым байтом) кладётся между буфером и return address.\
Перед ret проверяется: если canary изменился — программа крашится.

**RELRO**\
RELocation Read-Only — защита таблицы GOT.\
Partial RELRO — GOT перезаписывается до первого вызова функции.\
Full RELRO — GOT сразу только для чтения, перезаписать нельзя.

В CTF почти всегда включают хотя бы NX + Canary + ASLR.\
PIE и Full RELRO — признак более сложной задачи.

### Stack canary leak и brute-force

**Leak canary**\
Самый надёжный способ — использовать другую уязвимость (format string, off-by-one read, heap UAF), чтобы прочитать canary до переполнения.\
Обычно canary лежит сразу после локальных переменных → можно вывести его через %x или %s.

**Brute-force canary**\
Если сервер форкается (каждое соединение — новый процесс с тем же canary) — можно перебирать canary по байтам.\
Обычно 6 байт (последний всегда 00) → 2¹⁶–2⁴⁸ попыток в худшем случае, но на практике часто 2¹⁶–2²⁴.

В CTF leak — предпочтительнее, brute-force — запасной вариант для fork-серверов.

### Partial RELRO и full RELRO bypass

**Partial RELRO**\
GOT перезаписывается только после первого вызова функции (lazy binding).\
Если ты перезапишешь GOT до первого вызова (например через format string или heap overflow) — при следующем вызове printf/puts программа прыгнет на твой адрес.

**Full RELRO**\
GOT сразу read-only.\
Перезаписать GOT нельзя.\
Обход:

* использовать ret2dlresolve (подделать структуры динамической линковки)
* переписать другие указатели (\_\_free\_hook, \_\_malloc\_hook)
* использовать one\_gadget или гаджеты без GOT

В CTF Full RELRO заставляет переходить от GOT overwrite к более сложным техникам (dlresolve, hooks).

### ASLR bypass (info leak, partial overwrite)

**Info leak**\
Самый частый и надёжный способ:

* format string → %s или %x на GOT → адрес libc
* heap leak → unsorted bin fd/bk → libc base
* stack leak → canary + return address → PIE base + libc offset\
  После утечки считаешь точные адреса system, "/bin/sh", гаджетов.

**Partial overwrite**\
Если знаешь старшие байты адреса (например libc base через leak), а младшие случайны — можно перезаписать только последние 1–2 байта.\
Часто используется в связке с heap overflow или format string %hhn.

В CTF ASLR почти никогда не обходят brute-force (слишком долго), а только через утечку или частичную перезапись.

### Итог

Главное, что нужно запомнить: современные программы защищены сразу несколькими механизмами (NX, Canary, ASLR, PIE, RELRO), и задача эксплойтера — понять, какие именно включены, и найти способ их обойти (утечка, brute, partial write, альтернативные техники).

Ключевые слова и термины для запоминания:\
NX, ASLR, PIE, Canary, RELRO, Partial RELRO, Full RELRO, info leak, partial overwrite, brute-force, stack canary leak.

Эти знания помогают:

* определить по поведению программы, включён ли canary (краш с «stack smashing detected»)
* слить libc base через format string или heap и посчитать адрес system
* обойти ASLR, зная только младшие байты адреса
* понять, почему GOT overwrite не работает (Full RELRO) и перейти к ret2dlresolve
* комбинировать утечку canary + утечку libc → полный контроль над программой

Освой сначала, как определять защиты (checksec или поведение краша), потом утечки адресов — и большинство защит перестанут быть преградой, а станут просто дополнительными шагами в эксплойте.

***
