- PVSM.RU - https://www.pvsm.ru -

Что будет, если переименовать суперпользователя? Экспериментируем, удивляемся и расстраиваемся…

Что будет, если переименовать суперпользователя? Экспериментируем, удивляемся и расстраиваемся… - 1

В интернете много желающих перебирать пароли к SSH, чтобы получить мощности вашего сервера [1] безвозмездно. Как это можно предотвратить? Отключить вход по паролю? Лениво. Использовать нестандартный порт? Не поможет. Поставить fail2ban? Скучно. Переименовать root? Вот это хорошая идея!

На профильных площадках можно встретить вопрос о том, как переименовать суперпользователя, и теоретические ответы с предупреждением о потенциальной деструктивности этого действа. В этой статье я расскажу, что может сломаться в теории и на практике.

Примечание: для понимания статьи требуются минимальные познания в операционных системах семейств Linux или UNIX.

Для операционных систем семейства *NIX написано много программ. Протестировать их все не получится. Что можно сделать? Разобраться как операционная система (ОС) работает в многопользовательском режиме. Начнем с логического начала — загрузим ОС. Этот процесс можно разбить на следующие этапы:

  • загрузка ядра (Kernel),
  • инициализация служб,
  • вход в систему.

Получилось кратко. Рассмотрим каждый из этапов.

Используйте навигацию, если не хотите читать текст полностью:

Пользователи в пространстве ядра [2]
Пространство пользователя [3]
Интерактивный уровень [4]
Рубрика «Эксперименты» [5]
Где суперпользователь не root? [6]

Пользователи в пространстве ядра


Ядро — это основа операционной системы. Оно загружается первым, инициализирует доступные внешние устройства и распределяет доступные вычислительные ресурсы между потребителями. В многопользовательских системах, как следует из названия, может существовать более одного пользователя, поэтому ядро должно обеспечивать разграничение прав доступа.

Где применяется разграничение прав доступа? В файловой системе:

# ls -la
total 645
drwxrwxrwx 9 root      256 Sep 22 05:49 .
drwxrwxrwx 9 root      256 Sep 22 05:49 ..
drwxrwxr-x 2 bin      2512 Sep 22 05:32 bin
-rwxr-xr-x 1 bin      8986 Jun  8  1979 boot
drwxrwxr-x 2 bin       160 Sep 22 05:47 dev
drwxrwxr-x 2 bin       336 Sep 22 05:47 etc
-rwxr-xr-x 1 sys     53302 Jun  8  1979 hphtunix
-rwxr-xr-x 1 sys     52850 Jun  8  1979 hptmunix
drwxrwxr-x 2 bin       320 Sep 22 05:33 lib
drwxrwxr-x 2 root       96 Sep 22 05:46 mdec
-rwxr-xr-x 1 root    50990 Jun  8  1979 rkunix
-rwxr-xr-x 1 root    51982 Jun  8  1979 rl2unix
-rwxr-xr-x 1 sys     51790 Jun  8  1979 rphtunix
-rwxr-xr-x 1 sys     51274 Jun  8  1979 rptmunix
drwxrwxr-x 2 root      112 Sep 22 06:52 tmp
drwxrwxr-x11 root      176 Sep 22 05:46 usr

Что ограничивают в правах? Программы:

firemoon@DESKTOP-7S33FAN:~$ ps u
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
firemoon    12  0.0  0.0   9172  5244 pts/0    Ss   13:56   0:00 -bash
firemoon    82  0.0  0.0  10456  3308 pts/0    R+   14:04   0:00 ps u

Драйверы файловых систем и планировщик процессорного времени — это части ядра операционной системы. Поэтому ядро имеет ограниченную информацию о пользователе. Если быть точным, то пользователь в пространстве ядра — это цифра. Давайте обратимся к коду.

В ядре Linux метаинформация процесса хранится в структуре task_struct [7]. Описание этой структуры занимает более 700 строк кода, поэтому вот краткая выжимка:

