浅谈Linux下的ruid、euid、suid及普通用户可执行程序以root权限特权运行的方法

浅谈RUID、EUID、SUID

想要实现普通用户在非sudo的情况下,执行需要root权限的函数或者指令,必须要能够理解这三个UID的值。这三个UID分别为实际用户ID(real uid)、有效用户ID(effective uid)、保存的设置用户ID(saved set-user-ID)。

实际用户ID其实就是当前登录系统的用户ID,有效用户ID就是当前进程是以那个用户ID来运行的,而保存的设置用户ID实际上就是有效用户ID的一个副本。
在运行一个进程时,该进程的有效用户ID在一般情况下是实际用户的ID,但是如果该可执行文件具有SUID的权限,那么他的有效用户ID就是这个可执行程序的拥有者。
上述说法可能比较抽象,我们以Linux下的passwd命令为例,对SUID进行详细的解释。
首先使用ll /usr/bin/passwd指令查看passwd命令的权限。并以mylord用户执行passwd指令。

passwd_1.png

ll /usr/bin/passwd指令,我们可以看到passwd这个可执行文件的所有者是root用户,并且根据-rwsr-xr-x中的s可以看出这个可执行文件具有自身的SUID权限。当我们以mylord这个用户执行passwd指令时,查看进程发现passwd的实际USER却是root,这就是SUID权限。下面对Linux的SUID机制做一个总结:

  • (1)、经常运行时能够使用那些资源,不取决于该可执行文件的所属组,而是取决于运行该命令的用户的UID/GID。
  • (2)、对于一个root所属的可执行文件,如果对该文件设置了SUID位,则其他所有的普通用户均可以root身份运行该文件,此时,该进程即可获得root所享有的资源。可以简单的理解位让普通用户拥有可以执行“只有root权限才能执行”的特殊权限。
  • (3)、SUID的作用是让执行该命令的用户以该命令拥有者的权限去执行,比如普通用户执行passwd时会拥有root的权限。它的标志为:在会出现x的地方出现s(eg:-rwsr-xr-x)。

Linux C中实现特权程序

在Linux C中想要实现特权程序,就需要用到SUID。
首先我们现在/usr/目录下创建一个test文件并尝试以mylord用户删除该文件。

removetestfile.png

发现无法删除test文件,因为我们没有root权限。编写下面的程序test.cpp:

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

int main()
{
    uid_t ruid, euid, suid;
    getresuid(&ruid, &euid, &suid);     //获取当前进程的三个UID的值
    printf("%d,%d,%d\n", ruid, euid, suid);

    printf("%d\n",remove("/usr/test"));

    setuid(getuid());           //降权

    getresuid(&ruid, &euid, &suid);
    printf("%d,%d,%d\n", ruid, euid, suid);
}

编写完成后在以root用户编译该程序(切记,一定要是root用户),并将该程序赋予SUID:

runcode.png

发现remove函数返回值为0,成功删除test文件。
那么为什么后面还需要加setuid(getuid());这行代码呢?
我们要先理解setuid()函数的作用。该函数的定义如下:

SYNOPSIS         top
       #include <sys/types.h>
       #include <unistd.h>

       int setuid(uid_t uid);
DESCRIPTION         top
       setuid() sets the effective user ID of the calling process.  If the
       calling process is privileged (more precisely: if the process has the
       CAP_SETUID capability in its user namespace), the real UID and saved
       set-user-ID are also set.

       Under Linux, setuid() is implemented like the POSIX version with the
       _POSIX_SAVED_IDS feature.  This allows a set-user-ID (other than
       root) program to drop all of its user privileges, do some un-
       privileged work, and then reengage the original effective user ID in
       a secure manner.

       If the user is root or the program is set-user-ID-root, special care
       must be taken: setuid() checks the effective user ID of the caller
       and if it is the superuser, all process-related user ID's are set to
       uid.  After this has occurred, it is impossible for the program to
       regain root privileges.

       Thus, a set-user-ID-root program wishing to temporarily drop root
       privileges, assume the identity of an unprivileged user, and then
       regain root privileges afterward cannot use setuid().  You can
       accomplish this with seteuid(2).

描述部分翻译一下:

  • (1)、若进程具有root特权,则setuid函数将实际用户ID、有效用户ID、以及保存的设置用户ID设置为uid。
  • (2)、若进程没有超级用户特权,但是uid等于实际用户ID或保存设置的用户ID,则setuid只将有效用户ID设置为uid。不改变实际用户ID和保存的设置用户ID。
  • (3)、如果上面两个条件都不满足,则errno设置为ERERM,并返回出错。
    那么显而易见,我们可以理解在执行./test后发生的所有事情了。
    首先在编译过程中,我们以root用户编译该程序,那么可执行文件test的所属用户为root,之后我们用chmod指令给该文件赋予了SUID属性,那么在该进程刚开始运行时,实际用户ID为mylord用户的UID:1000、有效用户ID为root用户的UID:0、保存的设置用户ID为root用户的UID:0。在有s属性的可执行文件启动时,该进程的有效用户ID设置为保存的设置用户ID,并且该进程的实际可以享用的资源由有效用户ID决定。因此,该进程具有root用户所享有的资源并可以成功删除root创建的文件test。之后getuid()函数获得当前登录的用户ID:1000,并由setuid()函数赋值,因为该进程有超级用户特权所以将RUID、EUID、SUID全部设置为1000(getuid()的返回值)。这个语句执行完成之后,该进程被降权,失去了root用户享有的资源,成为了一个安全的进程。

因此,在做完特权操作后,一定要谨记使用setuid(getuid());语句对该进程降权以保证系统安全。


参考文献:
https://www.cnblogs.com/bwangel23/archive/2015/01/15/4225818.html
https://www.cnblogs.com/puyangsky/p/5307030.html
https://blog.csdn.net/weixin_34194702/article/details/89999074
http://man7.org/linux/man-pages/man2/setuid.2.html


©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容