contrib: add extract-handshakes kprobe example
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
		
							parent
							
								
									e6ce5fd386
								
							
						
					
					
						commit
						d4421aea89
					
				
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@ -20,3 +20,4 @@ src/tests/qemu/distfiles/
 | 
			
		||||
*.nam
 | 
			
		||||
*.til
 | 
			
		||||
*.pro.user
 | 
			
		||||
.cache.mk
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										3
									
								
								contrib/extract-handshakes/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								contrib/extract-handshakes/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,3 @@
 | 
			
		||||
offset-finder.o
 | 
			
		||||
offset-finder
 | 
			
		||||
offsets.include
 | 
			
		||||
							
								
								
									
										28
									
								
								contrib/extract-handshakes/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								contrib/extract-handshakes/Makefile
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,28 @@
 | 
			
		||||
ifeq ($(KERNELRELEASE),)
 | 
			
		||||
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
 | 
			
		||||
PWD := $(shell pwd)
 | 
			
		||||
CFLAGS ?= -O3 -march=native
 | 
			
		||||
CFLAGS += -Wall -pedantic -std=gnu11
 | 
			
		||||
 | 
			
		||||
offsets.include: offset-finder
 | 
			
		||||
	./$^ > $@
 | 
			
		||||
 | 
			
		||||
offset-finder: offset-finder.c offset-finder.o
 | 
			
		||||
	$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $^
 | 
			
		||||
 | 
			
		||||
offset-finder.o: offset-finder.c
 | 
			
		||||
	$(MAKE) -C $(KERNELDIR) M=$(PWD) $@
 | 
			
		||||
	objcopy -j '.rodata*' $@ $@
 | 
			
		||||
 | 
			
		||||
clean:
 | 
			
		||||
	rm -f offset-finder offsets.include
 | 
			
		||||
	$(MAKE) -C $(KERNELDIR) M=$(PWD) clean
 | 
			
		||||
 | 
			
		||||
.PHONY: clean
 | 
			
		||||
else
 | 
			
		||||
offset-finder-m := offset-finder.o
 | 
			
		||||
oldsrc := $(src)
 | 
			
		||||
src := $(src)/../../../src
 | 
			
		||||
include $(src)/compat/Kbuild.include
 | 
			
		||||
src := $(oldsrc)
 | 
			
		||||
endif
 | 
			
		||||
							
								
								
									
										20
									
								
								contrib/extract-handshakes/README
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								contrib/extract-handshakes/README
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,20 @@
 | 
			
		||||
Handshake Extractor
 | 
			
		||||
===================
 | 
			
		||||
 | 
			
		||||
This will extract private keys from outgoing handshake sessions, prior
 | 
			
		||||
to them being sent, via kprobes. It exports the bare minimum to be
 | 
			
		||||
able to then decrypt all packets in the handshake and in the subsequent
 | 
			
		||||
transport data session.
 | 
			
		||||
 | 
			
		||||
Build:
 | 
			
		||||
 | 
			
		||||
    $ make
 | 
			
		||||
 | 
			
		||||
Run (as root):
 | 
			
		||||
 | 
			
		||||
    # ./extract-handshakes.sh
 | 
			
		||||
    New handshake session:
 | 
			
		||||
      LOCAL_STATIC_PRIVATE_KEY = QChaGDXeH3eQsbFAhueUNWFdq9KfpF3yl+eITjZbXEk=
 | 
			
		||||
      REMOTE_STATIC_PUBLIC_KEY = HzgTY6aWXtuSyW/PUquZtg8LB/DyMwEXGkPiEmdSsUU=
 | 
			
		||||
      LOCAL_EPHEMERAL_PRIVATE_KEY = UNGdRHuKDeqbFvmiV5FD4wP7a8PqI6v3Xnnz6Jc6NXQ=
 | 
			
		||||
      PRESHARED_KEY = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
 | 
			
		||||
							
								
								
									
										80
									
								
								contrib/extract-handshakes/extract-handshakes.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										80
									
								
								contrib/extract-handshakes/extract-handshakes.sh
									
									
									
									
									
										Executable file
									
								
							@ -0,0 +1,80 @@
 | 
			
		||||
#!/bin/bash
 | 
			
		||||
# SPDX-License-Identifier: GPL-2.0
 | 
			
		||||
#
 | 
			
		||||
# Copyright (C) 2015-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
 | 
			
		||||
# Copyright (C) 2017-2018 Peter Wu <peter@lekensteyn.nl>. All Rights Reserved.
 | 
			
		||||
 | 
			
		||||
set -e
 | 
			
		||||
 | 
			
		||||
ME_DIR="${BASH_SOURCE[0]}"
 | 
			
		||||
ME_DIR="${ME_DIR%/*}"
 | 
			
		||||
source "$ME_DIR/offsets.include" || { echo "Did you forget to run make?" >&2; exit 1; }
 | 
			
		||||
 | 
			
		||||
case "$(uname -m)" in
 | 
			
		||||
	x86_64) ARGUMENT_REGISTER="%si" ;;
 | 
			
		||||
	i386|i686) ARGUMENT_REGISTER="%dx" ;;
 | 
			
		||||
	aarch64) ARGUMENT_REGISTER="%x1" ;;
 | 
			
		||||
	arm) ARGUMENT_REGISTER="%r1" ;;
 | 
			
		||||
	*) echo "ERROR: Unknown architecture" >&2; exit 1 ;;
 | 
			
		||||
esac
 | 
			
		||||
 | 
			
		||||
ARGS=( )
 | 
			
		||||
REGEX=".*: idxadd: .*"
 | 
			
		||||