struct task_struct {
        /* Тут много пропущено */
        /* Process credentials: */
        /* Tracer's credentials at attach: */
        const struct cred __rcu                *ptracer_cred;
        /* Objective and real subjective task credentials (COW): */
        const struct cred __rcu                *real_cred;
        /* Effective (overridable) subjective task credentials (COW): */
        const struct cred __rcu                *cred;
        /* Тут пропущено больше */
};

Сама структура cred [8] описана в другом файле и выглядит не менее солидно:

struct cred {
        atomic_long_t        usage;
        kuid_t                uid;                /* real UID of the task */
        kgid_t                gid;                /* real GID of the task */
        kuid_t                suid;                /* saved UID of the task */
        kgid_t                sgid;                /* saved GID of the task */
        kuid_t                euid;                /* effective UID of the task */
        kgid_t                egid;                /* effective GID of the task */
        kuid_t                fsuid;                /* UID for VFS ops */
        kgid_t                fsgid;                /* GID for VFS ops */
        /* Тут много пропущено */
} __randomize_layout;

Смотрим на структуры данных kuid_t и kgid_t [9]:

typedef struct {
        uid_t val;
} kuid_t;
typedef struct {
        gid_t val;
} kgid_t;

Так, теперь разбираем uid_t и gid_t [10]:

typedef __kernel_uid32_t        uid_t;
typedef __kernel_gid32_t        gid_t;

Ну и в конце выбираем одно из платформозависимых определений [11]:

#ifndef __kernel_uid32_t
typedef unsigned int        __kernel_uid32_t;
typedef unsigned int        __kernel_gid32_t;
#endif

Аналогично: информация о владельце и группе-владельце хранится в структуре inode [12]. Она описывает файл на файловой системе:

struct inode {
        umode_t                        i_mode;
        unsigned short                i_opflags;
        kuid_t                        i_uid;
        kgid_t                        i_gid;
        unsigned int                i_flags;
        /* Тут много пропущено */
} __randomize_layout;

Ядро резервирует два идентификатора.

  • 0 — идентификатор суперпользователя. Пользователь с этим идентификатором игнорирует все (или почти) проверки прав доступа.
  • (uid_t)-1 (в беззнаковом — это максимальное значение типа данных) — обозначение ошибки.

Что из этого следует? Ядро операционной системы не использует имена пользователей и наша шалость с переименованием никак не повлияет на ранние этапы загрузки ОС.

Ядро по готовности запускает главный процесс в пространстве пользователя — init.

Что будет, если переименовать суперпользователя? Экспериментируем, удивляемся и расстраиваемся… - 2

Пространство пользователя

Что будет, если переименовать суперпользователя? Экспериментируем, удивляемся и расстраиваемся… - 3

Отвлеченная шутка к началу раздела.

Процесс init (сокращенно от initialization) обычно имеет идентификатор процесса (pid) равный единице и запускается ядром. В каноническом UNIX инициализация состояла из следующих шагов:

  • запуск скрипта /etc/rc,
  • подключение к физическим или виртуальным терминалам (getty),
  • запуск скрипта /etc/rc.local (специфично для BSD).

В современных операционных системах семейства Linux вместо классического init используется монструозный systemd. Тем не менее, нет значения, какая подсистема инициализации используется, если сервисы не смогут запуститься. Давайте разбираться, что и где может пойти не так.

Есть старая админская хитрость: вместо init «подставить» /bin/sh. Это позволит получить интерактивный доступ к ОС без аутентификации. Это известное решение для сброса забытого пароля суперпользователя.

Ядро «волшебным» образом создает первый процесс от имени суперпользователя. Все остальные процессы — его дети. «Размножение» процессов в *NIX происходит в два системных вызова:

  • fork(2) — клонирование текущего процесса,
  • execve(2) — выполнение указанного исполняемого файла.

Вот так выглядит полный пример:

