这是一个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 ; }
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
?
有两种情况,
- 您希望在执行setuid程序时暂时删除root权限
- 您想要执行setuid程序时永久删除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和saved-user-id。 您可以在setuid程序中引入暂停(来自用户的输入)并检查每个步骤cat /proc/PROCID/task/PROCID/status | less
cat /proc/PROCID/task/PROCID/status | less
命令。 在每个步骤中,您可以检查保存的uid是否如前所述进行了更改。
如果您的euid是root用户,并且您更改了uid,则权限将被永久删除。如果有效的用户标识不是root,那么保存的用户标识将不会被触及,您可以随时在程序中重新获得root权限。
描述 setuid()设置调用进程的有效用户标识。 如果调用者的有效UID是root,则也设置真实的UID和保存的set-user-ID。
在Linux下,setuid()与_POSIX_SAVED_IDS特性一样被实现为POSIX版本。 这允许设置用户ID(非root用户)删除所有用户权限,执行一些无权限的工作,然后以安全的方式重新获得原始的有效用户ID。
如果用户是root或程序是set-user-ID-root,那么必须特别小心。 setuid()函数检查调用者的有效用户标识,如果它是超级用户,则所有与进程相关的用户标识都设置为uid。 发生这种情况之后,程序不可能重新获得root权限。
因此,一个希望临时删除root权限的set-user-ID-root程序,假定非特权用户的身份,然后重新获得root权限,之后不能使用setuid()。 你可以用seteuid(2)完成这个。
(从Linux程序员手册,2014-09-21,第setuid.2
页)
哦! 这些功能很难正确使用。
手册页指出,setuid将改变真实的,保存的和有效的uid。 所以在调用setuid(1000)之后,所有三个变为1000。
如果且仅当你是euid 0,情况就是这样。然而,当你调用setuid(0)
时候,你是euid 1000并且保存了 uid 0(例如检查getresuid(2)
)。 这就是为什么你能够恢复特权。