examples: add key extractor
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
		
							parent
							
								
									62fe72133c
								
							
						
					
					
						commit
						cb8be29c18
					
				
							
								
								
									
										27
									
								
								contrib/extract-keys/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								contrib/extract-keys/Makefile
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,27 @@
 | 
			
		||||
ifeq ($(KERNELRELEASE),)
 | 
			
		||||
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
 | 
			
		||||
PWD := $(shell pwd)
 | 
			
		||||
CFLAGS ?= -O3 -march=native
 | 
			
		||||
CFLAGS += -Wall -pedantic -std=gnu11
 | 
			
		||||
 | 
			
		||||
extract-keys: extract-keys.c config.h
 | 
			
		||||
	$(CC) $(CFLAGS) $(CPPFLAGS) -D_FILE_OFFSET_BITS=64 -o $@ -lresolv $<
 | 
			
		||||
 | 
			
		||||
config.o: config.c
 | 
			
		||||
	$(MAKE) -C $(KERNELDIR) M=$(PWD) $@
 | 
			
		||||
	objcopy -j '.rodata*' $@ $@
 | 
			
		||||
 | 
			
		||||
config: config.c config.o
 | 
			
		||||
	$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $^
 | 
			
		||||
 | 
			
		||||
config.h: config
 | 
			
		||||
	./$< > $@
 | 
			
		||||
 | 
			
		||||
clean:
 | 
			
		||||
	rm -f extract-keys config config.h
 | 
			
		||||
	$(MAKE) -C $(KERNELDIR) M=$(PWD) clean
 | 
			
		||||
 | 
			
		||||
.PHONY: clean
 | 
			
		||||
else
 | 
			
		||||
config-m := config.o
 | 
			
		||||
endif
 | 
			
		||||
							
								
								
									
										23
									
								
								contrib/extract-keys/README
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								contrib/extract-keys/README
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,23 @@
 | 
			
		||||
Key Extractor
 | 
			
		||||
=============
 | 
			
		||||
 | 
			
		||||
This will extract the symmetric ChaCha20Poly1305 session keys from the kernel
 | 
			
		||||
for a WireGuard interface, for use in making packet dissectors.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Build:
 | 
			
		||||
    $ make
 | 
			
		||||
 | 
			
		||||
Run (as root):
 | 
			
		||||
    # ./extract-keys INTERFACE
 | 
			
		||||
 | 
			
		||||
Output:
 | 
			
		||||
    REMOTE_KEY_ID SENDING_KEY
 | 
			
		||||
    LOCAL_KEY_ID RECEIVING_KEY
 | 
			
		||||
 | 
			
		||||
Example:
 | 
			
		||||
    # ./extract-keys wg0
 | 
			
		||||
    0x57b56068 tMTSEOJpEYFAQV2UviDiYooX0A1AD/ONqrzoQVHa1rQ=
 | 
			
		||||
    0xa182fd19 xvQSkQ5HTX5RUeJ74eAAb/xfNhdrDThxG91GXZIPKmY=
 | 
			
		||||
    0x01662508 LbMc84JULzXJiHotSkdSOPZ0bHh6IDwOrbxWLfwosTs=
 | 
			
		||||
    0xbd819021 4VA8lZ3I1HjnJcWTmhEzBdC92W1Aag9Lnyy2GkroOYI=
 | 
			
		||||
							
								
								
									
										32
									
								
								contrib/extract-keys/config.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								contrib/extract-keys/config.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,32 @@
 | 
			
		||||
struct def {
 | 
			
		||||
	const char *name;
 | 
			
		||||
	long long value;
 | 
			
		||||
};
 | 
			
		||||
extern const struct def defs[];
 | 
			
		||||
 | 
			
		||||
#ifdef __KERNEL__
 | 
			
		||||
#include "../../../src/wireguard.h"
 | 
			
		||||