#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
int main(int argc, char *argv[], char *envp[]) {
    int pid = fork();
    switch(pid) {
        case -1:
            /* Ошибка */
            perror("fork");
            return -1;
        case 0:
            /* Ветка, доступная ребенку */
            char* child_argv[] = {"/bin/echo", "Hello, World!", NULL};
            /* Вызываем /bin/echo с указанными аргументами */
            execve("/bin/echo", child_argv, envp);
            /* Вообще-то дальше код недостижим. Но если достижим, то это ошибка */
            perror("execve");
            return -2;
        default:
            /* Ветка, доступная родителю. pid - идентификатор ребенка */
            printf("Child pid = %dn", pid);
    }
    /* Хорошим тоном будет дождаться выполнения дочернего процесса */
    int status;
    waitpid(pid, &status, 0);
    printf("Child process exited with exit code: %dn", WEXITSTATUS(status));
    return 0;
}

В этом примере нет ничего про пользователей, потому что это происходит неявно. Системный вызов fork(2) занимается копированием, поэтому дочерний процесс имеет ту же информацию о пользователе, что и родительский. Системный вызов execve(2) находит исполняемый файл и проверяет его права доступа.

Если у программы в правах есть бит SUID, то execve(2) всегда запускает программу от имени владельца файла. Но эту особенность рассмотрим позже.

Итак, init запускает служебные процессы, но не каждому процессу полагаются максимальные права в системе. Ядро позволяет переключиться на любого пользователя. Этим занимается системный вызов setuid(2):

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
int main(int argc, char *argv[], char *envp[]) {
    if(setuid(747) < 0) {
        perror("setuid");
        return -1;
    }
    char* child_argv[] = {"id", NULL};
    execve("/usr/bin/id", child_argv, envp);
    return 0;
}

Как говорилось ранее, ядро оперирует только идентификаторами, поэтому setuid(2) принимает числа. Этот системный вызов позволяет изменить пользователя, от имени которого выполняется программа. В случае суперпользователя — добровольно отказаться от своих прав.

Системный вызов setuid(2) позволяет представляться разными пользователями, поэтому он доступен только для суперпользователя:

firemoon@ubuntu:/tmp$ ./a.out
setuid: Operation not permitted
root@ubuntu:/tmp$ ./a.out
uid=747 gid=0(root) groups=0(root)

У Linux есть отступления от традиционной для UNIX системы разграничения прав. В частности, существует система возможностей, capabilities(7), которая позволяет более тонко настраивать права и функции пользователей. В терминах этой системы setuid(2) доступен при наличии атрибута CAP_SETUID.

Опытный администратор наверняка отметит, что в systemd-юнитах указывается имя пользователя, а не его числовой идентификатор. Как имя превращается в число?

Управление пользователями вне ядра берет на себя стандартная библиотека С, libc или glibc (в зависимости от используемой ОС). Функции getpwnam(3) и getpwuid(3) позволяют получить запись о пользователе по имени (логину) или числовому идентификатору.

По умолчанию все пользователи ОС хранятся в локальной базе данных, файле /etc/passwd, однако современные операционные системы позволяют сконфигурировать обращение к удаленным БД, например через LDAP.

Из-за соображений безопасности хэши паролей пользователей вынесли из общедоступного /etc/passwd в /etc/shadow с ограничением на чтение не суперпользователю.

Это первая потенциальная точка отказа. Если при запуске демона явно указано имя суперпользователя root, то система не найдет его, а демон не будет запущен. Можно предположить оптимистичный вариант. Допустим, что в реализации init есть микро оптимизация — игнорировать явное указание на пользователя root. Тогда, может, ничего не сломается.

Резюмируем. При загрузке ОС могут сломаться сервисы, в которых явно прописан пользователь root. Понадеемся, что этого не случится, и перейдем к интерактивному взаимодействию с системой.

Интерактивный уровень


После успешной загрузки системы нас встретит виртуальный терминал или графическая оболочка, которая предложит ввести логин, а затем — пароль.

