Четвёртая цифра в 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:
- Kernel в
execve()видит SUID-bit - Устанавливает effective UID процесса = owner-UID файла = 0 (root)
passwdвыполняется с euid=0passwdможет open()/etc/shadow(mode 0640, root:shadow) и обновить хеш дляlevo- Завершается, процесс заканчивается, твоя shell остаётся с обычным euid=1000
Без SUID-механизма — обычный user не смог бы поменять свой пароль, потому что /etc/shadow не writable никому, кроме root. SUID — это контролируемое предоставление privileged operation обычным пользователям.
kernel hardcoded поведение для SUID-flag.
Где встречаются 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.
Классические проблемы:
- Buffer overflow в SUID-бинаре: дай ему длинную строку, переполни стек, выполни shellcode — с euid=0.
- Logic bug: например,
pkexec(CVE-2021-4034, PwnKit) — exploit через manipulation argv. - 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: дроп capabilitiesSGID: для бинарей и для директорий
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= SUID2= SGID1= sticky4+2 = 6= SUID + SGID4+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-сценарии
Когда DE натолкнётся на эти биты.
Попробуй сам
- Найди все SUID-бинари в системе:
sudo find /usr -perm -4000 -type f 2>/dev/null - Посмотри на /tmp:
ls -ld /tmp # drwxrwxrwt - Создай 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 - Проверь, что 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 (внешние диски) — нет.
Главное
- Полная форма 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 вместо.