RealUID, сохраненный UID, эффективный UID. В чем дело? - PullRequest
36 голосов
/ 14 декабря 2011

Это программа set-root-uid

$ls -l
-rwsr-sr-x 1 root root 7406 2011-12-13 22:37 ./x*

Исходный код:

int main(void) {
    printf(
        "         UID           GID  \n"
        "Real      %d  Real      %d  \n"
        "Effective %d  Effective %d  \n",
             getuid (),     getgid (),
             geteuid(),     getegid()
    );

seteuid(600);
    printf(
        "         UID           GID  \n"
        "Real      %d  Real      %d  \n"
        "Effective %d  Effective %d  \n",
             getuid (),     getgid (),
             geteuid(),     getegid()
    );

setuid(1000);

    printf(
        "         UID           GID  \n"
        "Real      %d  Real      %d  \n"
        "Effective %d  Effective %d  \n",
             getuid (),     getgid (),
             geteuid(),     getegid()
    );

setuid(0); // HOW DOES THIS SUCCEED IN SETTING THE EUID BACK TO 0
    printf(
        "         UID           GID  \n"
        "Real      %d  Real      %d  \n"
        "Effective %d  Effective %d  \n",
             getuid (),     getgid (),
             geteuid(),     getegid()
    );

    return 0 ;       
}

OUTPUT

         UID           GID  
Real      1000  Real      1000  
Effective 0  Effective 0  
         UID           GID  
Real      1000  Real      1000  
Effective 600  Effective 0  
         UID           GID  
Real      1000  Real      1000  
Effective 1000  Effective 1000  
         UID           GID  
Real      1000  Real      1000  
Effective 0  Effective 1000  

Мой вопрос

На странице руководства указано, что setuid изменит реальный, сохраненный и эффективный uid. Поэтому после вызова setuid(1000) все три изменяются на 1000. Как это setuid(0) позвольте мне изменить euid на 0?

Ответы [ 4 ]

30 голосов
/ 14 декабря 2011

Есть два случая,

  1. Вы хотите временно удалить привилегию root при выполнении программы setuid
  2. Вы хотите навсегда удалить привилегии root при выполнении программы setuid ...
  • Вы можете временно сделать это, установив в euid реальный идентификатор пользователя, а затем изменив uid на что угодно. И позже, когда вам понадобится привилегия root, вы можете установить значение root, а действующий идентификатор пользователя изменится на root. , Это потому, что сохраненный идентификатор пользователя не изменился.
  • Вы можете навсегда отбросить привилегию, изменив uid на идентификатор пользователя с меньшими привилегиями. После этого независимо от того, что вы не можете вернуть привилегию root.

Дело 1:

После запуска программы setuid

1.seteuid(600);
2.setuid(1000);
3.setuid(0);

В этом случае привилегию root можно вернуть обратно.

              +----+------+------------+
              | uid|euid  |saved-uid   |
              |----|------|------------|
            1.|1000| 0    | 0          |
            2.|1000| 600  | 0          |
            3.|1000| 1000 | 0          |
            4.|1000|  0   | 0          |
              |    |      |            |
              +------------------------+

Дело 2:

После запуска программы setuid ,

1.setuid(1000);
2.setuid(0);



               +----+------+------------+
               | uid|euid  |saved-uid   |
               |----|------|------------|
             1.|1000|0     | 0          |
             2.|1000|1000  | 1000       |
               |    |      |            |
               +------------------------+

В этом случае вы не можете вернуть привилегию root. Это можно проверить с помощью следующей команды:

cat / proc / PROCID / task / PROCID / status | меньше

Uid:    1000    0       0       0
Gid:    1000    0       0       0

Эта команда отобразит Uid и Gid и будет иметь 4 поля (первые три поля - это то, что нас интересует). Нечто подобное выше

Три поля представляют uid, euid и сохраненный идентификатор пользователя. Вы можете ввести паузу (ввод от пользователя) в вашу программу setuid и проверять для каждого шага команду cat /proc/PROCID/task/PROCID/status | less. На каждом шаге вы можете проверить, что сохраненный uid меняется, как указано.

Если ваш euid является пользователем root и вы изменили uid, привилегии будут удалены навсегда. Если эффективный идентификатор пользователя не является root, то сохраненный идентификатор пользователя никогда не затрагивается, и вы можете восстановить привилегию root обратно в любое время, когда вы хотите в своей программе.

