WWW2Exec - atexit()
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)
Сьогодні дуже незвично експлуатувати це!
atexit()
- це функція, до якої передаються інші функції як параметри. Ці функції будуть виконані під час виконання exit()
або повернення з main.
Якщо ви можете модифікувати адресу будь-якої з цих функцій, щоб вказати на shellcode, наприклад, ви отримаєте контроль над процесом, але це наразі складніше.
В даний час адреси функцій, які потрібно виконати, сховані за кількома структурами, і врешті-решт адреса, на яку вони вказують, не є адресами функцій, а зашифрована за допомогою XOR та зміщень з випадковим ключем. Тому наразі цей вектор атаки не дуже корисний, принаймні на x86 та x64_86.
Функція шифрування - це PTR_MANGLE
. Інші архітектури, такі як m68k, mips32, mips64, aarch64, arm, hppa... не реалізують функцію шифрування, оскільки вона повертає те ж саме, що отримала на вхід. Тому ці архітектури можуть бути атаковані за цим вектором.
Ви можете знайти детальне пояснення того, як це працює, за адресою https://m101.github.io/binholic/2017/05/20/notes-on-abusing-exit-handlers.html
Як пояснено в цьому пості, якщо програма завершується за допомогою return
або exit()
, вона виконає __run_exit_handlers()
, яка викличе зареєстровані деструктори.
Якщо програма завершується через функцію _exit()
, вона викличе exit
syscall і обробники виходу не будуть виконані. Тому, щоб підтвердити, що __run_exit_handlers()
виконується, ви можете встановити точку зупинки на ній.
Важливий код - (source):
Зверніть увагу, як map -> l_addr + fini_array -> d_un.d_ptr
використовується для обчислення позиції масиву функцій для виклику.
Є кілька варіантів:
Перезаписати значення map->l_addr
, щоб воно вказувало на підроблений fini_array
з інструкціями для виконання довільного коду
Перезаписати записи l_info[DT_FINI_ARRAY]
та l_info[DT_FINI_ARRAYSZ]
(які більш-менш послідовні в пам'яті), щоб вони вказували на підроблену Elf64_Dyn
структуру, яка знову зробить так, що array
вказуватиме на зону пам'яті, контрольовану атакуючим.
Цей звіт перезаписує l_info[DT_FINI_ARRAY]
з адресою контрольованої пам'яті в .bss
, що містить підроблений fini_array
. Цей підроблений масив містить спочатку адресу одного гаджета, яка буде виконана, а потім різницю між адресою цього підробленого масиву та значенням map->l_addr
, щоб *array
вказував на підроблений масив.
Згідно з основним постом цієї техніки та цим звітом ld.so залишає вказівник на стеку, який вказує на бінарний link_map
в ld.so. З довільним записом можливо перезаписати його і змусити вказувати на підроблений fini_array
, контрольований атакуючим, з адресою до одного гаджета, наприклад.
Наступний код містить ще один цікавий розділ з кодом:
У цьому випадку буде можливим перезаписати значення map->l_info[DT_FINI]
, яке вказує на підроблену ElfW(Dyn)
структуру. Знайдіть більше інформації тут.
__run_exit_handlers
Як пояснено тут, якщо програма завершується через return
або exit()
, вона виконає __run_exit_handlers()
, яка викличе будь-які функції деструкторів, зареєстровані.
Код з _run_exit_handlers()
:
Код з __call_tls_dtors()
:
Для кожної зареєстрованої функції в tls_dtor_list
буде деманглити вказівник з cur->func
і викликати його з аргументом cur->obj
.
Використовуючи функцію tls
з цього форку GEF, можна побачити, що насправді dtor_list
дуже близький до stack canary і PTR_MANGLE cookie. Отже, з переповненням на ньому було б можливим перезаписати cookie і stack canary.
Перезаписуючи PTR_MANGLE cookie, було б можливим обійти функцію PTR_DEMANLE
, встановивши її на 0x00, що означатиме, що xor
, використаний для отримання реальної адреси, є просто адресою, що налаштована. Потім, записуючи на dtor_list
, можна з'єднати кілька функцій з адресою функції та її аргументом.
Нарешті, зверніть увагу, що збережений вказівник не тільки буде xored з cookie, але також буде обернений на 17 біт:
Отже, вам потрібно врахувати це перед додаванням нової адреси.
Знайдіть приклад у оригінальному пості.
__run_exit_handlers
Ця техніка пояснена тут і знову залежить від того, що програма виходить, викликаючи return
або exit()
, тому __run_exit_handlers()
викликається.
Давайте перевіримо більше коду цієї функції:
Змінна f
вказує на initial
структуру, і в залежності від значення f->flavor
будуть викликані різні функції.
В залежності від значення, адреса функції, яку потрібно викликати, буде в іншому місці, але вона завжди буде demangled.
Більше того, в опціях ef_on
та ef_cxa
також можливо контролювати аргумент.
Можна перевірити initial
структуру в сесії налагодження з GEF, запустивши gef> p initial
.
Щоб зловживати цим, вам потрібно або leak, або стерти PTR_MANGLE
cookie, а потім перезаписати запис cxa
в initial з system('/bin/sh')
.
Ви можете знайти приклад цього в оригінальному блозі про техніку.
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)