Самое время рассказать про SUID-бит и почему он нужен. Аутентификацией и созданием сессии пользователя занимается программа login(1). Она запускается от имени суперпользователя, принимает данные для входа и проверяет их. Если пара логин-пароль существует в системе, login(1) переключается в указанного пользователя через setuid(2) и запускает интерпретатор командной строки.

Как было сказано ранее, все дочерние процессы, созданные в командной строке, будут запущены от имени того же пользователя. Также мы уже знаем, что setuid(2) в классическом *NIX может запускать только суперпользователь. Безвыходная ситуация? Нет. Бит SUID — это особый механизм, который позволяет запускать программу с правами владельца файла.

$ ls -l /usr/bin/su*
-rwsr-xr-x 1 root root 55672 Feb 21  2022 /usr/bin/su
-rwsr-xr-x 1 root root 232416 Apr  3  2023 /usr/bin/sudo
-rwxr-xr-x 1 root root  35232 Feb  7  2022 /usr/bin/sum

Обратите внимание на право s вместо x для программ su и sudo. Это и есть бит SUID. Это значит, что execve(2) всегда будет запускать эти программы от имени владельца файла, в данном случае — от root. Этот механизм позволяет запускать программы «от администратора». Вот показательный, но вредный пример:

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
int main(int argc, char *argv[], char *envp[]) {
    uid_t uid = getuid();
    if(uid == 0) {
        printf("We are root! pid = %dn", getpid());
        return 0;
    }
    printf("Let's request root access! pid = %dn", getpid());
    char* child_argv[] = {"su", "-c", argv[0], NULL};
    execve("/usr/bin/su", child_argv, envp);
    return 0;
}

На выходе получаем это:

ubuntu@ubuntu-2204:/tmp$ ./a.out
Let's request root access! pid = 3354
Password:
We are root! pid = 3355

В своем канале [13] я писал про повышение через перерождение. Если хотите читать краткие познавательные заметки раньше, чем выходят полноценные тексты на Хабр, — подписывайтесь.

Пример использует программу su, которая по умолчанию переключает в пользователя root, если имени пользователя нет в аргументах. Аналогично имя суперпользователя жестко прописано в программе sudo. Это создает угрозу для shell-скриптов, которые хотят выполнить что-либо от имени администратора. Пример:

# Было
sudo apt update
# Стало
sudo -u <новое имя суперпользователя> apt update

Также интерпретатор командной строки предлагает переменную окружения, которая содержит имя пользователя:

root@ubuntu-2204:~# echo $USER
root

Это не мотивирует делать корректную проверку по числовому идентификатору пользователя. Никто ведь не будет переименовывать root, правда? Но если вы об этом задумались, то вот команды, которые работают с UID, а не с именем:

# Узнать UID текущего пользователя, для проверок на суперпользователя
id -u
# Переключение на пользователя с uid=0
sudo -u '#0' -i
# Переключение на пользователя с uid=0 при помощи su:
su - $(id -un 0)

Я взял первый попавшийся скрипт, установщик Docker Engine [14], и он собрал джекпот: проверил суперпользователя по имени и su/sudo без аргументов.

if [ "$user" != 'root' ]; then
    if command_exists sudo; then
        sh_c='sudo -E sh -c'
    elif command_exists su; then
        sh_c='su -c'
    else
        cat >&2 <<-'EOF'
        Error: this installer needs the ability to run commands as root.
        We are unable to find either "sudo" or "su" available to make this happen.
        EOF
        exit 1
    fi
fi

Резюмируем. Скорее всего, сломаются shell-скрипты, которые используют программы для повышения привилегий su, sudo или аналогичные. Это, конечно, решается редактированием скриптов или созданием псевдонима, но универсального решения может не быть.

alias sudo='sudo -u <новое имя суперпользователя>'

Что-то сломается, что-то — нет. Пора переходить к практике.

Рубрика «Эксперименты»

Ubuntu 22.04

