ROP - Return Oriented Programing
Last updated
Last updated
Вивчайте та практикуйте взлом AWS: Навчання HackTricks AWS Red Team Expert (ARTE) Вивчайте та практикуйте взлом GCP: Навчання HackTricks GCP Red Team Expert (GRTE)
Return-Oriented Programming (ROP) - це високорівнева техніка експлуатації, яка використовується для обходу заходів безпеки, таких як No-Execute (NX) або Data Execution Prevention (DEP). Замість впровадження та виконання shellcode, зловмисник використовує шматки коду, вже присутні у бінарному файлі або завантажених бібліотеках, відомі як "гаджети". Кожен гаджет зазвичай закінчується інструкцією ret
та виконує невелику операцію, таку як переміщення даних між регістрами або виконання арифметичних операцій. З'єднавши ці гаджети, зловмисник може скласти навантаження для виконання довільних операцій, ефективно обходячи захист NX/DEP.
Перехоплення потоку управління: Спочатку зловмисник повинен перехопити потік управління програми, зазвичай використовуючи переповнення буфера для перезапису збереженого адреси повернення на стеку.
Ланцюжок гаджетів: Потім зловмисник уважно вибирає та з'єднує гаджети для виконання потрібних дій. Це може включати підготовку аргументів для виклику функції, виклик функції (наприклад, system("/bin/sh")
) та обробку будь-яких необхідних завершальних або додаткових операцій.
Виконання навантаження: Коли уразлива функція повертається, замість повернення до законного місця, вона починає виконувати ланцюжок гаджетів.
Зазвичай гаджети можна знайти за допомогою ROPgadget, ropper або безпосередньо з pwntools (ROP).
cdecl: Викликач очищає стек. Аргументи функції додаються на стек у зворотньому порядку (справа наліво). Аргументи додаються на стек зправа наліво.
stdcall: Схоже на cdecl, але викликаний об'єкт відповідає за очищення стеку.
Спочатку припустимо, що ми ідентифікували необхідні гаджети у бінарному файлі або його завантажених бібліотеках. Гаджети, які нас цікавлять:
pop eax; ret
: Цей гаджет видаляє верхнє значення зі стеку в регістр EAX
та повертається, дозволяючи нам контролювати EAX
.
pop ebx; ret
: Схожий на попередній, але для регістру EBX
, що дозволяє контролювати EBX
.
mov [ebx], eax; ret
: Переміщує значення з EAX
до пам'яті, на яку вказує EBX
, та повертається. Це часто називається гаджетом write-what-where.
Крім того, ми маємо адресу функції system()
.
За допомогою pwntools ми підготовлюємо стек для виконання ланцюжка ROP наступним чином з метою виконання 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, щоб забезпечити належне вирівнювання стеку перед викликом функцій.
ABI x86-64 забезпечує, що стек вирівнюється на 16 байтів, коли виконується інструкція виклику. LIBC, для оптимізації продуктивності, використовує інструкції SSE (наприклад movaps), які вимагають цього вирівнювання. Якщо стек не вирівняний належним чином (означає, що RSP не є кратним 16), виклики функцій, таких як system, не вдасться в ROP ланцюжку. Щоб виправити це, просто додайте ret гаджет перед викликом system у вашому ROP ланцюжку.
Оскільки x64 використовує регістри для перших кількох аргументів, часто потрібно менше гаджетів, ніж у x86 для простих викликів функцій, але пошук та ланцюження правильних гаджетів може бути складнішим через збільшену кількість регістрів та більший адресний простір. Збільшена кількість регістрів та більший адресний простір у x64 архітектурі надають як можливості, так і виклики для розвитку експлойтів, особливо в контексті Return-Oriented Programming (ROP).
Перевірте наступну сторінку для цієї інформації:
Stack Canaries: У випадку переповнення буфера, потрібно обійти захист стекового канарейки, щоб переписати вказівники повернення для зловживання 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 в стеці
Вивчайте та практикуйте взлом AWS:Навчання HackTricks AWS Red Team Expert (ARTE) Вивчайте та практикуйте взлом GCP: Навчання HackTricks GCP Red Team Expert (GRTE)