ROP - Return Oriented Programing
Основна інформація
Return-Oriented Programming (ROP) - це високорівнева техніка експлуатації, яка використовується для обходу заходів безпеки, таких як No-Execute (NX) або Data Execution Prevention (DEP). Замість впровадження та виконання shellcode, зловмисник використовує шматки коду, вже присутні у бінарному файлі або завантажених бібліотеках, відомі як "гаджети". Кожен гаджет зазвичай закінчується інструкцією ret
та виконує невелику операцію, таку як переміщення даних між регістрами або виконання арифметичних операцій. З'єднавши ці гаджети, зловмисник може скласти навантаження для виконання довільних операцій, ефективно обходячи захист NX/DEP.
Як працює ROP
Перехоплення потоку управління: Спочатку зловмисник повинен перехопити потік управління програми, зазвичай використовуючи переповнення буфера для перезапису збереженого адреси повернення на стеку.
Ланцюжок гаджетів: Потім зловмисник уважно вибирає та з'єднує гаджети для виконання потрібних дій. Це може включати підготовку аргументів для виклику функції, виклик функції (наприклад,
system("/bin/sh")
) та обробку будь-яких необхідних завершальних або додаткових операцій.Виконання навантаження: Коли уразлива функція повертається, замість повернення до законного місця, вона починає виконувати ланцюжок гаджетів.
Інструменти
Зазвичай гаджети можна знайти за допомогою ROPgadget, ropper або безпосередньо з pwntools (ROP).
Приклад ланцюжка ROP в x86
Конвенції виклику для x86 (32-біт)
cdecl: Викликач очищає стек. Аргументи функції додаються на стек у зворотньому порядку (справа наліво). Аргументи додаються на стек зправа наліво.
stdcall: Схоже на cdecl, але викликаний об'єкт відповідає за очищення стеку.
Пошук гаджетів
Спочатку припустимо, що ми ідентифікували необхідні гаджети у бінарному файлі або його завантажених бібліотеках. Гаджети, які нас цікавлять:
pop eax; ret
: Цей гаджет видаляє верхнє значення зі стеку в регістрEAX
та повертається, дозволяючи нам контролюватиEAX
.pop ebx; ret
: Схожий на попередній, але для регіструEBX
, що дозволяє контролюватиEBX
.mov [ebx], eax; ret
: Переміщує значення зEAX
до пам'яті, на яку вказуєEBX
, та повертається. Це часто називається гаджетом write-what-where.Крім того, ми маємо адресу функції
system()
.
Ланцюжок ROP
За допомогою pwntools ми підготовлюємо стек для виконання ланцюжка ROP наступним чином з метою виконання system('/bin/sh')
, зверніть увагу, як починається ланцюжок:
Інструкція
ret
для вирівнювання (необов'язково)Адреса функції
system
(припускаючи вимкнене ASLR та відому libc, додаткова інформація в Ret2lib)Заповнювач для адреси повернення від
system()
Адреса рядка
"/bin/sh"
(параметр для функції system)
Ланцюжок ROP у прикладі x64
Викликові конвенції x64 (64-бітні)
Використовує конвенцію виклику System V AMD64 ABI на системах подібних до Unix, де перші шість цілих або вказівникових аргументів передаються в регістри
RDI
,RSI
,RDX
,RCX
,R8
таR9
. Додаткові аргументи передаються через стек. Результат повертається вRAX
.Викликова конвенція Windows x64 використовує
RCX
,RDX
,R8
таR9
для перших чотирьох цілих або вказівникових аргументів, з додатковими аргументами, що передаються через стек. Результат повертається вRAX
.Регістри: 64-бітні регістри включають
RAX
,RBX
,RCX
,RDX
,RSI
,RDI
,RBP
,RSP
, таR8
доR15
.
Пошук Гаджетів
Для наших цілей давайте зосередимося на гаджетах, які дозволять нам встановити регістр RDI (щоб передати рядок "/bin/sh" як аргумент до system()) і потім викликати функцію system(). Ми припустимо, що ми ідентифікували наступні гаджети:
pop rdi; ret: Викидає верхнє значення стеку в RDI і потім повертається. Істотний для встановлення нашого аргументу для system().
ret: Простий повернення, корисний для вирівнювання стеку в деяких сценаріях.
І ми знаємо адресу функції system().
Ланцюжок ROP
Нижче наведено приклад використання pwntools для налаштування та виконання ланцюжка ROP з метою виконання system('/bin/sh') на x64:
У цьому прикладі:
Ми використовуємо гаджет
pop rdi; ret
для встановленняRDI
на адресу"/bin/sh"
.Ми безпосередньо переходимо до
system()
після встановленняRDI
, з адресою system() в ланцюжку.ret_gadget
використовується для вирівнювання, якщо це потрібно в цільовому середовищі, що є більш поширеним у x64, щоб забезпечити належне вирівнювання стеку перед викликом функцій.
Вирівнювання стеку
ABI x86-64 забезпечує, що стек вирівнюється на 16 байтів, коли виконується інструкція виклику. LIBC, для оптимізації продуктивності, використовує інструкції SSE (наприклад movaps), які вимагають цього вирівнювання. Якщо стек не вирівняний належним чином (означає, що RSP не є кратним 16), виклики функцій, таких як system, не вдасться в ROP ланцюжку. Щоб виправити це, просто додайте ret гаджет перед викликом system у вашому ROP ланцюжку.
Відмінність між x86 та x64
Оскільки x64 використовує регістри для перших кількох аргументів, часто потрібно менше гаджетів, ніж у x86 для простих викликів функцій, але пошук та ланцюження правильних гаджетів може бути складнішим через збільшену кількість регістрів та більший адресний простір. Збільшена кількість регістрів та більший адресний простір у x64 архітектурі надають як можливості, так і виклики для розвитку експлойтів, особливо в контексті Return-Oriented Programming (ROP).
ROP ланцюжок у прикладі ARM64
Основи ARM64 та конвенції виклику
Перевірте наступну сторінку для цієї інформації:
Introduction to ARM64v8Захист від ROP
Stack Canaries: У випадку переповнення буфера, потрібно обійти захист стекового канарейки, щоб переписати вказівники повернення для зловживання ROP ланцюжком.
Відсутність гаджетів: Якщо гаджетів недостатньо, не буде можливо створити ROP ланцюжок.
Техніки на основі ROP
Зверніть увагу, що ROP - це лише техніка для виконання довільного коду. На основі ROP було розроблено багато технік Ret2XXX:
Ret2lib: Використовуйте ROP для виклику довільних функцій з завантаженої бібліотеки з довільними параметрами (зазвичай щось на зразок
system('/bin/sh')
.
Ret2Syscall: Використовуйте ROP для підготовки виклику системного виклику, наприклад
execve
, та виконання довільних команд.
EBP2Ret & EBP Chaining: Перше буде використовувати EBP замість EIP для контролю потоку, а друге схоже на Ret2lib, але в цьому випадку потік контролюється в основному адресами EBP (хоча також потрібно контролювати EIP).
Інші Приклади та Посилання
64 біти, Pie та nx увімкнено, немає канарейки, перезаписати RIP з адресою
vsyscall
з єдиним метою або повернутися до наступної адреси в стеку, яка буде частковим перезаписом адреси для отримання частини функції, яка витікає прапорецьarm64, без ASLR, ROP гаджет для зроблення стеку виконавчим та переходу до shellcode в стеці
Last updated