for key in "${!OFFSETS[@]}"; do
 | 
			
		||||
	values="${OFFSETS[$key]}"
 | 
			
		||||
	values=( ${values//,/ } )
 | 
			
		||||
	for i in {0..3}; do
 | 
			
		||||
		value="$ARGUMENT_REGISTER"
 | 
			
		||||
		for indirection in "${values[@]:1}"; do
 | 
			
		||||
			value="+$indirection($value)"
 | 
			
		||||
		done
 | 
			
		||||
		value="+$((i * 8 + values[0]))($value)"
 | 
			
		||||
		ARGS+=( "${key,,}$i=$value:x64" )
 | 
			
		||||
		REGEX="$REGEX ${key,,}$i=0x([0-9a-f]+)"
 | 
			
		||||
	done
 | 
			
		||||
done
 | 
			
		||||
 | 
			
		||||
turn_off() {
 | 
			
		||||
	set +e
 | 
			
		||||
	[[ -f /sys/kernel/debug/tracing/events/wireguard/idxadd/enable ]] || exit
 | 
			
		||||
	echo 0 > /sys/kernel/debug/tracing/events/wireguard/idxadd/enable
 | 
			
		||||
	echo "-:wireguard/idxadd" >> /sys/kernel/debug/tracing/kprobe_events
 | 
			
		||||
	exit
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
trap turn_off INT TERM EXIT
 | 
			
		||||
echo "p:wireguard/idxadd index_hashtable_insert ${ARGS[*]}" >> /sys/kernel/debug/tracing/kprobe_events
 | 
			
		||||
echo 1 > /sys/kernel/debug/tracing/events/wireguard/idxadd/enable
 | 
			
		||||
 | 
			
		||||
unpack_u64() {
 | 
			
		||||
	local i expanded="$1"
 | 
			
		||||
	if [[ $ENDIAN == big ]]; then
 | 
			
		||||
		printf -v expanded "%.*s$expanded" $((16 - ${#expanded})) 0000000000000000
 | 
			
		||||
		for i in {0..7}; do
 | 
			
		||||
			echo -n "\\x${expanded:(i * 2):2}"
 | 
			
		||||
		done
 | 
			
		||||
	elif [[ $ENDIAN == little ]]; then
 | 
			
		||||
		(( ${#expanded} % 2 == 1 )) && expanded="0$expanded"
 | 
			
		||||
		expanded="${expanded}0000000000000000"
 | 
			
		||||
		for i in {0..7}; do
 | 
			
		||||
			echo -n "\\x${expanded:((7 - i) * 2):2}"
 | 
			
		||||
		done
 | 
			
		||||
	else
 | 
			
		||||
		echo "ERROR: Unable to determine endian" >&2
 | 
			
		||||
		exit 1
 | 
			
		||||
	fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
while read -r line; do
 | 
			
		||||
	[[ $line =~ $REGEX ]] || continue
 | 
			
		||||
	echo "New handshake session:"
 | 
			
		||||
	j=1
 | 
			
		||||
	for key in "${!OFFSETS[@]}"; do
 | 
			
		||||
		bytes=""
 | 
			
		||||
		for i in {0..3}; do
 | 
			
		||||
			bytes="$bytes$(unpack_u64 "${BASH_REMATCH[j]}")"
 | 
			
		||||
			((++j))
 | 
			
		||||
		done
 | 
			
		||||
		echo "  $key = $(printf "$bytes" | base64)"
 | 
			
		||||
	done
 | 
			
		||||
done < /sys/kernel/debug/tracing/trace_pipe
 | 
			
		||||
							
								
								
									
										44
									
								
								contrib/extract-handshakes/offset-finder.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								contrib/extract-handshakes/offset-finder.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,44 @@
 | 
			
		||||
/* SPDX-License-Identifier: GPL-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2015-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
struct def {
 | 
			
		||||
	const char *name;
 | 
			
		||||
	unsigned long offset;
 | 
			
		||||
	unsigned long indirection_offset;
 | 
			
		||||
};
 | 
			
		||||
extern const struct def defs[];
 | 
			
		||||
 | 
			
		||||
#ifdef __KERNEL__
 | 
			
		||||
#include "../../../src/noise.h"
 | 
			
		||||
 | 
			
		||||
const struct def defs[] = {
 | 
			
		||||
	{ "LOCAL_STATIC_PRIVATE_KEY", offsetof(struct noise_static_identity, static_private), offsetof(struct noise_handshake, static_identity) },
 | 
			
		||||
	{ "LOCAL_EPHEMERAL_PRIVATE_KEY", offsetof(struct noise_handshake, ephemeral_private), -1 },
 | 
			
		||||
	{ "REMOTE_STATIC_PUBLIC_KEY", offsetof(struct noise_handshake, remote_static), -1 },
 | 
			
		||||
	{ "PRESHARED_KEY", offsetof(struct noise_handshake, preshared_key), -1 },
 | 
			
		||||
	{ NULL, 0 }
 | 
			
		||||
};
 | 
			
		||||
#else
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
int main(int argc, char *argv[])
 | 
			
		||||
{
 | 
			
		||||
	puts("declare -A OFFSETS=(");
 | 
			
		||||
	for (const struct def *def = defs; def->name; ++def) {
 | 
			
		||||
		printf("\t[%s]=%ld", def->name, def->offset);
 | 
			
		||||
		if (def->indirection_offset != -1)
 | 
			
		||||
			printf(",%ld", def->indirection_offset);
 | 
			
		||||
		putchar('\n');
 | 
			
		||||
	}
 | 
			
		||||
	puts(")");
 | 
			
		||||
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
 | 
			
		||||
	puts("ENDIAN=big");
 | 
			
		||||
#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
 | 
			
		||||
	puts("ENDIAN=little");
 | 
			
		||||
#else
 | 
			
		||||
#error "Unsupported endianness"
 | 
			
		||||
#endif
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
		Reference in New Issue
	
	Block a user