const struct def defs[] = {
 | 
			
		||||
	{ "SOCK_DEVICE_OFFSET", offsetof(struct sock, sk_user_data) },
 | 
			
		||||
	{ "DEVICE_NAME_OFFSET", -ALIGN(sizeof(struct net_device), NETDEV_ALIGN) + offsetof(struct net_device, name) },
 | 
			
		||||
	{ "IFNAMSIZ", IFNAMSIZ },
 | 
			
		||||
	{ "DEVICE_PEERS_OFFSET", offsetof(struct wireguard_device, peer_list) },
 | 
			
		||||
	{ "PEERS_PEER_OFFSET", -offsetof(struct wireguard_peer, peer_list) },
 | 
			
		||||
	{ "PEER_CURRENTKEY_OFFSET", offsetof(struct wireguard_peer, keypairs.current_keypair) },
 | 
			
		||||
	{ "PEER_PREVIOUSKEY_OFFSET", offsetof(struct wireguard_peer, keypairs.previous_keypair) },
 | 
			
		||||
	{ "PEER_NEXTKEY_OFFSET", offsetof(struct wireguard_peer, keypairs.next_keypair) },
 | 
			
		||||
	{ "KEY_LOCALID_OFFSET", offsetof(struct noise_keypair, entry.index) },
 | 
			
		||||
	{ "KEY_REMOTEID_OFFSET", offsetof(struct noise_keypair, remote_index) },
 | 
			
		||||
	{ "KEY_SENDING_OFFSET", offsetof(struct noise_keypair, sending.key) },
 | 
			
		||||
	{ "KEY_RECEIVING_OFFSET", offsetof(struct noise_keypair, receiving.key) },
 | 
			
		||||
	{ NULL, 0 }
 | 
			
		||||
};
 | 
			
		||||
