Return-Oriented Programming
Return-Oriented Programming (ROP, программирование, ориентированное на возврат) — это метод эксплуатации программных уязвимостей, основанный на использовании существующих фрагментов машинного кода (гаджетов), завершающихся инструкцией возврата, для построения произвольной цепочки вызовов и выполнения вредоносных действий. ROP является одной из наиболее распространённых техник обхода механизмов защиты памяти, таких как NX-бит (No-Execute) и DEP (Data Execution Prevention), которые запрещают выполнение кода в областях данных.
История
Метод ROP был впервые описан в 2007 году группой исследователей из Калифорнийского университета в Сан-Диего и Технологического института Джорджии в работе «Return-Oriented Programming: Exploits Without Code Injection». Работа демонстрировала возможность построения полного эксплойта без внедрения нового кода, используя только фрагменты легитимного кода, уже загруженного в память процесса. До этого существовали более ранние методы, такие как return-to-libc (возврат к библиотечным функциям), который позволял вызывать стандартные функции C-библиотеки, но был ограничен по сложности и не позволял выполнять произвольные последовательности команд.
Развитие ROP было ответом на внедрение в операционные системы и компиляторы технологий, предотвращающих выполнение кода на стеке и в куче. Первоначально ROP применялся для атак на x86-архитектуру, но впоследствии был адаптирован для ARM, MIPS, SPARC и других архитектур. К 2010-м годам ROP стал стандартным инструментом в арсенале создателей эксплойтов, что привело к разработке методов защиты, таких как ASLR (Address Space Layout Randomization) и CFI (Control Flow Integrity).
Принцип работы
Гаджеты
Основным строительным блоком ROP является гаджет — короткая последовательность инструкций машинного кода, заканчивающаяся инструкцией возврата (ret на x86, bx lr на ARM и т.д.). Гаджеты извлекаются из существующих исполняемых модулей (библиотек, исполняемых файлов) процесса. Каждый гаджет выполняет простую операцию: загрузку данных в регистр, арифметическое действие, запись в память или вызов функции. Пример гаджета для x86:
`` pop eax; ret ``
Эта последовательность загружает значение со стека в регистр EAX и возвращает управление по адресу, лежащему на вершине стека.
Цепочка гаджетов
Злоумышленник, получив контроль над стеком (например, через переполнение буфера), выстраивает на нём последовательность адресов гаджетов и необходимых данных. Эта последовательность называется цепочкой ROP (ROP chain). При выполнении:
- Первый гаджет получает управление после перехвата потока выполнения.
- После выполнения инструкции
retон снимает со стека адрес следующего гаджета и передаёт ему управление. - Процесс повторяется, пока не будет выполнена вся цепочка.
В результате злоумышленник может выполнить любую последовательность операций, не внедряя ни одного байта нового кода в память процесса.
Построение цепочки
Для построения цепочки ROP необходимо:
- Найти достаточное количество гаджетов в доступных модулях (обычно в системных библиотеках, таких как libc.so в Linux или ntdll.dll в Windows).
- Определить адреса гаджетов в памяти процесса. Для этого требуется знание базовых адресов модулей, что осложняется ASLR.
- Спроектировать последовательность, которая выполняет целевую задачу: например, вызывает системный вызов для открытия shell (
execve), записывает файл или отключает защиту.
Классификация
По архитектуре
- x86 (32-битная) — наиболее простая для ROP, так как инструкции имеют переменную длину, и гаджеты могут быть найдены в неожиданных местах из-за выравнивания байтов.
- x86-64 (64-битная) — сложнее из-за требования выравнивания стека по 16 байтам для вызова некоторых функций (например, в System V ABI) и большего количества регистров, что требует большего числа гаджетов.
- ARM — инструкции фиксированной длины (4 байта для ARM, 2 для Thumb), что снижает плотность гаджетов, но ROP возможен как в ARM, так и в Thumb-режиме.
- MIPS, SPARC, RISC-V — ROP существует, но менее распространён из-за особенностей архитектуры (например, использование регистров связи).
По типу атаки
- Прямая ROP — злоумышленник полностью строит цепочку из гаджетов, не используя внедрённый код.
- Jump-Oriented Programming (JOP) — использует гаджеты, завершающиеся инструкцией косвенного перехода (jmp, call), а не возврата.
- Call-Oriented Programming (COP) — вариант, использующий инструкции вызова функций.
- Sigreturn-Oriented Programming (SROP) — использует системный вызов
sigreturnдля установки всех регистров из одного блока данных (сигнального кадра).
Примеры применения
Отключение DEP и выполнение shellcode
Классическое применение ROP — отключение защиты NX/DEP для региона памяти, после чего в этот регион помещается shellcode. Цепочка ROP вызывает функцию VirtualProtect (Windows) или mprotect (Linux) с нужными аргументами, а затем передаёт управление на shellcode.
Выполнение системных вызовов
В Linux цепочка ROP может настроить регистры для системного вызова (например, execve), после чего выполнить инструкцию int 0x80 или syscall (для x86-64). Это позволяет запустить произвольную программу (например, /bin/sh).
Обход ASLR
Если ASLR включён, адреса гаджетов заранее неизвестны. Для обхода используется утечка адреса (например, через информационную уязвимость), после чего вычисляются базовые адреса модулей и пересчитываются адреса гаджетов. В некоторых случаях применяется частичный обход ASLR через атаки на энтропию.
Методы защиты
Address Space Layout Randomization (ASLR)
ASLR случайным образом размещает в памяти исполняемые модули, стеки и кучи. Это затрудняет определение адресов гаджетов. Однако ASLR может быть обойдён при утечке адреса или если модуль не рандомизирован (например, исполняемый файл без поддержки PIE).
Control Flow Integrity (CFI)
CFI проверяет, что косвенные переходы (вызовы функций, возвраты) следуют заранее определённым графам потока управления. Любое отклонение (например, переход на гаджет ROP) обнаруживается и блокируется. Существуют разные реализации CFI — от грубых (Coarse-grained CFI) до точных (Fine-grained CFI).
Shadow Stack (Теневой стек)
Теневой стек хранит копию адресов возврата в отдельной, защищённой от записи области памяти. При выполнении инструкции ret реальный адрес возврата сравнивается со значением из теневого стека. Расхождение указывает на атаку ROP. Эта технология реализована в процессорах Intel (CET — Control-flow Enforcement Technology) и AMD (SEV-SNP).
Stack Canaries (Канарейки)
Канарейки — случайные значения, помещаемые на стек перед адресом возврата функции. Если происходит переполнение буфера, канарейка изменяется, и перед возвратом функция проверяет её целостность. Это затрудняет перехват управления, но не защищает от ROP, если злоумышленник может обойти проверку (например, через утечку канарейки).
Критика и ограничения
- Сложность построения цепочек — для сложных задач требуется множество гаджетов, что увеличивает размер эксплойта и время его создания. Инструменты автоматизации (например, ROPgadget, Ropper) упрощают поиск, но не гарантируют нахождение всех необходимых гаджетов.
- Зависимость от контекста — ROP требует точного знания версий библиотек, компилятора и флагов сборки. Разные версии одного модуля могут иметь разные адреса гаджетов.
- Ограниченная защита — ROP не защищает от атак, использующих утечки информации или нестандартные архитектуры. Также существуют методы, обходящие CFI, например, через атаки на саму реализацию CFI.
- Эффективность на современных системах — с внедрением CET и аналогичных аппаратных решений ROP становится значительно сложнее, но не невозможным. Исследователи продолжают находить способы обхода (например, через использование гаджетов, не затрагивающих теневой стек).
Инструменты
- ROPgadget — утилита для поиска гаджетов в бинарных файлах.
- Ropper — аналогичный инструмент с поддержкой многих архитектур.
- pwntools — библиотека для Python, включающая функции для построения ROP-цепочек.
- angr — фреймворк для символьного выполнения, способный автоматически генерировать ROP-цепочки.
Источники
- Shacham, H. (2007). «Return-Oriented Programming: Exploits Without Code Injection».
- Checkoway, S., et al. (2010). «Return-Oriented Programming without Returns».
- Carlini, N., & Wagner, D. (2014). «ROP is Still Dangerous: Breaking Modern Defenses».
- Intel Corporation. «Control-flow Enforcement Technology Specification».
- PaX Team. «Documentation for the PaX project».
BFOmetr — база данных и аналитика по компаниям России.
На главную BFOmetr →