8 голосов
/ 14 декабря 2011

ОПИСАНИЕ setuid () устанавливает эффективный идентификатор пользователя вызывающего процесса.Если эффективный UID вызывающего абонента является root, реальный UID и сохраненный set-user-ID также устанавливаются.

В Linux setuid () реализован как версия POSIX с функцией _POSIX_SAVED_IDS.Это позволяет программе set-user-ID (отличной от root) отбросить все свои пользовательские привилегии, выполнить некоторую непривилегированную работу и затем повторно безопасно включить исходный эффективный ID пользователя.

Еслипользователь root или программа set-user-ID-root, необходимо соблюдать особую осторожность.Функция setuid () проверяет эффективный идентификатор пользователя вызывающей стороны, и, если это суперпользователь, все идентификаторы пользователя, связанные с процессом, устанавливаются в uid.После того, как это произошло, программа не может восстановить корневые привилегии.

Таким образом, программа set-user-ID-root, желающая временно отбросить корневые привилегии, принять личность непривилегированного пользователя, а затемвосстановить корневые привилегии после этого не может использовать setuid ().Вы можете сделать это с помощью seteuid (2).

(из Руководства для программистов Linux, 2014-09-21, стр. setuid.2)

3 голосов
/ 14 декабря 2011

O! Эти функции трудно использовать правильно.

На странице руководства указано, что setuid изменит реальный, сохраненный и эффективный uid. Таким образом, после вызова setuid (1000) все три изменяются на 1000.

Это так, если и только если вы euid 0. В то время, когда вы звоните setuid(0), вы, однако, euid 1000 и сохранено uid 0 (проверьте, например, getresuid(2)) , Вот почему вы можете восстановить привилегии.

1 голос
/ 10 апреля 2019

Код:

#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>

void print_uid(char *str, int ret)
{
    uid_t ruid;
    uid_t euid;
    uid_t suid;
    getresuid(&ruid, &euid, &suid);

    printf("%s ret:%d\n"
           "Real:%4d  Effective:%4d  Saved:%4d\n",
           str, ret, ruid, euid, suid);
}

int main(void)
{
    int ret = 0;
    print_uid("init", ret);            /* Real:1000  Effective:   0  Saved:   0 */

    ret = seteuid(600);
    print_uid("seteuid(600)", ret);    /* Real:1000  Effective: 600  Saved:   0 */

    ret = setuid(1000);
    print_uid("setuid(1000)", ret);    /* Real:1000  Effective:1000  Saved:   0 */

    ret = setuid(0);
    print_uid("setuid(0)", ret);       /* Real:1000  Effective:   0  Saved:   0 */

    ret = setuid(1000);
    print_uid("setuid(1000)", ret);    /* Real:1000  Effective:1000  Saved:1000 */

    ret = setuid(0);
    print_uid("setuid(0)", ret);       /* Real:1000  Effective:1000  Saved:1000 */

    return 0 ;       
}

sudo chown root setuid_feature
sudo chmod + s setuid_feature

В Linux существует три uid процесса: REAL UID, EFFECTIVE uid, SAVED uid.
Конд 1. Когда euid является root, setuid или seteuid могут быть установлены на любой uid, но при использовании setuid (не seteuid) все три могут быть установлены на один и тот же uid, который не является ROOT, и тогда процесс не может восстановить привилегию ROOT.
Конд 2. Когда euid не является root, setuid или seteuid могут быть установлены в ruid или suid, и изменяется только euid.

                       |      seteuid             |          setuid  
Cond 1. (euid == root) | set euid to any uid      | set all three uids to any uid  
Cond 2. (euid != root) | set euid to ruid or suid | set euid to ruid or suid  

Итак, в коде есть 5 процессов setuid или seteuid, позвольте мне их классифицировать:
1. seteuid (600): Cond 1, установите euid на 600
2. setuid (1000): Cond 2, установите euid на 1000
3. setuid (0): Cond 2, установите для euid значение 0 (suid)
4. setuid (1000): Cond 1, установите все три идентификатора 1000
5. setuid (0): Cond 2, все три идентификатора не равны 0, поэтому не могут быть установлены в 0, сбой с ret = -1

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...