DDexec / EverythingExec

Вивчайте та практикуйте хакінг AWS: Навчання HackTricks AWS Red Team Expert (ARTE) Вивчайте та практикуйте хакінг GCP: Навчання HackTricks GCP Red Team Expert (GRTE)

Підтримайте HackTricks

Контекст

У Linux для запуску програми вона повинна існувати як файл, вона повинна бути доступна якимось чином через ієрархію файлової системи (це просто як працює execve()). Цей файл може знаходитися на диску або в оперативній пам'яті (tmpfs, memfd), але вам потрібен шлях до файлу. Це дуже спрощує контроль над тим, що запускається в системі Linux, дозволяє виявляти загрози та інструменти зловмисників або запобігати їм спробувати виконати що-небудь своє (наприклад, не дозволяючи непривілейованим користувачам розміщувати виконувані файли де завгодно).

Але ця техніка призначена змінити все це. Якщо ви не можете запустити процес, який вам потрібен... тоді ви захоплюєте один вже існуючий.

Ця техніка дозволяє вам обійти загальні техніки захисту, такі як тільки для читання, noexec, білістинг імен файлів, білістинг хешів...

Залежності

Кінцевий скрипт залежить від наступних інструментів для роботи, вони повинні бути доступні в системі, яку ви атакуєте (зазвичай ви знайдете їх скрізь):

dd
bash | zsh | ash (busybox)
head
tail
cut
grep
od
readlink
wc
tr
base64

Техніка

Якщо ви можете довільно модифікувати пам'ять процесу, то можете захопити його. Це можна використовувати для захоплення вже існуючого процесу та заміни його іншою програмою. Ми можемо досягти цього, використовуючи виклик ptrace() (що вимагає можливості виконання викликів системи або наявності gdb в системі) або, що цікавіше, записуючи в /proc/$pid/mem.

Файл /proc/$pid/mem є однозначним відображенням всього адресного простору процесу (наприклад, від 0x0000000000000000 до 0x7ffffffffffff000 в x86-64). Це означає, що читання або запис у цей файл за зсувом x те саме, що читання або зміна вмісту за віртуальною адресою x.

Зараз ми маємо чотири основні проблеми:

  • Загалом, тільки root та власник програми файлу можуть його змінювати.

  • ASLR.

  • Якщо ми спробуємо прочитати або записати за адресою, яка не відображена в адресному просторі програми, ми отримаємо помилку вводу/виводу.

Ці проблеми мають рішення, які, хоча вони не є ідеальними, є досить хорошими:

  • Більшість оболонок оболонок дозволяють створювати файлові дескриптори, які потім будуть успадковані дочірніми процесами. Ми можемо створити fd, що вказує на файл mem оболонки з правами запису... тому дочірні процеси, які використовують цей fd, зможуть модифікувати пам'ять оболонки.

  • ASLR навіть не проблема, ми можемо перевірити файл maps оболонки або будь-який інший з procfs, щоб отримати інформацію про адресний простір процесу.

  • Тому нам потрібно використовувати lseek() у файлі. З оболонки це не можна зробити, якщо не використовувати погано відомий dd.

Детальніше

Кроки досить прості і не потребують жодних спеціальних знань для їх розуміння:

  • Розібрати бінарний файл, який ми хочемо запустити, та завантажувач, щоб дізнатися, які відображення їм потрібні. Потім створити "shell"код, який буде виконувати, загалом кажучи, ті самі кроки, які робить ядро при кожному виклику execve():

  • Створити вказані відображення.

  • Прочитати бінарні файли в них.

  • Налаштувати дозволи.

  • Нарешті, ініціалізувати стек з аргументами для програми та розмістити допоміжний вектор (необхідний завантажувачем).

  • Перейти до завантажувача та дозволити йому зробити все інше (завантажити бібліотеки, необхідні для програми).

  • Отримати з файлу syscall адресу, на яку процес повернеться після виклику системного виклику, який він виконує.

  • Перезаписати це місце, яке буде виконуваним, нашим "shell"кодом (через mem ми можемо модифікувати незаписувані сторінки).

  • Передати програму, яку ми хочемо запустити, на stdin процесу (її буде read() цим "shell"кодом).

  • На цьому етапі все залежить від завантажувача, щоб завантажити необхідні бібліотеки для нашої програми та перейти до неї.

Перевірте інструмент за посиланням https://github.com/arget13/DDexec

EverythingExec

Є кілька альтернатив для dd, одна з яких, tail, наразі є програмою за замовчуванням для використання lseek() через файл mem (що було єдиним метою використання dd). Зазначені альтернативи:

tail
hexdump
cmp
xxd

Встановивши змінну SEEKER, ви можете змінити використаний пошуковик, наприклад:

SEEKER=cmp bash ddexec.sh ls -l <<< $(base64 -w0 /bin/ls)

Якщо ви знайдете інший дійсний пошуковик, який не реалізований в скрипті, ви все ще можете використовувати його, встановивши змінну SEEKER_ARGS:

SEEKER=xxd SEEKER_ARGS='-s $offset' zsh ddexec.sh ls -l <<< $(base64 -w0 /bin/ls)

Заблокуйте це, EDRs.

Посилання

Last updated