跳转至

ruid、euid、suid区分

  • 参考
  • 参考2
  • 解释:
  • ruid (real uid) :实际用户 ID 其实就是当前登录系统的用户 ID, 是那个运行程序的用户。
  • euid (effective uid) :有效的用户 id,可以由 c 接口 seteuid 或者 setuid 等修改。这个 euid 是用来做权限校验的,比如访问其它文件时,对比的就是 euid。
  • suid (saved set-user-ID) :保存的设置用户 ID,可以理解成保存着最初 euid 的状态(seteid 影响),
  • 规则:
  • 通常 ruid、euid、suid 是相等的。
  • 通过 chmod u+s 或者 chmod o+s 修改可执行文件的 suid,sgid(+s 对 other 位是没有作用的), 可执行位为 S当修改了可执行文件的 suid 时,任意用户执行此可执行文件,其 euid 和 suid 变成了设置的 uid,而不再是执行程序的用户,ps 显示的用户也设置的用户。

  • 示例

    $ ll test.sh
    -rwxr-xr--. 1 shuhw shuhw  0 6月  16 13:53 test.sh
    $ chmod o+s test.sh
    $ ll test.sh
    -rwSr-xr--. 1 shuhw shuhw  0 6月  16 13:53 test.sh
    

1 Experiments

First, let’s create one C file named test.c, as below:

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
int main()
{
  uid_t ruid, euid, suid; 
  getresuid(&ruid, &euid, &suid);
  printf("EUID: %d, RUID: %d, SUID: %d\n", ruid, euid, suid);
  system("cat file-read-only-by-root"); // file-read-only-by-root: -r-------- root root
  setreuid(geteuid(), geteuid());
  getresuid(&ruid, &euid, &suid);
  printf("EUID: %d, RUID: %d, SUID: %d\n", ruid, euid, suid);
  system("cat file-read-only-by-root"); // file-read-only-by-root: -r-------- root root
  return 0;
}
gcc -o test test.c
sudo chown root:ubuntu test # Here ubuntu is the normal user

Without setting setuid bit, the result of executing test is as below:

$ ./test
EUID: 1000, RUID: 1000, SUID: 1000
cat: file-read-only-by-root: Permission denied
EUID: 1000, RUID: 1000, SUID: 1000
cat: file-read-only-by-root: Permission denied

Then we setuid for test file and execute it again,

sudo chmod u+s test
$ ./test
EUID: 1000, RUID: 0, SUID: 0
cat: file-read-only-by-root: Permission denied
EUID: 0, RUID: 0, SUID: 0
Testing

From digging deeply, we find out the problem in the first system("cat file-read-only-by-root") is that Bash Script bans the setuid option. However, if we directly use fopen->fread or open->read, it would be fine. The new C file is as follows:

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>

#define BUFF_SIZE 100

void read_file() {
   FILE *fp;
   char buffer[BUFF_SIZE];

   /* Open file for both reading and writing */
   fp = fopen("file-read-only-by-root", "r");
   /* Read and display data */
   fread(buffer, BUFF_SIZE - 1, sizeof(char), fp);
   printf("%s\n", buffer);
   fclose(fp);
}

int main()
{
  uid_t ruid, euid, suid; 
  getresuid(&ruid, &euid, &suid);
  printf("EUID: %d, RUID: %d, SUID: %d\n", ruid, euid, suid);
  read_file(); // file-read-only-by-root: -r-------- root root
  setreuid(geteuid(), geteuid());
  getresuid(&ruid, &euid, &suid);
  printf("EUID: %d, RUID: %d, SUID: %d\n", ruid, euid, suid);
  read_file(); // file-read-only-by-root: -r-------- root root
  return 0;
}

Then we add setuid option and test again,

$ ./test
EUID: 1000, RUID: 0, SUID: 0
Testing

EUID: 0, RUID: 0, SUID: 0
Testing