#else
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
int main(int argc, char *argv[])
 | 
			
		||||
{
 | 
			
		||||
	for (const struct def *def = defs; def->name; ++def)
 | 
			
		||||
		printf("#define %s %lld\n", def->name, def->value);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										139
									
								
								contrib/extract-keys/extract-keys.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										139
									
								
								contrib/extract-keys/extract-keys.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,139 @@
 | 
			
		||||
#include <endian.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <resolv.h>
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include "config.h"
 | 
			
		||||
 | 
			
		||||
static int fd;
 | 
			
		||||
 | 
			
		||||
static void open_kmem(void)
 | 
			
		||||
{
 | 
			
		||||
	fd = open("/dev/kmem", O_RDONLY);
 | 
			
		||||
	if (fd < 0) {
 | 
			
		||||
		perror("open(/dev/kmem)");
 | 
			
		||||
		exit(errno);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void read_kmem(void *buffer, size_t len, unsigned long addr)
 | 
			
		||||
{
 | 
			
		||||
	if (lseek(fd, addr, SEEK_SET) == (off_t)-1) {
 | 
			
		||||
		perror("lseek");
 | 
			
		||||
		exit(errno);
 | 
			
		||||
	}
 | 
			
		||||
	if (read(fd, buffer, len) != len) {
 | 
			
		||||
		perror("read");
 | 
			
		||||
		exit(errno);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline unsigned int read_int(unsigned long addr)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int ret;
 | 
			
		||||
	read_kmem(&ret, sizeof(ret), addr);
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline unsigned long read_long(unsigned long addr)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long ret;
 | 
			
		||||
	read_kmem(&ret, sizeof(ret), addr);
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static unsigned long find_interface(const char *interface)
 | 
			
		||||
{
 | 
			
		||||
	FILE *f = fopen("/proc/net/udp", "r");
 | 
			
		||||
	char line[256], *ptr;
 | 
			
		||||
	unsigned long addr = 0;
 | 
			
		||||
	char name[IFNAMSIZ + 1] = { 0 };
 | 
			
		||||
 | 
			
		||||
	if (!f) {
 | 
			
		||||
		perror("fopen(/proc/net/udp)");
 | 
			
		||||
		exit(errno);
 | 
			
		||||
	}
 | 
			
		||||
	if (!fgets(line, 256, f))
 | 
			
		||||
		goto out;
 | 
			
		||||
	while (fgets(line, 256, f)) {
 | 
			
		||||
		ptr = line + strlen(line) - 1;
 | 
			
		||||
		while (*--ptr == ' ');
 | 
			
		||||
		while (*--ptr != ' ');
 | 
			
		||||
		while (*(--ptr - 1) != ' ');
 | 
			
		||||
		addr = strtoul(ptr, NULL, 16);
 | 
			
		||||
		if (!addr)
 | 
			
		||||
			continue;
 | 
			
		||||
		addr = read_long(addr + SOCK_DEVICE_OFFSET);
 | 
			
		||||
		if (!addr)
 | 
			
		||||
			continue;
 | 
			
		||||
		read_kmem(name, IFNAMSIZ, addr + DEVICE_NAME_OFFSET);
 | 
			
		||||
		if (!strcmp(name, interface))
 | 
			
		||||
			goto out;
 | 
			
		||||
	}
 | 
			
		||||
	addr = 0;
 | 
			
		||||
out:
 | 
			
		||||
	fclose(f);
 | 
			
		||||
	return addr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool print_key(unsigned long key)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char sending[32], receiving[32];
 | 
			
		||||
	char sending_b64[45], receiving_b64[45];
 | 
			
		||||
	unsigned int local_index, remote_index;
 | 
			
		||||
 | 
			
		||||
	if (!key)
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	local_index = le32toh(read_int(key + KEY_LOCALID_OFFSET));
 | 
			
		||||
	remote_index = le32toh(read_int(key + KEY_REMOTEID_OFFSET));
 | 
			
		||||
	read_kmem(sending, 32, key + KEY_SENDING_OFFSET);
 | 
			
		||||
	read_kmem(receiving, 32, key + KEY_RECEIVING_OFFSET);
 | 
			
		||||
 | 
			
		||||
	b64_ntop(sending, 32, sending_b64, 45);
 | 
			
		||||
	b64_ntop(receiving, 32, receiving_b64, 45);
 | 
			
		||||
 | 
			
		||||
	printf("0x%08x %s\n", local_index, receiving_b64);
 | 
			
		||||
	printf("0x%08x %s\n", remote_index, sending_b64);
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool walk_peers(unsigned long peer_head)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long peer, peer_entry;
 | 
			
		||||
	bool found = false;
 | 
			
		||||
	for (peer_entry = read_long(peer_head); peer_entry != peer_head; peer_entry = read_long(peer_entry)) {
 | 
			
		||||
		peer = peer_entry + PEERS_PEER_OFFSET;
 | 
			
		||||
		if (print_key(read_long(peer + PEER_CURRENTKEY_OFFSET)))
 | 
			
		||||
			found = true;
 | 
			
		||||
		if (print_key(read_long(peer + PEER_PREVIOUSKEY_OFFSET)))
 | 
			
		||||
			found = true;
 | 
			
		||||
		if (print_key(read_long(peer + PEER_NEXTKEY_OFFSET)))
 | 
			
		||||
			found = true;
 | 
			
		||||
	}
 | 
			
		||||
	return found;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main(int argc, char *argv[])
 | 
			
		||||
{
 | 
			
		||||
	unsigned long wireguard_device;
 | 
			
		||||
	if (argc < 2) {
 | 
			
		||||
		fprintf(stderr, "Usage: %s WIREGUARD_INTERFACE\n", argv[0]);
 | 
			
		||||
		return EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
	open_kmem();
 | 
			
		||||
	wireguard_device = find_interface(argv[1]);
 | 
			
		||||
	if (!wireguard_device) {
 | 
			
		||||
		fprintf(stderr, "Could not find interface %s\n", argv[1]);
 | 
			
		||||
		return EBADSLT;
 | 
			
		||||
	}
 | 
			
		||||
	if (!walk_peers(wireguard_device + DEVICE_PEERS_OFFSET)) {
 | 
			
		||||
		fprintf(stderr, "No active sessions\n");
 | 
			
		||||
		return ENOKEY;
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user