Learning Platform
Глоссарий Troubleshooting
Урок 07.05 · 25 мин
Средний
SUIDSGIDSticky bitPrivilege escalation/tmpSpecial permissions

Четвёртая цифра в octal

Помнишь, я говорил chmod 0644 и упоминал «четвёртая цифра — позже»? Время пришло. Полная форма прав в Linux — это 12 бит, не 9:

0 644
^ ^^^
| └── обычные rwx для u/g/o (9 бит)
└── специальные биты (3 бита): SUID + SGID + sticky

Специальные биты:

  • SUID (Set User ID) = octal 4
  • SGID (Set Group ID) = octal 2
  • Sticky bit = octal 1

То есть chmod 4755 file означает: специальные = 4 (SUID), обычные = 755 (rwxr-xr-x). Можно комбинировать: chmod 6755 = SUID + SGID, chmod 1777 = sticky + rwxrwxrwx.

В ls -l они показываются внутри execute-бит:

-rwsr-xr-x    SUID-bit (s в позиции owner execute)
-rwxr-sr-x    SGID-bit (s в позиции group execute)
drwxrwxrwt    sticky bit (t в позиции other execute)
-rwSr--r--    SUID без execute (заглавная S — bit стоит, но execute нет — обычно бесполезно)

Заглавная S/T = бит стоит, но execute не стоит. Маленькая s/t = бит стоит и execute тоже. Это нюанс отображения.

SUID: запуск с правами owner

SUID = «при выполнении бинаря — установить effective UID = UID файла, а не UID запускающего юзера».

Это позволяет обычному user временно получить права owner. Канонический пример — /usr/bin/passwd:

$ ls -l /usr/bin/passwd
-rwsr-xr-x 1 root root 71112 Feb 10 12:34 /usr/bin/passwd

-rwsr-xr-x = mode 4755. Owner=root, SUID есть. Когда обычный user levo запускает passwd:

  1. Kernel в execve() видит SUID-bit
  2. Устанавливает effective UID процесса = owner-UID файла = 0 (root)
  3. passwd выполняется с euid=0
  4. passwd может open() /etc/shadow (mode 0640, root:shadow) и обновить хеш для levo
  5. Завершается, процесс заканчивается, твоя shell остаётся с обычным euid=1000

Без SUID-механизма — обычный user не смог бы поменять свой пароль, потому что /etc/shadow не writable никому, кроме root. SUID — это контролируемое предоставление privileged operation обычным пользователям.

Поток выполнения SUID-бинаря

kernel hardcoded поведение для SUID-flag.

levo вызывает /usr/bin/passwdruid=1000, euid=1000
execve видит SUID-bit, owner=rootkernel: euid=0Это происходит АТОМАРНО внутри execve. Программа стартует уже с поднятым euid.
passwd с euid=0 читает /etc/shadowopen(/etc/shadow, O_RDWR) — OK
passwd проверяет старый парольgetpass + crypt
passwd пишет новый хешwrite() в /etc/shadow
passwd завершаетсяruid=1000 (был), euid=сбрасывается

Где встречаются SUID-бинари

$ find /usr/bin -perm -4000 -type f 2>/dev/null
/usr/bin/passwd
/usr/bin/chsh        # сменить shell в /etc/passwd
/usr/bin/chfn        # сменить GECOS
/usr/bin/sudo
/usr/bin/mount        # монтирование (на Debian, на других дистрибутивах перенесли в /sbin)
/usr/bin/umount
/usr/bin/su
/usr/bin/newgrp      # сменить primary group в сессии

Все эти бинари нужны обычным юзерам, но требуют root-операций под капотом.

Безопасность SUID — головная боль security-команд

SUID — главная цель атакующего на Linux: найди SUID-бинарь с уязвимостью, эксплуатируй — получи root.

Классические проблемы:

  1. Buffer overflow в SUID-бинаре: дай ему длинную строку, переполни стек, выполни shellcode — с euid=0.
  2. Logic bug: например, pkexec (CVE-2021-4034, PwnKit) — exploit через manipulation argv.
  3. PATH injection: SUID-бинарь делает system("foo") без полного пути; атакующий ставит ~/foo в PATH и подсовывает свой.

Поэтому:

  • Не делай свои SUID-программы, если не понимаешь security implications.
  • Для большинства задач есть sudo с гранулярным policy — это safer.
  • Если SUID нужен (CTF, личный инструмент) — пиши на Rust/Go, не C; drop privileges (setuid(getuid())) сразу после получения нужного ресурса.

chmod u+s file и chmod 4xxx

$ chmod u+s myscript     # symbolic: добавить SUID
$ chmod 4755 myscript    # octal: 4 = SUID, 755 = rwxr-xr-x