Ubuntu — это моя рабочая операционная система, поэтому практическую часть решил начать с нее. Сперва я начал с версии на базе графической оболочки. Переименовать суперпользователя достаточно просто — я выбрал имя void.

  1. Переименовываем root в void в файле /etc/passwd.
  2. Переименовываем root в void в файле /etc/shadow.
  3. Перезагружаем ОС, чтобы все компоненты системы гарантированно узнали об изменениях.

Операционная система никак не препятствует изменениям:

Что будет, если переименовать суперпользователя? Экспериментируем, удивляемся и расстраиваемся… - 4

Вот что вас ждет.

После перезагрузки система теряет работоспособность для конечного пользователя.

  • Login Manager отказывается запускаться. Графический интерфейс входа на tty1 не загружается.
  • Не запускаются виртуальные терминалы tty2 и прочие. Ctrl+Alt+F2 не поможет зайти в систему.
  • Если у вас случайно оказался установлен SSH-сервер на ОС с графическим интерфейсом, это тоже не поможет. NetworkManager откажется запускаться и подключения к сети не произойдет.

Единственная возможность зайти в систему — загрузиться в режим восстановления. Отладка в таком режиме показалась совершенно бесперспективным занятием, поэтому я попытал счастья в серверной редакции Ubuntu 22.04. И она запустилась после перезагрузки! Но, как и ожидалось, не полностью.

Служба User Login Management (systemd-logind) по-прежнему отказывается запускаться, поэтому доступен только один виртуальный терминал, tty1. При этом в логах есть таймаут, но нет явной ошибки:

Feb 04 19:43:05 ubuntu-2204 systemd[1]: Starting User Login Management...
Feb 04 19:43:05 ubuntu-2204 systemd-logind[1205]: New seat seat0.
Feb 04 19:43:05 ubuntu-2204 systemd-logind[1205]: Watching system buttons on /dev/input/event0 (Power Button)
Feb 04 19:43:05 ubuntu-2204 systemd-logind[1205]: Watching system buttons on /dev/input/event1 (Sleep Button)
Feb 04 19:43:05 ubuntu-2204 systemd-logind[1205]: Watching system buttons on /dev/input/event2 (AT Translated Set 2 keyboard)
Feb 04 19:44:36 ubuntu-2204 systemd[1]: systemd-logind.service: start operation timed out. Terminating.
Feb 04 19:44:36 ubuntu-2204 systemd[1]: systemd-logind.service: Failed with result 'timeout'.
Feb 04 19:44:36 ubuntu-2204 systemd[1]: Failed to start User Login Management.
Feb 04 19:44:36 ubuntu-2204 systemd[1]: systemd-logind.service: Scheduled restart job, restart counter is at 7.
Feb 04 19:44:36 ubuntu-2204 systemd[1]: Stopped User Login Management.

Ошибка связана с D-Bus, системой межпроцессного взаимодействия, которая активно используется с systemd и графической оболочкой GNOME. В описании systemd-logind.service можно найти декларацию для D-Bus:

[Service]
BusName=org.freedesktop.login1

Похоже, что какие-то механизмы D-Bus завязаны на имя суперпользователя, из-за чего программа не может подключиться к шине, а systemd не видит процесса по указанному имени и перезапускает службу. Сломанный D-Bus также влияет на обращения к systemctl из-под обычного пользователя:

ubuntu@ubuntu-2204:~$ reboot
Failed to set wall message, ignoring: Connection timed out
Failed to reboot system via logind: Connection timed out
Failed to open initctl fifo: Permission denied
Failed to talk to init daemon.

Дополнительный артефакт — это бесправный пользователь root. Я переименовал пользователя root, значит после перезагрузки его не должно существовать. Но он существует и его идентификатор отличен от нуля. Пользователь появляется даже при загрузке в режим восстановления:

ubuntu@ubuntu-2204:~$ getent passwd root
root:x:998:0::/root:/bin/bash

Это выглядит как интересный троллинг молодых системных администраторов, который принуждает думать. Смотрите сами:

ubuntu@ubuntu-2204:~$ sudo apt update
[sudo] password for ubuntu:
Reading package lists... Done
E: Could not open lock file /var/lib/apt/lists/lock - open (13: Permission denied)
E: Unable to lock directory /var/lib/apt/lists/
W: Problem unlinking the file /var/cache/apt/pkgcache.bin - RemoveCaches (13: Permission denied)
W: Problem unlinking the file /var/cache/apt/srcpkgcache.bin - RemoveCaches (13: Permission denied)

Таким образом, команды su и sudo будут корректно работать, то есть переключать в пользователя root, но результат выполнения команды будет неожиданным.

Последнее замечание: при установке пакетов через пакетный менеджер появляется уже знакомая ошибка, которая притормаживает процесс примерно на 30 секунд.

Processing triggers for man-db (2.10.2-1) ...
Error: Timeout was reached
Scanning processes...

В итоге простое переименование суперпользователя хорошо ломает Ubuntu, даже серверную. Ошибка явно связана с D-Bus и systemctl, которые сейчас, кажется, в каждом первом дистрибутиве Linux. Чего же ждать дальше?

Debian 9

Что будет, если переименовать суперпользователя? Экспериментируем, удивляемся и расстраиваемся… - 5

ОС Debain — это основа для Ubuntu. Может, проблема с D-Bus связана с каким-то особенностями Ubuntu? Нет. Несколько служб «упали», виртуальных терминалов нет. Симптомы точь-в-точь такие же. Тогда следующий шаг — другое семейство дистрибутивов.

Manjaro Linux (Arch Linux)

Методом «научного тыка» следующей для проверки я выбрал Arch Linux. Этот дистрибутив отличается подходом rolling release, который обещает самые свежие версии ПО. Для теста я взял дистрибутив Manjaro Linux [15] с графической оболочкой xfce. Далее — переименование root по уже известной схеме. Система вновь не препятствует деструктивным действиям.

Что будет, если переименовать суперпользователя? Экспериментируем, удивляемся и расстраиваемся… - 6

Момент истины.

И здесь я немного удивился. Не упал ни один из systemd-юнитов. Коммуникация с systemd от имени обычного пользователя через утилиты reboot и shutdown работает как раньше. Пакетный менеджер работает тоже в норме. Хотя некоторые сообщения об ошибке оказывают психологическое давление.

[arch@arch-virtualbox ~]$ sudo pacman -S clang
[sudo] пароль для arch: 
ошибка: для выполнения этой операции требуются права root.

Окей, двигаемся дальше, в сторону CentOS.

CentOS 9 Stream

Основной проблемный компонент — D-Bus. Но systemd может ограниченно работать без D-Bus, а вот оболочка GNOME — нет. Посмотрим на еще одно семейство ОС — CentOS. Для эксперимента выберем CentOS 9 Stream с графической оболочкой GNOME.

CentOS активно сопротивляется: файл /etc/shadow имеет права 000 и доступ ограничен через SELinux.

centos@localhost:~$ ls -l /etc/shadow
----------. 1 root root 1122 фев  4 22:51 /etc/shadow

Но проблема легко решается командой chmod. Назначаем права 600, редактируем файл, возвращаем права 000 и перезапускаем систему. Система успешно загружается, в systemd все юниты в работе. Проверяем пакетный менеджер:

[centos@localhost ~]$ sudo yum install clang
[sudo] пароль для centos:
Последняя проверка окончания срока действия метаданных: 0:25:37 назад, Пн 05 фев 2024 12:41:33.
Зависимости разрешены.
…

Подождите. А почему sudo смог? Проверяем.

[centos@localhost ~]$ sudo id
[sudo] пароль для centos:
uid=0(void) gid=0(root) группы=0(root) контекст=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
[centos@localhost ~]$ getent passwd 0
void:x:0:0:root:/root:/bin/bash
[centos@localhost ~]$ getent passwd root
root:x:0:0:Super User:/root:/bin/bash
[centos@localhost ~]$ getent passwd | grep ^root
[centos@localhost ~]$

