# DDexec / EverythingExec {{#include ../../../banners/hacktricks-training.md}} ## Контекст У Linux, щоб запустити програму, вона повинна існувати як файл, вона повинна бути доступною якимось чином через ієрархію файлової системи (так працює `execve()`). Цей файл може знаходитися на диску або в оперативній пам'яті (tmpfs, memfd), але вам потрібен шлях до файлу. Це дуже спростило контроль за тим, що запускається на системі Linux, полегшило виявлення загроз і інструментів зловмисників або запобігання їх спробам виконати щось своє (_e. g._ не дозволяючи неправа користувачам розміщувати виконувані файли будь-де). Але ця техніка змінює все це. Якщо ви не можете запустити процес, який хочете... **тоді ви захоплюєте вже існуючий**. Ця техніка дозволяє вам **обійти загальні захисні техніки, такі як тільки для читання, noexec, білий список імен файлів, білий список хешів...** ## Залежності Остаточний скрипт залежить від наступних інструментів, які повинні бути доступні в системі, яку ви атакуєте (за замовчуванням ви знайдете їх усі скрізь): ``` dd bash | zsh | ash (busybox) head tail cut grep od readlink wc tr base64 ``` ## Техніка Якщо ви можете довільно змінювати пам'ять процесу, то ви можете його захопити. Це можна використовувати для захоплення вже існуючого процесу та заміни його на іншу програму. Ми можемо досягти цього або за допомогою системного виклику `ptrace()` (який вимагає, щоб ви мали можливість виконувати системні виклики або щоб gdb був доступний на системі), або, що більш цікаво, записуючи в `/proc/$pid/mem`. Файл `/proc/$pid/mem` є одноосібним відображенням всього адресного простору процесу (_e. g._ від `0x0000000000000000` до `0x7ffffffffffff000` в x86-64). Це означає, що читання з цього файлу або запис у нього за зміщенням `x` є тим самим, що читання з або модифікація вмісту за віртуальною адресою `x`. Тепер у нас є чотири основні проблеми, з якими потрібно зіткнутися: - Загалом, тільки root і власник програми файлу можуть його змінювати. - ASLR. - Якщо ми спробуємо прочитати або записати за адресою, яка не відображена в адресному просторі програми, ми отримаємо помилку I/O. Ці проблеми мають рішення, які, хоча й не ідеальні, є хорошими: - Більшість оболонкових інтерпретаторів дозволяють створення дескрипторів файлів, які потім будуть успадковані дочірніми процесами. Ми можемо створити fd, що вказує на файл `mem` оболонки з правами на запис... тому дочірні процеси, які використовують цей fd, зможуть змінювати пам'ять оболонки. - ASLR навіть не є проблемою, ми можемо перевірити файл `maps` оболонки або будь-який інший з procfs, щоб отримати інформацію про адресний простір процесу. - Тому нам потрібно `lseek()` через файл. З оболонки це не можна зробити, якщо не використовувати infamous `dd`. ### Детальніше Кроки відносно прості і не вимагають жодного роду експертизи для їх розуміння: - Проаналізуйте двійковий файл, який ми хочемо запустити, і завантажувач, щоб дізнатися, які відображення їм потрібні. Потім створіть "shell" код, який, загалом, виконає ті ж кроки, що й ядро при кожному виклику `execve()`: - Створіть зазначені відображення. - Прочитайте двійникові файли в них. - Налаштуйте права. - Нарешті, ініціалізуйте стек з аргументами для програми та розмістіть допоміжний вектор (необхідний завантажувачу). - Стрибніть у завантажувач і дайте йому зробити решту (завантажити бібліотеки, необхідні для програми). - Отримайте з файлу `syscall` адресу, до якої процес повернеться після виконання системного виклику. - Перезапишіть це місце, яке буде виконуваним, нашим shellcode (через `mem` ми можемо змінювати не записувані сторінки). - Передайте програму, яку ми хочемо запустити, в stdin процесу (буде `read()` цим "shell" кодом). - На цьому етапі завантажувачу залишається завантажити необхідні бібліотеки для нашої програми та стрибнути в неї. **Перевірте інструмент на** [**https://github.com/arget13/DDexec**](https://github.com/arget13/DDexec) ## EverythingExec Існує кілька альтернатив `dd`, одна з яких, `tail`, наразі є програмою за замовчуванням, що використовується для `lseek()` через файл `mem` (що було єдиною метою використання `dd`). Ці альтернативи: ```bash tail hexdump cmp xxd ``` Встановлюючи змінну `SEEKER`, ви можете змінити використовуваний seeker, _e. g._: ```bash SEEKER=cmp bash ddexec.sh ls -l <<< $(base64 -w0 /bin/ls) ``` Якщо ви знайдете ще одного дійсного seeker, який не реалізовано в скрипті, ви все ще можете його використовувати, встановивши змінну `SEEKER_ARGS`: ```bash SEEKER=xxd SEEKER_ARGS='-s $offset' zsh ddexec.sh ls -l <<< $(base64 -w0 /bin/ls) ``` Заблокуйте це, EDRs. ## Посилання - [https://github.com/arget13/DDexec](https://github.com/arget13/DDexec) {{#include ../../../banners/hacktricks-training.md}}