ВНИМАНИЕ: SUID на shell-скрипты НЕ работает на современном Linux. Kernel игнорирует SUID-bit при execve() интерпретируемых файлов (с shebang) для безопасности — иначе можно было бы подменить interpreter и получить root. SUID работает только на compiled binaries или через wrapper.

Если хочется «скрипт от root», правильнее — sudoers-правило с NOPASSWD.

Linux capabilities: замена SUID-бинарей USER и security в Dockerfile: дроп capabilities

SGID: для бинарей и для директорий

SGID на бинаре работает аналогично SUID, но для group: effective GID становится group-owner файла. Используется редко. Пример — wall (отправить сообщение всем терминалам), которому нужен GID tty.

SGID на директории — это совершенно другая семантика, и она невероятно полезна для DE:

Новые файлы и поддиректории, создаваемые в SGID-директории, автоматически наследуют её group, а не primary group создателя.

$ sudo mkdir /shared
$ sudo chown root:data-team /shared
$ sudo chmod 2775 /shared    # 2 = SGID, 775 = rwxrwxr-x

$ ls -ld /shared
drwxrwsr-x 2 root data-team 4096 May 13 /shared
#    ^-- s в group-execute = SGID

# Теперь levo (member of data-team) создаёт файл:
$ touch /shared/report.csv
$ ls -l /shared/report.csv
-rw-r--r-- 1 levo data-team 0 May 13 report.csv
#                ^^^^^^^^^^ group наследована от dir

Без SGID на dir новый файл был бы levo:levo (primary group создателя), и другие члены data-team не смогли бы его редактировать (group=levo, у них её нет).

SGID + 0775 + umask 0002 = shared folder pattern

Канонический setup для shared work directory:

$ sudo mkdir /opt/etl-jobs
$ sudo chown root:etl-team /opt/etl-jobs
$ sudo chmod 2775 /opt/etl-jobs    # SGID
$ umask 0002                        # новые файлы 0664, dirs 0775

Теперь любой member etl-team создавая файл получит:

  • owner = он сам
  • group = etl-team (унаследовано от SGID)
  • mode = 0664 (rw-rw-r—) — все members группы могут редактировать

Это best practice для команд, работающих с общими ETL-скриптами, конфигами, dashboards.

# Проверка
$ touch /opt/etl-jobs/load_orders.py
$ ls -l /opt/etl-jobs/
-rw-rw-r-- 1 levo etl-team 0 May 13 load_orders.py

Sticky bit: защита /tmp

Sticky bit на директории означает: только owner файла (или root) может его удалить, даже если у других пользователей есть w на саму директорию.

Канонический пример — /tmp:

$ ls -ld /tmp
drwxrwxrwt 18 root root 4096 May 13 /tmp
#         ^-- t в other-execute = sticky bit

# Mode 1777: sticky + rwxrwxrwx
# Любой user может создавать файлы в /tmp.
# Но удалить может только владелец конкретного файла.