При обращении к пользователю root по имени системы всегда находит этого пользователя! Даже если в общей базе его нет. Потрясающий ход. Ну тогда продолжим установку:

  Установка        : gcc-toolset-13-runtime-13.0-2.el9.x86_64                                                      9/16
  Запуск скриптлета: gcc-toolset-13-runtime-13.0-2.el9.x86_64                                                      9/16
Error writing to log: Ошибка ввода/вывода
Error in POSTIN scriptlet in rpm package gcc-toolset-13-runtime
Error: Cannot open file /var/cache/dnf/appstream-831abc7e9d6a1a72/packages/gcc-toolset-13-binutils-2.40-17.el9.x86_64.rpm: [Errno 5] Ошибка ввода/вывода: '/var/cache/dnf/appstream-831abc7e9d6a1a72/packages/gcc-toolset-13-binutils-2.40-17.el9.x86_64.rpm'
TypeError: an integer is required (got type NoneType)
FATAL ERROR: python callback ??? failed, aborting!

Странная ошибка. Но подробностей выяснить не удалось.

[centos@localhost ~]$ ls
-bash: /usr/libexec/pk-command-not-found: Input/output error
[centos@localhost ~]$ reboot
-bash: /usr/libexec/pk-command-not-found: Input/output error
[centos@localhost ~]$ getent passwd
-bash: /usr/bin/getent: Input/output error

После принудительной перезагрузке система отказалась «просыпаться» даже в режиме восстановления:

Что будет, если переименовать суперпользователя? Экспериментируем, удивляемся и расстраиваемся… - 7

А так все хорошо начиналось. Впрочем, ситуация не воспроизвелась при переустановке системы. Так что может и не в суперпользователе дело.

RedOS

RedOS построена на базе CentOS, поэтому, ожидаемо, наблюдается сходное поведение:

  • файл /etc/shadow защищен правами 000,
  • после переименования система использует «фантомного» суперпользователя.

RedOS не «развалилась» как оригинальная CentOS при установке пакетов. Возможно, это какой-то редкий сбой ОС, либо не менее редкий сбой VirtualBox. В любом случае, это был неприятный прецедент, который повышает риски и для RedOS.

FreeBSD 14

Чтобы разбавить концентрацию Linux-ов, последним в списке будет FreeBSD. Начнем с того, что FreeBSD имеет туз в рукаве — суперпользователя с именем toor.

root@freebsd:~ # getent passwd | grep '^[^:]*:[^:]*:0'
root:*:0:0:Charlie &:/root:/bin/sh
toor:*:0:0:Bourne-again Superuser:/root:

Пользователь toor — это наследие истории. Пользователь root — это главный и единственный пользователь, который может восстановить систему после сбоя. При этом в корне чаще всего находился только минимально необходимый для работы набор программ, а дополнительные программы выносились на другие разделы. Так было и с командным интерпретатором. Для пользователя root это минимальный sh.

Для повышения комфорта повседневной работы завели пользователя toor, который имеет идентификатор 0, но использует более современный и функциональный интерпретатор — Bourne-Again SHell (bash).

В FreeBSD есть файл /etc/passwd, а есть его бинарные «братья». Для переименования суперпользователя нужно запустить специальный редактор vipw. В отличие от Linux, дистрибутив FreeBSD принял потерю пользователя root как должное. Пользователь не был создан с ограниченными правами, не появилось и «фантомной» записи. Пользователь toor намекает, что другим именем суперпользователя систему не удивить, хотя su определенно сломается.

freebsd@freebsd:~ $ su -c whoami
su: Sorry

Возможно, эти тексты тоже вас заинтересуют:

«Двигай телом»: обзор новой игровой консоли Nex Playground [16]
Dell, IBM и Google заставили сотрудников вернуться в офисы: что в итоге? [17]
Базовая настройка коммутатора Cisco 2960: особенности и фишки [18]

