setuid与capability
课程作业:
1.解释“passwd”,“sudo”, “ping”等命令为什么需要setuid位,去掉s位试运行,添加权能试运行。
2.指出每个权能对应的系统调用,简要解释功能
3.查找你Linux发行版系统(Ubuntu/centos等)中所有设置了setuid位的程序,指出其应该有的权能
4.实现一个程序其满足以下的功能:
(1)能够永久的删除其子进程的某个权能。
(2)能暂时性的删除其子进程的某个权能。
(3)能让上面被暂时性删除的权能重新获得。
回答:
1.解释“passwd”,“sudo”, “ping”等命令为什么需要setuid位,去掉s位试运行,添加权能试运行。
“passwd”,”sudo”,”ping”都需要root权限来运行命令,普通用户没有权限运行,设置setuid位,就是允许用户以文件所有者的权限去执行。
可见“passwd”,“sudo”, “ping”都设置了s位
去掉s位,无法执行
加上相应的权能,又可正常执行(没找到sudo的权能)
2.指出每个权能对应的系统调用,简要解释功能
使用 sudo find / -name capability.h 查找到路径 /usr/src/linux-headers-4.10.0-28/include/uapi/linux/capability.h ,整理可得下表:
如下:
权能 |
编号(相关系统调用) |
解释 |
CAP_CHOWN |
0(chown) |
对文件的UIDs和GIDs做任意修改 |
CAP_DAC_OVERRIDE |
1 |
忽略对文件的DAC访问限制 |
CAP_DAC_READ_SEARCH |
2 |
忽略DAC中对文件和目录的读、搜索权限 |
CAP_FOWNER |
3 |
忽略进程UID与文件UID的匹配检查 |
CAP_FSETID |
4 |
文件修改时不清除setuid和setgid位,不匹配时设置setgid位 |
CAP_KILL |
5(kill) |
绕过发送信号时的权限检查 |
CAP_SETGID |
6(setgid) |
设置或管理进程GID |
CAP_SETUID |
7(setuid) |
管理或设置进程UID |
CAP_SETPCAP |
8(capset) |
允许授予或删除其他进程的任何权能 |
CAP_LINUX_IMMUTABLE |
9(chattr) |
允许设置文件的不可修改位(IMMUTABLE)和只添加(APPND-ONLY)属性 |
CAP_NET_BIND_SERVICE |
10 |
允许绑定到小于1024的端口 |
权能 |
编号(相关系统调用) |
解释 |
CAP_NET_BROADCAST |
11 |
允许socket发送监听组播 |
CAP_NET_ADMIN |
12 |
允许执行网络管理任务 |
CAP_NET_RAW |
13(socket) |
允许使用原始套接字 |
CAP_IPC_LOCK |
14(mlock) |
允许锁定共享内存片段 |
CAP_IPC_OWNER |
15 |
忽略IPC所有权检查 |
CAP_SYS_MOUDLE |
16(init_module) |
插入和删除内核模块 |
CAP_SYS_RAWIO |
17 |
允许对ioperm/iopl的访问 |
CAP_SYS_CHROOT |
18(chroot) |
允许使用chroot()系统调用 |
CAP_SYS_PTRACE |
19(ptrace) |
允许跟踪任何进程 |
CAP_SYS_PACCT |
20(acct) |
允许配置进程记账 |
CAP_SYS_ADMIN |
21 |
允许执行系统管理任务 |
CAP_SYS_BOOT |
22(reboot) |
允许重新启动系统 |
CAP_SYS_NICE |
23(nice) |
允许提升优先级,设置其他进程优先级 |
CAP_SYS_RESOURCE |
24(setrlimit) |
设置资源限制 |
权能
权能 |
编号(相关系统调用) |
解释 |
CAP_SYS_TIME |
25(stime) |
允许改变系统时钟 |
CAP_SYS_TTY_CONFIG |
26(vhangup) |
允许配置TTY设备 |
CAP_MKNOD |
27(mknod) |
允许使用mknod()系统调用,创建特殊文件 |
CAP_LEASE |
28(fcntl) |
为任意文件建立租约 |
CAP_AUDIT_WRITE |
29 |
允许向内核审计日志写记录 |
CAP_AUDIT_CONTROL |
30 |
启用或禁用内核审计,修改审计过滤器规则 |
CAP_SETFCAP |
31 |
设置文件权能 |
CAP_MAC_OVERRIDE |
32 |
允许MAC配置或状态改变,为smack LSM实现 |
CAP_MAC_ADMIN |
33 |
覆盖强制访问控制 |
CAP_SYSLOG |
34(syslog) |
执行特权syslog(2)操作 |
CAP_WAKE_ALARM |
35 |
触发将唤醒系统的东西 |
CAP_BLOCK_SUSPEND |
36(epoll) |
可以阻塞系统挂起的特性 |
CAP_AUDIT_READ |
37 |
允许通过一个多播socket读取审计日志 |
3.查找你Linux发行版系统(Ubuntu/centos等)中所有设置了setuid位的程序,指出其应该有的权能
使用find / -perm /u=s命令
列举部分命令程序的权能如下:
/bin/su |
CAP_DAC_OVERRIDE |
忽略对文件的所有DAC访问限制 |
CAP_SETGID |
允许改变组ID |
|
CAP_SETUID |
允许改变用户ID |
|
/bin/ping |
CAP_NET_RAW |
允许使用原始(raw)套接字 |
/bin/fusermount |
CAP_SYS_ADMIN |
允许执行系统管理任务:加载/卸载文件系统、设置磁盘配额、开/关交换设备和文件等 |
/bin/umount |
CAP_SYS_ADMIN |
允许执行系统管理任务:加载/卸载文件系统、设置磁盘配额、开/关交换设备和文件等 |
/bin/mount |
CAP_SYS_ADMIN |
允许执行系统管理任务:加载/卸载文件系统、设置磁盘配额、开/关交换设备和文件等 |
/usr/bin/passwd |
CAP_CHOWN |
允许改变文件的所有权 |
CAP_DAC_OVERRIDE |
忽略对文件的所有DAC访问限制 |
|
CAP_FOWNER |
如果文件属于进程的UID,就取消对文件的限制 |
4.实现一个程序其满足以下的功能:
(1)能够永久的删除其子进程的某个权能。
(2)能暂时性的删除其子进程的某个权能。
(3)能让上面被暂时性删除的权能重新获得。
在linux中,权能有如下三种:
- effective:当前有效的权能,执行某特权操作时,操作系统检查cap_effective的对应位是否有效,而不再是检查进程的有效UID是否为0。
- permitted:当前进程所有能使用的能力,effective包含于permitted
- inheritable:可以被继承的能力
execve()权能变换规则
pI' = pI
pP' = fP | (fI & pI)
pE' = pP' & fE
其中,pl'、pP'、pE'指子进程的权能,fP、fE指文件的权能
注意三点:
- 文件可继承集决定进程的哪些可继承能力可以放在新的进程允许集中。如果文件可继承集中只有 cap_dac_override,那么只能将这个能力继承到新的进程允许集中。
- 文件允许集也称为 “强迫(forced)” 集,其中的能力总是出现在新的进程允许集中,无论这些能力是否在任务的可继承集中。
- 最后,文件有效位表示任务的新允许集中的位是否应该在新的有效集中设置;也就是说,程序是否能够马上使用这些能力,而不需要用 cap_set_proc(3) 显式地请求它们。
总结:
下面总结一下:
- 文件有效位表示程序在默认情况下是否能够使用它的允许能力。
- 文件允许集中的能力总会在产生的进程上启用。
- 文件可继承集中的能力可以从父进程的可继承集继承到新的允许集。
设计思路
以ping为例,我们知道ping需要的权能为cap_net_raw,为了能在execve后执行ping,即execve中的ping有cap_net_raw权能,根据上面的变换规则:
①设置/bin/ping权能为cap_net_raw+ei,使得可以继承
②设置当前的进程的权能有cap_net_raw+i权能
void init(){
if(getuid() != 0){
puts("请使用sudo执行本程序");
exit(1);
}
listCaps();
cap_value_t cap_values[] = {CAP_SETUID, CAP_SETGID ,CAP_NET_RAW};
cap_t caps = cap_init();
cap_set_flag(caps, CAP_PERMITTED, 3, cap_values, CAP_SET);
cap_set_flag(caps, CAP_EFFECTIVE, 3, cap_values, CAP_SET);
cap_set_proc(caps);
prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
cap_free(caps);
listCaps();
setgid(1000);
setuid(1000);
listCaps();
caps = cap_get_proc();
cap_set_flag(caps, CAP_EFFECTIVE, 3, cap_values, CAP_SET);
cap_set_flag(caps, CAP_INHERITABLE, 3, cap_values, CAP_SET);
cap_set_proc(caps);
cap_free(caps);
whoami();
listCaps();
}
注意:
1、必须在root权限下运行,否则cap等函数无法正常运行
2、必须先给进程设置允许集,必须先设置允许集才可以设置有效集和可继承集。
其中,prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)函数就是保证在0权限变为非0权限后,允许集不丢失。如下:
PR_SET_KEEPCAPS (since Linux 2.2.18)
Set the state of the thread's "keep capabilities" flag, which determines whether the threads's permitted capability set is cleared when a change is made to the threads's user IDs such that the threads's real UID, effective UID, and saved set-user-ID all become nonzero when at least one of them previously had the value 0. By default, the permitted capability set is cleared when such a change is made; setting the "keep capabilities" flag prevents it from being cleared. arg2 must be either 0 (permitted capabilities are cleared) or 1 (permitted capabilities are kept). (A thread's effective capability set is always cleared when such a credential change is made, regardless of the setting of the "keep capabilities" flag.) The "keep capabilities" value will be reset to 0 on subsequent calls to execve(2).
3、CAP_SETUID, CAP_SETGID, CAP_SETPCAP也必须要设置,CAP_SETUID和CAP_SETGID是为了普通用户可以使用setuid()和setgid()函数。
③永久删除子进程的权能就移除effective和inheritable、permitted的,暂时性删除就移除effective和inheritable的,恢复暂时性删除的就添加进effective和inheritable。
cap_t caps = cap_get_proc();
if(cmd == '3'){
cap_set_flag(caps, CAP_EFFECTIVE, 1, &temp, CAP_SET);
cap_set_flag(caps, CAP_INHERITABLE, 1, &temp, CAP_SET);
}
else{
cap_set_flag(caps, CAP_EFFECTIVE, 1, &temp, CAP_CLEAR);
cap_set_flag(caps, CAP_INHERITABLE, 1, &temp, CAP_CLEAR);
if(cmd == '1')
cap_set_flag(caps, CAP_PERMITTED, 1, &temp, CAP_CLEAR);
}
if(cap_set_proc(caps))
perror("cap_set_proc() ERROR: ");
else
printf("%s %s success\n", (cmd =='3'? "recover":"remove"),line);
cap_free(caps);
temp为让用户输入的权能名称
参考文献: