BROP - Blind Return Oriented Programming
Reading time: 6 minutes
tip
Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Підтримайте HackTricks
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на github.
Основна інформація
Мета цієї атаки полягає в тому, щоб зловживати ROP через переповнення буфера без будь-якої інформації про вразливий бінарний файл.
Ця атака базується на наступному сценарії:
- Вразливість стека та знання про те, як її викликати.
- Серверний додаток, який перезапускається після збою.
Атака
1. Знайти вразливий офсет відправляючи ще один символ, поки не буде виявлено збій сервера
2. Брутфорс канарки для її витоку
3. Брутфорс збережених адрес RBP та RIP у стеку для їх витоку
Ви можете знайти більше інформації про ці процеси тут (BF Forked & Threaded Stack Canaries) та тут (BF Addresses in the Stack).
4. Знайти стоп-гаджет
Цей гаджет в основному дозволяє підтвердити, що щось цікаве було виконано гаджетом ROP, оскільки виконання не призвело до збою. Зазвичай цей гаджет буде чимось, що зупиняє виконання і розташоване в кінці ланцюга ROP, коли шукають гаджети ROP для підтвердження виконання конкретного гаджета ROP.
5. Знайти гаджет BROP
Ця техніка використовує гаджет ret2csu. І це тому, що якщо ви отримуєте доступ до цього гаджета посеред деяких інструкцій, ви отримуєте гаджети для контролю rsi
та rdi
:
 (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png)
Це будуть гаджети:
pop rsi; pop r15; ret
pop rdi; ret
Зверніть увагу, як з цими гаджетами можна контролювати 2 аргументи функції для виклику.
Також зверніть увагу, що гаджет ret2csu має дуже унікальний підпис, оскільки він буде витягувати 6 регістрів зі стеку. Тому відправляючи ланцюг, як:
'A' * offset + canary + rbp + ADDR + 0xdead * 6 + STOP
Якщо STOP виконується, це в основному означає, що адреса, яка витягує 6 регістрів зі стеку, була використана. Або що використана адреса також була адресою STOP.
Щоб усунути цю останню опцію, виконується новий ланцюг, як наступний, і він не повинен виконувати гаджет STOP, щоб підтвердити, що попередній дійсно витягнув 6 регістрів:
'A' * offset + canary + rbp + ADDR
Знаючи адресу гаджета ret2csu, можна вивести адресу гаджетів для контролю rsi
та rdi
.
6. Знайти PLT
Таблицю PLT можна шукати з 0x400000 або з витягнутої адреси RIP зі стеку (якщо PIE використовується). Записи таблиці відокремлені на 16B (0x10B), і коли викликається одна функція, сервер не зривається, навіть якщо аргументи неправильні. Також перевірка адреси запису в PLT + 6B також не призводить до збою, оскільки це перший код, що виконується.
Отже, можна знайти таблицю PLT, перевіряючи наступні поведінки:
'A' * offset + canary + rbp + ADDR + STOP
-> немає збою'A' * offset + canary + rbp + (ADDR + 0x6) + STOP
-> немає збою'A' * offset + canary + rbp + (ADDR + 0x10) + STOP
-> немає збою
7. Знайти strcmp
Функція strcmp
встановлює регістр rdx
на довжину рядка, що порівнюється. Зверніть увагу, що rdx
є третім аргументом, і нам потрібно, щоб він був більше 0, щоб пізніше використовувати write
для витоку програми.
Можна знайти місце розташування strcmp
в PLT на основі його поведінки, використовуючи той факт, що ми тепер можемо контролювати 2 перші аргументи функцій:
- strcmp(<non read addr>, <non read addr>) -> збій
- strcmp(<non read addr>, <read addr>) -> збій
- strcmp(<read addr>, <non read addr>) -> збій
- strcmp(<read addr>, <read addr>) -> немає збою
Це можна перевірити, викликавши кожен запис таблиці PLT або використовуючи PLT повільний шлях, який в основному полягає в виклику запису в таблиці PLT + 0xb (що викликає dlresolve
) з наступним у стеку номер запису, який потрібно перевірити (починаючи з нуля), щоб просканувати всі записи PLT з першого:
- strcmp(<non read addr>, <read addr>) -> збій
b'A' * offset + canary + rbp + (BROP + 0x9) + RIP + (BROP + 0x7) + p64(0x300) + p64(0x0) + (PLT + 0xb ) + p64(ENTRY) + STOP
-> Призведе до збою- strcmp(<read addr>, <non read addr>) -> збій
b'A' * offset + canary + rbp + (BROP + 0x9) + p64(0x300) + (BROP + 0x7) + RIP + p64(0x0) + (PLT + 0xb ) + p64(ENTRY) + STOP
- strcmp(<read addr>, <read addr>) -> немає збою
b'A' * offset + canary + rbp + (BROP + 0x9) + RIP + (BROP + 0x7) + RIP + p64(0x0) + (PLT + 0xb ) + p64(ENTRY) + STOP
Пам'ятайте, що:
- BROP + 0x7 вказує на
pop RSI; pop R15; ret;
- BROP + 0x9 вказує на
pop RDI; ret;
- PLT + 0xb вказує на виклик dl_resolve.
Знайшовши strcmp
, можна встановити rdx
на значення більше 0.
tip
Зверніть увагу, що зазвичай rdx
вже міститиме значення більше 0, тому цей крок може бути не обов'язковим.
8. Знайти Write або еквівалент
Нарешті, потрібен гаджет, який ексфільтрує дані, щоб ексфільтрувати бінарний файл. І в цей момент можна контролювати 2 аргументи та встановити rdx
більше 0.
Є 3 загальні функції, які можна зловживати для цього:
puts(data)
dprintf(fd, data)
write(fd, data, len(data)
Однак оригінальна стаття згадує лише про write
, тому давайте поговоримо про це:
Поточна проблема полягає в тому, що ми не знаємо, де функція write знаходиться всередині PLT і ми не знаємо номер fd, щоб надіслати дані до нашого сокету.
Однак ми знаємо, де знаходиться таблиця PLT, і можна знайти write на основі його поведінки. І ми можемо створити кілька з'єднань з сервером і використовувати високий FD, сподіваючись, що він відповідає деяким з наших з'єднань.
Поведінкові сигнатури для знаходження цих функцій:
'A' * offset + canary + rbp + (BROP + 0x9) + RIP + (BROP + 0x7) + p64(0) + p64(0) + (PLT + 0xb) + p64(ENTRY) + STOP
-> Якщо є дані, що виводяться, тоді було знайдено puts'A' * offset + canary + rbp + (BROP + 0x9) + FD + (BROP + 0x7) + RIP + p64(0x0) + (PLT + 0xb) + p64(ENTRY) + STOP
-> Якщо є дані, що виводяться, тоді було знайдено dprintf'A' * offset + canary + rbp + (BROP + 0x9) + RIP + (BROP + 0x7) + (RIP + 0x1) + p64(0x0) + (PLT + 0xb ) + p64(STRCMP ENTRY) + (BROP + 0x9) + FD + (BROP + 0x7) + RIP + p64(0x0) + (PLT + 0xb) + p64(ENTRY) + STOP
-> Якщо є дані, що виводяться, тоді було знайдено write
Автоматичне експлуатація
Посилання
- Оригінальна стаття: https://www.scs.stanford.edu/brop/bittau-brop.pdf
- https://www.ctfrecipes.com/pwn/stack-exploitation/arbitrary-code-execution/code-reuse-attack/blind-return-oriented-programming-brop
tip
Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Підтримайте HackTricks
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на github.