淺談Linux下的ruid、euid、suid及普通用戶可執(zhí)行程序以root權(quán)限特權(quán)運(yùn)行的方法

淺談RUID、EUID、SUID

想要實(shí)現(xiàn)普通用戶在非sudo的情況下,執(zhí)行需要root權(quán)限的函數(shù)或者指令,必須要能夠理解這三個(gè)UID的值。這三個(gè)UID分別為實(shí)際用戶ID(real uid)、有效用戶ID(effective uid)、保存的設(shè)置用戶ID(saved set-user-ID)。

實(shí)際用戶ID其實(shí)就是當(dāng)前登錄系統(tǒng)的用戶ID,有效用戶ID就是當(dāng)前進(jìn)程是以那個(gè)用戶ID來(lái)運(yùn)行的,而保存的設(shè)置用戶ID實(shí)際上就是有效用戶ID的一個(gè)副本。
在運(yùn)行一個(gè)進(jìn)程時(shí),該進(jìn)程的有效用戶ID在一般情況下是實(shí)際用戶的ID,但是如果該可執(zhí)行文件具有SUID的權(quán)限,那么他的有效用戶ID就是這個(gè)可執(zhí)行程序的擁有者。
上述說(shuō)法可能比較抽象,我們以Linux下的passwd命令為例,對(duì)SUID進(jìn)行詳細(xì)的解釋。
首先使用ll /usr/bin/passwd指令查看passwd命令的權(quán)限。并以mylord用戶執(zhí)行passwd指令。

passwd_1.png

ll /usr/bin/passwd指令,我們可以看到passwd這個(gè)可執(zhí)行文件的所有者是root用戶,并且根據(jù)-rwsr-xr-x中的s可以看出這個(gè)可執(zhí)行文件具有自身的SUID權(quán)限。當(dāng)我們以mylord這個(gè)用戶執(zhí)行passwd指令時(shí),查看進(jìn)程發(fā)現(xiàn)passwd的實(shí)際USER卻是root,這就是SUID權(quán)限。下面對(duì)Linux的SUID機(jī)制做一個(gè)總結(jié):

  • (1)、經(jīng)常運(yùn)行時(shí)能夠使用那些資源,不取決于該可執(zhí)行文件的所屬組,而是取決于運(yùn)行該命令的用戶的UID/GID。
  • (2)、對(duì)于一個(gè)root所屬的可執(zhí)行文件,如果對(duì)該文件設(shè)置了SUID位,則其他所有的普通用戶均可以root身份運(yùn)行該文件,此時(shí),該進(jìn)程即可獲得root所享有的資源。可以簡(jiǎn)單的理解位讓普通用戶擁有可以執(zhí)行“只有root權(quán)限才能執(zhí)行”的特殊權(quán)限。
  • (3)、SUID的作用是讓執(zhí)行該命令的用戶以該命令擁有者的權(quán)限去執(zhí)行,比如普通用戶執(zhí)行passwd時(shí)會(huì)擁有root的權(quán)限。它的標(biāo)志為:在會(huì)出現(xiàn)x的地方出現(xiàn)s(eg:-rwsr-xr-x)。

Linux C中實(shí)現(xiàn)特權(quán)程序

在Linux C中想要實(shí)現(xiàn)特權(quán)程序,就需要用到SUID。
首先我們現(xiàn)在/usr/目錄下創(chuàng)建一個(gè)test文件并嘗試以mylord用戶刪除該文件。

removetestfile.png

發(fā)現(xiàn)無(wú)法刪除test文件,因?yàn)槲覀儧](méi)有root權(quán)限。編寫(xiě)下面的程序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);     //獲取當(dāng)前進(jìn)程的三個(gè)UID的值
    printf("%d,%d,%d\n", ruid, euid, suid);

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

    setuid(getuid());           //降權(quán)

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

編寫(xiě)完成后在以root用戶編譯該程序(切記,一定要是root用戶),并將該程序賦予SUID:

runcode.png

發(fā)現(xiàn)remove函數(shù)返回值為0,成功刪除test文件。
那么為什么后面還需要加setuid(getuid());這行代碼呢?
我們要先理解setuid()函數(shù)的作用。該函數(shù)的定義如下:

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)、若進(jìn)程具有root特權(quán),則setuid函數(shù)將實(shí)際用戶ID、有效用戶ID、以及保存的設(shè)置用戶ID設(shè)置為uid。
  • (2)、若進(jìn)程沒(méi)有超級(jí)用戶特權(quán),但是uid等于實(shí)際用戶ID或保存設(shè)置的用戶ID,則setuid只將有效用戶ID設(shè)置為uid。不改變實(shí)際用戶ID和保存的設(shè)置用戶ID。
  • (3)、如果上面兩個(gè)條件都不滿足,則errno設(shè)置為ERERM,并返回出錯(cuò)。
    那么顯而易見(jiàn),我們可以理解在執(zhí)行./test后發(fā)生的所有事情了。
    首先在編譯過(guò)程中,我們以root用戶編譯該程序,那么可執(zhí)行文件test的所屬用戶為root,之后我們用chmod指令給該文件賦予了SUID屬性,那么在該進(jìn)程剛開(kāi)始運(yùn)行時(shí),實(shí)際用戶ID為mylord用戶的UID:1000、有效用戶ID為root用戶的UID:0、保存的設(shè)置用戶ID為root用戶的UID:0。在有s屬性的可執(zhí)行文件啟動(dòng)時(shí),該進(jìn)程的有效用戶ID設(shè)置為保存的設(shè)置用戶ID,并且該進(jìn)程的實(shí)際可以享用的資源由有效用戶ID決定。因此,該進(jìn)程具有root用戶所享有的資源并可以成功刪除root創(chuàng)建的文件test。之后getuid()函數(shù)獲得當(dāng)前登錄的用戶ID:1000,并由setuid()函數(shù)賦值,因?yàn)樵撨M(jìn)程有超級(jí)用戶特權(quán)所以將RUID、EUID、SUID全部設(shè)置為1000(getuid()的返回值)。這個(gè)語(yǔ)句執(zhí)行完成之后,該進(jìn)程被降權(quán),失去了root用戶享有的資源,成為了一個(gè)安全的進(jìn)程。

因此,在做完特權(quán)操作后,一定要謹(jǐn)記使用setuid(getuid());語(yǔ)句對(duì)該進(jìn)程降權(quán)以保證系統(tǒng)安全。


參考文獻(xiàn):
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


?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容