Leaking libc address with ROP
Швидке резюме
Знайдіть переповнення зсуву
Знайдіть гаджет
POP_RDI
, гаджетPUTS_PLT
та гаджетMAIN
Використовуйте попередні гаджети, щоб витягнути адресу пам'яті функції puts або іншої функції libc та знайти версію libc (завантажте її)
З бібліотекою, обчисліть ROP та експлуатуйте його
Інші навчальні посібники та бінарники для практики
Цей навчальний посібник буде експлуатувати код/бінарник, запропонований у цьому навчальному посібнику: https://tasteofsecurity.com/security/ret2libc-unknown-libc/ Інші корисні навчальні посібники: https://made0x78.com/bseries-ret2libc/, https://guyinatuxedo.github.io/08-bof_dynamic/csaw19_babyboi/index.html
Код
Ім'я файлу: vuln.c
ROP - Leaking LIBC template
Завантажте експлойт і помістіть його в ту ж директорію, що й вразливий бінар, і надайте необхідні дані скрипту:
Leaking libc - template1- Знаходження зсуву
Шаблон потребує зсуву перед продовженням з експлойтом. Якщо будь-який зсув надано, він виконає необхідний код для його знаходження (за замовчуванням OFFSET = ""
):
Виконайте python template.py
, відкриється консоль GDB з програмою, що зазнала збою. Всередині цієї консолі GDB виконайте x/wx $rsp
, щоб отримати байти, які збиралися перезаписати RIP. Нарешті, отримайте зсув за допомогою консолі python:
Після знаходження зсуву (в цьому випадку 40) змініть змінну OFFSET всередині шаблону, використовуючи це значення.
OFFSET = "A" * 40
Інший спосіб - використовувати: pattern create 1000
-- виконати до ret -- pattern seach $rsp
з GEF.
2- Пошук гаджетів
Тепер нам потрібно знайти ROP гаджети всередині бінарного файлу. Ці ROP гаджети будуть корисні для виклику puts
, щоб знайти libc, що використовується, а пізніше для запуску фінального експлойту.
PUTS_PLT
потрібен для виклику функції puts.
MAIN_PLT
потрібен для повторного виклику головної функції після одного взаємодії, щоб використати переповнення знову (безкінечні раунди експлуатації). Він використовується в кінці кожного ROP для повторного виклику програми.
POP_RDI потрібен для передачі параметра до викликаної функції.
На цьому етапі вам не потрібно нічого виконувати, оскільки все буде знайдено pwntools під час виконання.
3- Пошук бібліотеки libc
Тепер час знайти, яка версія бібліотеки libc використовується. Для цього ми збираємося викрити адресу в пам'яті функції puts
, а потім ми будемо шукати, в якій версії бібліотеки знаходиться версія puts за цією адресою.
Щоб це зробити, найважливішим рядком виконуваного коду є:
Це надішле кілька байтів, поки перезаписування RIP не стане можливим: OFFSET
.
Потім він встановить адресу гаджета POP_RDI
, щоб наступна адреса (FUNC_GOT
) була збережена в регістрі RDI. Це тому, що ми хочемо викликати puts, передаючи їй адресу PUTS_GOT
, оскільки адреса в пам'яті функції puts зберігається за адресою, на яку вказує PUTS_GOT
.
Після цього буде викликано PUTS_PLT
(з PUTS_GOT
всередині RDI), щоб puts прочитала вміст всередині PUTS_GOT
(адресу функції puts в пам'яті) і вивела її.
Нарешті, головна функція викликається знову, щоб ми могли знову експлуатувати переповнення.
Таким чином, ми обманули функцію puts, щоб вона вивела адресу в пам'яті функції puts (яка знаходиться в бібліотеці libc). Тепер, коли ми маємо цю адресу, ми можемо шукати, яка версія libc використовується.
Оскільки ми експлуатуємо деякий локальний бінарний файл, не потрібно з'ясовувати, яка версія libc використовується (просто знайдіть бібліотеку в /lib/x86_64-linux-gnu/libc.so.6
).
Але в випадку віддаленої експлуатації я поясню, як ви можете це знайти:
3.1- Пошук версії libc (1)
Ви можете шукати, яка бібліотека використовується на веб-сторінці: https://libc.blukat.me/ Це також дозволить вам завантажити виявлену версію libc
3.2- Пошук версії libc (2)
Ви також можете зробити:
$ git clone https://github.com/niklasb/libc-database.git
$ cd libc-database
$ ./get
Це займе деякий час, будьте терплячими. Для цього нам потрібно:
Ім'я символу libc:
puts
Витік адреси libc:
0x7ff629878690
Ми можемо з'ясувати, яка libc найімовірніше використовується.
Ми отримуємо 2 збіги (ви повинні спробувати другий, якщо перший не працює). Завантажте перший:
Скопіюйте libc з libs/libc6_2.23-0ubuntu10_amd64/libc-2.23.so
до нашого робочого каталогу.
3.3- Інші функції для leak
4- Знаходження адреси libc на основі & експлуатація
На цьому етапі ми повинні знати, яка бібліотека libc використовується. Оскільки ми експлуатуємо локальний бінарний файл, я використаю просто: /lib/x86_64-linux-gnu/libc.so.6
Отже, на початку template.py
змініть змінну libc на: libc = ELF("/lib/x86_64-linux-gnu/libc.so.6") #Встановіть шлях до бібліотеки, коли знаєте його
Надавши шлях до бібліотеки libc, решта експлуатації буде автоматично розрахована.
Всередині функції get_addr
буде розраховано базову адресу libc:
Зверніть увагу, що кінцева адреса бази libc повинна закінчуватися на 00. Якщо це не ваш випадок, ви могли витікати неправильну бібліотеку.
Тоді адреса функції system
та адреса рядка "/bin/sh" будуть обчислені з бази libc та надані бібліотеці libc.
Нарешті, експлойт виконання /bin/sh буде підготовлений для відправки:
Давайте пояснимо цей фінальний ROP.
Останній ROP (rop1
) знову викликав функцію main, тому ми можемо знову експлуатувати переповнення (ось чому OFFSET
знову тут). Потім ми хочемо викликати POP_RDI
, вказуючи на адресу "/bin/sh" (BINSH
), і викликати функцію system (SYSTEM
), оскільки адреса "/bin/sh" буде передана як параметр.
Нарешті, адреса функції exit викликається, щоб процес коректно завершився і не було згенеровано жодних сповіщень.
Таким чином, експлойт виконає _/bin/sh_** оболонку.**
4(2)- Використання ONE_GADGET
Ви також можете використовувати ONE_GADGET , щоб отримати оболонку замість використання system і "/bin/sh". ONE_GADGET знайде в бібліотеці libc спосіб отримати оболонку, використовуючи лише одну ROP адресу.
Однак, зазвичай є деякі обмеження, найпоширеніші та легкі для уникнення - це такі, як [rsp+0x30] == NULL
. Оскільки ви контролюєте значення всередині RSP, вам просто потрібно надіслати ще кілька значень NULL, щоб уникнути обмеження.
EXPLOIT FILE
Ви можете знайти шаблон для експлуатації цієї вразливості тут:
Leaking libc - templateЗагальні проблеми
MAIN_PLT = elf.symbols['main'] не знайдено
Якщо символ "main" не існує. Тоді ви можете знайти, де знаходиться основний код:
і встановіть адресу вручну:
Puts не знайдено
Якщо бінар не використовує Puts, вам слід перевірити, чи використовує він
sh: 1: %s%s%s%s%s%s%s%s: не знайдено
sh: 1: %s%s%s%s%s%s%s%s: не знайдено
Якщо ви знайдете цю помилку після створення всіх експлойтів: sh: 1: %s%s%s%s%s%s%s%s: не знайдено
Спробуйте відняти 64 байти від адреси "/bin/sh":
Last updated