Без sticky bit /tmp с правами 0777 был бы катастрофой: любой user мог бы rm /tmp/* и снести temp-файлы других программ. Sticky bit это защищает.

Когда sticky-bit нужен в DE-сценариях

Редко, но бывает: shared upload directory, куда много юзеров кладут CSV-файлы, и не хочется, чтобы кто-то по ошибке удалил чужой:

$ sudo mkdir /shared/uploads
$ sudo chmod 1777 /shared/uploads    # sticky + world-writable
# Любой кладёт файлы, никто не удалит чужие

chmod +t dir — symbolic shortcut.

Комбинирование SUID + SGID + sticky

В octal специальные биты суммируются:

  • 4 = SUID
  • 2 = SGID
  • 1 = sticky
  • 4+2 = 6 = SUID + SGID
  • 4+2+1 = 7 = всё вместе

Полные mode такие:

chmod 4755 file    # SUID
chmod 2755 file    # SGID
chmod 6755 file    # SUID + SGID
chmod 1777 dir     # sticky + world-writable (типа /tmp)
chmod 2775 dir     # SGID на dir (shared folder)
chmod 3775 dir     # SGID + sticky (shared, но не удалять чужое)

Под капотом: где живут эти биты

В inode на ext4/btrfs/xfs i_mode — это 16-битное поле:

| 4 бита   | 3 бита    | 9 бит       |
|----------|-----------|-------------|
| тип файла| SUID,SGID,| rwx u/g/o   |
|          | sticky    |             |

Тип файла: regular, dir, char dev, block dev, fifo, socket, symlink. Special bits и обычные права лежат в одном поле — потому chmod 0644 нужен ведущий ноль, чтобы явно показать «специальных битов нет, не трогай их».

Поиск SUID/SGID на системе

Аудит безопасности часто начинается с inventory всех SUID-бинарей:

# Все SUID-файлы в системе
$ sudo find / -perm -4000 -type f 2>/dev/null

# Все SGID-файлы
$ sudo find / -perm -2000 -type f 2>/dev/null

# SUID+SGID (опасно — двойное elevation)
$ sudo find / -perm -6000 -type f 2>/dev/null

# Sticky-директории
$ sudo find / -perm -1000 -type d 2>/dev/null

Чистая Ubuntu 26.04 имеет около 15-20 SUID-бинарей. Если ты видишь намного больше — это сигнал. Если в SUID появился странный файл в /tmp или /home/$USER/ — это, скорее всего, malware backdoor для post-exploitation.

DE-сценарии

Special bits в DE-практике

Когда DE натолкнётся на эти биты.

sudo, passwd, ssh-agentSUID — стандарт для privileged-командЭти бинари существуют и не трогаются. Просто знай, что у них SUID и почему.
/opt/team-shared/SGID + 0775 + umask 0002Shared dir для команды. Все members группы могут редактировать файлы друг друга.
/tmpsticky + 0777Не делай 'rm -rf /tmp/*' под root — почистится система.
/var/lib/uploads/SGID для group inheritanceКуда несколько сервисов пишут — чтобы все файлы наследовали group приложения.
SUID на твоих скриптахНЕ работает на shell-скриптахИспользуй sudo + sudoers вместо SUID-обёрток.

Попробуй сам

  1. Найди все SUID-бинари в системе:
    sudo find /usr -perm -4000 -type f 2>/dev/null
  2. Посмотри на /tmp:
    ls -ld /tmp     # drwxrwxrwt
  3. Создай SGID-директорию и проверь наследование группы:
    sudo mkdir /tmp/shared
    sudo chown root:users /tmp/shared
    sudo chmod 2775 /tmp/shared
    touch /tmp/shared/myfile
    ls -l /tmp/shared/myfile     # group должна быть users
  4. Проверь, что sticky-bit работает в /tmp:
    sudo -u nobody touch /tmp/not-mine
    rm /tmp/not-mine   # должно упасть: Operation not permitted

macOS-различия

  • macOS поддерживает SUID, SGID и sticky идентично.
  • /tmp на macOS — это symlink на /private/tmp, mode 1777 такой же.
  • SUID-бинари — sudo, passwd, pkexec-аналог. find работает идентично.
  • На APFS SUID работает; на mounted FAT/exFAT (внешние диски) — нет.
Проверка знанийKnowledge check
Ты заметил в директории /tmp файл /tmp/.X11-helper с правами -rwsrwxrwx, owner=root. Что это может значить и что делать?
ОтветAnswer
Это критический red flag, скорее всего — backdoor. Анализ: (1) Расположение в /tmp — типично для post-exploitation malware (writable directory с perceived legitimacy от X11 daemon). (2) SUID-bit + owner root — позволяет любому запустить программу с правами root. (3) Mode 0777 на SUID-binary — атакующий сделал его world-executable. (4) Имя '.X11-helper' с точкой — спрятано от ls без -a, маскируется под системный helper. Действия: НЕ запускать; немедленно изолировать машину от сети (logout SSH ключи могут быть скомпрометированы); сделать file copy для forensics (cp --preserve=all /tmp/.X11-helper /forensics/); запустить strings, file, проверить hash в VirusTotal; найти как файл попал — посмотреть последние логины в /var/log/auth.log, проверить, какие процессы запущены под root; уведомить security-team. Это не парижская задача DE, но знать паттерн стоит, чтобы заметить в продакшен-логах автоматизации.

Главное

  • Полная форма chmod — 12 бит: 3 специальных + 9 обычных.
  • SUID (4xxx) — при execve поднимает effective UID до owner. Используется в sudo, passwd. На shell-скриптах не работает (kernel блокирует).
  • SGID (2xxx) на бинаре — поднимает eGID. На директории — новые файлы наследуют её group. Канонический pattern для shared work folders.
  • Sticky bit (1xxx) на директории — только owner файла может его удалить. /tmp — главный пример.
  • find / -perm -4000 — аудит SUID-бинарей. Странный SUID-файл — это, скорее всего, backdoor.
  • Не делай свои SUID-программы — используй sudo с гранулярным sudoers вместо.

Проверьте понимание

Результат: 0 из 0
Концептуальный
Вопрос 1 из 4. ls -l /usr/bin/passwd показывает '-rwsr-xr-x'. Что означает 's' в позиции owner-execute?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 5