Короткий ответ

SUID root (chmod u+s) на непакетированном бинаре — локальный root. Снимите инвентарь find / -xdev -perm -4000, сравните с dpkg -S / известным списком Ubuntu, снимите bit с /usr/local, /opt, /home, /tmp. Не трогайте без понимания sudo, su, passwd, newgrp. World-writable SUID — снять bit немедленно. Не заменяйте SUID на chmod 777. Хост host.example (10.0.20.10).

Симптомы и как отличить

  • В /usr/local/bin/cleanup стоит rwsr-xr-x root;
  • бинарь не принадлежит ни одному пакету;
  • SGID на каталогах ожидают (games) vs SGID на скрипте python.
BitСмысл
4000 SUIDeuid владельца файла
2000 SGIDegid; на каталоге — наследование группы
1000 sticky/tmp

Отличие от capabilities getcap: современный ping часто cap, не suid. Отличие от сервиса root: долгоживущий uid 0 vs exec SUID. unit.

Возможные причины

  1. Самописный «чтобы пользователи монтировали».
  2. Старый chmod +s после Permission denied.
  3. Копия с другого дистрибутива.
  4. Малварь в /tmp.
  5. NFS no_root_squash.
  6. Контейнер volume с suid (часто nosuid на mounts — проверьте опции).

Диагностика

sudo find / -xdev -perm -4000 -type f -printf '%m %u %g %p\n' 2>/dev/null | sort
sudo find / -xdev -perm -2000 -type f -printf '%m %u %g %p\n' 2>/dev/null | sort

-xdev не уйдёт на bind-mount данные; пройдите отдельные тома явно (/var, /opt).

Пакет:

dpkg -S /usr/bin/passwd
dpkg -S /usr/local/bin/cleanup 2>&1

Writable + SUID:

sudo find / -xdev -perm -4000 -perm -0002 -type f 2>/dev/null
sudo find / -xdev -perm -4000 -writable -type f 2>/dev/null

Mount nosuid:

findmnt -o TARGET,OPTIONS | grep -E 'nosuid|suid'

/tmp с suid — плохо.

getcap -r /usr/bin /usr/sbin 2>/dev/null | head

Решение

Сценарий A. Чужой бинарь в /usr/local или /opt

sudo chmod u-s /usr/local/bin/cleanup
stat /usr/local/bin/cleanup

Нужные привилегии — systemd unit с User= и capabilities, sudoers Cmnd_Alias, не SUID. Если это бэкап — cron без writable.

Сценарий B. World-writable SUID

Сразу chmod u-s и уберите write for other: права. Считайте инцидент: кто положил, когда.

Сценарий C. Пакетный SUID, которого нет в золотом образе

Сверьте с чистой Ubuntu той же версии. Лишний пакет — apt-get remove. Не chmod u-s на passwd.

Типично легитимны (не исчерпывающий вечный список — сверяйте со своей системой): passwd, su, sudo, newgrp, chfn, chsh, mount/umount (на части релизов уже cap), pkexec. Если сомневаетесь — сравните с эталонной VM, не с форумом 2014 года.

Сценарий D. Нужен privileged bind без SUID

setcap cap_net_bind_service=+ep на конкретный бинарь плюс AppArmor, или proxy. Capabilities тоже риск, но уже не полный uid 0.

mount -o nosuid на /home, /tmp, /opt если политика позволяет (ломает редкий легитимный SUID там — обычно и не нужен).

Как сравнить с эталоном без гадания. Поднимите чистую VM той же lsb_release и find /usr /bin /sbin -perm -4000, сохраните список. Diff с продом покажет лишнее в /usr/local и пакеты, которых нет в золотом образе. Не скачивайте «список SUID Ubuntu» со случайного сайта — релизы отличаются (mount suid vs cap).

dpkg -V на пакет с известным suid покажет изменённый mode. Если passwd без SUID — кто-то уже «ужесточил» и сломает passwd пользователям. Верните пакет: apt-get install --reinstall passwd, не выдумывайте chmod 4755 по памяти без stat с эталона.

Bind-mount /tmp с suid,exec: исправьте fstab на nosuid,nodev,noexec если политика позволяет (ломает редкие легитимные инсталляторы в /tmp — обычно и не нужны на сервере). Проверка findmnt /tmp.

Контейнер runtime часто монтирует с nosuid. Исключение: привилегированный контейнер и bind хостового /. Тогда SUID на хосте снова важен.

После снятия bit проверьте функционал: если это был «удобный ping для user» — пакетный iputils-ping с cap. Если «удобный backup» — sudoers Cmnd_Alias или unit. Пользователи не должны требовать SUID на самописке.

Документ baseline: хэш списка find … -perm -4000 в заявке. Еженедельный diff в мониторинг.

find с -perm -4000 не показывает capabilities. После зачистки SUID прогоните getcap -r /usr/local /opt 2>/dev/null. Неожиданный cap_sys_admin+ep на самописке — тот же класс риска. Снимайте setcap -r файл осознанно.

Не храните эталонный список SUID только в голове. Файл baseline-suid.txt в ansible рядом с плейбуком, diff в CI против find с прода (через ssh admin). Расхождение без тикета — стоп выкладки.

Список эталона обновляйте после смены релиза (22.04→24.04): пакетный набор SUID меняется, diff к старому эталону будет ложноположительным.

Как проверить, что проблема устранена

sudo find /opt /usr/local /home /tmp /var/tmp -xdev -perm -4000 -type f
stat /usr/bin/sudo | grep Uid
findmnt /tmp

Нет SUID в home/opt/tmp. sudo работает у admin. Система грузится, passwd не сломан. Список пакетных SUID сохранён в заявке как baseline.

Если не помогло

  • Bit вернулся после apt: это пакет, не «малварь» автоматически — смотрите changelog.
  • Bit вернулся из ansible mode: '4755'.
  • Overlay/rootfs immutable.
  • Контейнер без nosuid на bind.
  • AppArmor не замена снятию SUID, но DENIED может маскировать тест.

Профилактика

  • Еженедельный diff списка SUID vs эталон.
  • Запрет mode 4xxx в деплое своих бинарей.
  • nosuid на user-writable томах.
  • Аудит пользователей после находки в /home.

FAQ

Снимать SUID с ping?

На новых Ubuntu ping часто с cap, не suid. Смотрите getcap/stat. Не копируйте старые гайды.

SGID на /var/mail

Ожидаемо для почты. Не трогайте пакетное, если не знаете.

find без -xdev

Уйдёт в /proc и сетевые ФС, шум и риск. Используйте -xdev + явные тома.

Можно ли SUID на скрипт bash?

Не работает как хотят, опасно как обман. Не делайте.

pkexec и polkit

Отдельная политика. Не disable polkit вместо инвентаризации SUID.