Где суперпользователь не root?


В разных семействах операционных систем разработчики делали так, как считали нужным. Например, в Windows имя первого пользователя задается при установке, а правами администратора можно наделить любого пользователя.

Имя суперпользователя root — это особенность семейств *NIX. И большинство систем следует этому правилу. Маленькие исключения — BSD-системы и Ubuntu. В первой есть «запасной» пользователь toor, о котором говорилось ранее. А Ubuntu абстрагирует пользователя от суперпользователя, предлагая выполнять административные действия через sudo:

Что будет, если переименовать суперпользователя? Экспериментируем, удивляемся и расстраиваемся… - 8

Пришлось поставить BeOS 5.

Впрочем, мне удалось найти старинную BeOS, которая развивалась до 2001 года. Она не является ответвлением семейства UNIX, но частично соблюдает интерфейс POSIX и имеет множество утилит, портированных из UNIX. BeOS не предлагает создать пользователя при установке, но при этом имеет ряд утилит для работы с пользователями.

  • Есть утилита whoami, которая раскрывает имя текущего пользователя.
  • Есть утилита id, которая позволяет убедиться, что пользователь baron — это действительно суперпользователь.
  • Есть утилита su, которая по умолчанию хочет переключиться в несуществующего пользователя system.
  • Утилит для создания пользователей мне найти не удалось, в том числе в графическом интерфейсе.

Переименовать суперпользователя — это простое действие, очень похожее на «лутбоксы» или «русскую рулетку». Нет никакой уверенности, что это действие добавит безопасности, зато определенно что-нибудь сломает. В лучшем случае, система адаптируется, как это произошло с CentOS и RedOS, в худшем случае — не запустится, как показала нам Ubuntu с графической оболочкой.

Автор: Владимир

Источник [19]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/linux/389988

Ссылки в тексте:

[1] сервера: https://selectel.ru/services/cloud/servers/?%20utm_source=habr.com&utm_medium=referral&utm_campaign=cloud_article_linux_080224_content

[2] Пользователи в пространстве ядра: #1

[3] Пространство пользователя: #2

[4] Интерактивный уровень: #3

[5] Рубрика «Эксперименты»: #4

[6] Где суперпользователь не root?: #5

[7] task_struct: https://github.com/torvalds/linux/blob/861c0981648f5b64c86fd028ee622096eb7af05a/include/linux/sched.h%23L748

[8] cred: https://github.com/torvalds/linux/blob/861c0981648f5b64c86fd028ee622096eb7af05a/include/linux/cred.h%23L117

[9] структуры данных kuid_t и kgid_t: https://github.com/torvalds/linux/blob/861c0981648f5b64c86fd028ee622096eb7af05a/include/linux/uidgid_types.h%23L7

[10] uid_t и gid_t: https://github.com/torvalds/linux/blob/master/include/linux/types.h%23L37

[11] одно из платформозависимых определений: https://github.com/torvalds/linux/blob/master/include/uapi/asm-generic/posix_types.h%23L49

[12] inode: https://github.com/torvalds/linux/blob/861c0981648f5b64c86fd028ee622096eb7af05a/include/linux/fs.h%23L639

[13] своем канале: https://t.me/+VzpLr5pam-MxODEy

[14] установщик Docker Engine: https://get.docker.com/

[15] Manjaro Linux: https://manjaro.org/download/

[16] «Двигай телом»: обзор новой игровой консоли Nex Playground: https://habr.com/ru/company/selectel/blog/791446

[17] Dell, IBM и Google заставили сотрудников вернуться в офисы: что в итоге?: https://habr.com/ru/company/selectel/blog/791316

[18] Базовая настройка коммутатора Cisco 2960: особенности и фишки: https://habr.com/ru/company/selectel/blog/789846

[19] Источник: https://habr.com/ru/companies/selectel/articles/791454/?utm_source=habrahabr&utm_medium=rss&utm_campaign=791454