ROP - Return Oriented Programing
Last updated
Last updated
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Return-Oriented Programming (ROP) - це просунута техніка експлуатації, що використовується для обходу заходів безпеки, таких як No-Execute (NX) або Data Execution Prevention (DEP). Замість того, щоб інжектувати та виконувати shellcode, зловмисник використовує фрагменти коду, які вже присутні в бінарному файлі або в завантажених бібліотеках, відомі як "gadgets". Кожен gadget зазвичай закінчується інструкцією ret
і виконує невелику операцію, таку як переміщення даних між реєстрами або виконання арифметичних операцій. Поєднуючи ці gadgets, зловмисник може створити payload для виконання довільних операцій, ефективно обходячи захист NX/DEP.
Перехоплення потоку управління: Спочатку зловмисник повинен перехопити потік управління програми, зазвичай експлуатуючи переповнення буфера, щоб перезаписати збережену адресу повернення в стеку.
Поєднання gadgets: Зловмисник потім ретельно вибирає та поєднує gadgets для виконання бажаних дій. Це може включати налаштування аргументів для виклику функції, виклик функції (наприклад, system("/bin/sh")
) та обробку будь-яких необхідних очищень або додаткових операцій.
Виконання payload: Коли вразлива функція повертається, замість повернення до легітимного місця, вона починає виконувати ланцюг gadgets.
Зазвичай gadgets можна знайти за допомогою ROPgadget, ropper або безпосередньо з pwntools (ROP).
cdecl: Викликач очищає стек. Аргументи функції поміщаються в стек у зворотному порядку (з правого на ліве). Аргументи поміщаються в стек з правого на ліве.
stdcall: Схоже на cdecl, але викликана функція відповідає за очищення стека.
Спочатку припустимо, що ми визначили необхідні gadgets у бінарному файлі або його завантажених бібліотеках. Gadgets, які нас цікавлять:
pop eax; ret
: Цей gadget витягує верхнє значення стека в регістр EAX
і потім повертається, дозволяючи нам контролювати EAX
.
pop ebx; ret
: Схоже на попередній, але для регістра EBX
, що дозволяє контролювати EBX
.
mov [ebx], eax; ret
: Переміщує значення в EAX
у пам'ятеву адресу, на яку вказує EBX
, а потім повертається. Це часто називається write-what-where gadget.
Крім того, у нас є адреса функції system()
.
Використовуючи pwntools, ми готуємо стек для виконання ROP chain наступним чином, намагаючись виконати system('/bin/sh')
, зверніть увагу, як ланцюг починається з:
Інструкція ret
для вирівнювання (необов'язково)
Адреса функції system
(припускаючи, що ASLR вимкнено і libc відома, більше інформації в Ret2lib)
Заповнювач для адреси повернення з system()
Адреса рядка "/bin/sh"
(параметр для функції system)
Використовує 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().
Нижче наведено приклад використання pwntools для налаштування та виконання ROP-ланцюга, що має на меті виконати system('/bin/sh') на x64:
У цьому прикладі:
Ми використовуємо гаджет pop rdi; ret
для встановлення RDI
на адресу "/bin/sh"
.
Ми безпосередньо переходимо до system()
після встановлення RDI
, з адресою system() в ланцюгу.
ret_gadget
використовується для вирівнювання, якщо цільове середовище цього вимагає, що є більш поширеним у x64 для забезпечення правильного вирівнювання стеку перед викликом функцій.
x86-64 ABI забезпечує, що стек вирівняний на 16 байт під час виконання інструкції виклику. LIBC, для оптимізації продуктивності, використовує інструкції SSE (такі як movaps), які вимагають цього вирівнювання. Якщо стек не вирівняний належним чином (означає, що RSP не є кратним 16), виклики до функцій, таких як system, зазнають невдачі в ROP-ланцюзі. Щоб виправити це, просто додайте ret gadget перед викликом system у вашому ROP-ланцюзі.
Оскільки x64 використовує регістри для перших кількох аргументів, це часто вимагає менше гаджетів, ніж x86 для простих викликів функцій, але знаходження та з'єднання правильних гаджетів може бути більш складним через збільшену кількість регістрів і більший адресний простір. Збільшена кількість регістрів і більший адресний простір в архітектурі x64 надають як можливості, так і виклики для розробки експлойтів, особливо в контексті програмування, орієнтованого на повернення (ROP).
Перевірте наступну сторінку для цієї інформації:
Stack Canaries: У випадку BOF, потрібно обійти зберігання canary стеку, щоб перезаписати вказівники повернення для зловживання ROP-ланцюгом.
Брак гаджетів: Якщо недостатньо гаджетів, не буде можливості згенерувати ROP-ланцюг.
Зверніть увагу, що ROP - це лише техніка для виконання довільного коду. На основі ROP було розроблено багато технік Ret2XXX:
Ret2lib: Використовуйте ROP для виклику довільних функцій з завантаженої бібліотеки з довільними параметрами (зазвичай щось на кшталт system('/bin/sh')
.
Ret2Syscall: Використовуйте ROP для підготовки виклику системного виклику, наприклад, execve
, і виконання довільних команд.
EBP2Ret та EBP Chaining: Перший буде зловживати EBP замість EIP для контролю потоку, а другий подібний до Ret2lib, але в цьому випадку потік контролюється переважно адресами EBP (хоча також потрібно контролювати EIP).
64 біт, Pie та nx увімкнено, без canary, перезаписати RIP з адресою vsyscall
з єдиною метою повернення до наступної адреси в стеку, яка буде частковим перезаписом адреси для отримання частини функції, яка витікає прапор
arm64, без ASLR, ROP гаджет для виконання стеку та переходу до shellcode в стеку
Вчіться та практикуйте Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE) Вчіться та практикуйте Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)