From d4421aea8907f15bd1b504c0377624bda752381a Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Wed, 28 Feb 2018 00:17:43 +0100 Subject: [PATCH] contrib: add extract-handshakes kprobe example Signed-off-by: Jason A. Donenfeld --- .gitignore | 1 + contrib/extract-handshakes/.gitignore | 3 + contrib/extract-handshakes/Makefile | 28 +++++++ contrib/extract-handshakes/README | 20 +++++ .../extract-handshakes/extract-handshakes.sh | 80 +++++++++++++++++++ contrib/extract-handshakes/offset-finder.c | 44 ++++++++++ 6 files changed, 176 insertions(+) create mode 100644 contrib/extract-handshakes/.gitignore create mode 100644 contrib/extract-handshakes/Makefile create mode 100644 contrib/extract-handshakes/README create mode 100755 contrib/extract-handshakes/extract-handshakes.sh create mode 100644 contrib/extract-handshakes/offset-finder.c diff --git a/.gitignore b/.gitignore index 83768f6..4f9e9fc 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ src/tests/qemu/distfiles/ *.nam *.til *.pro.user +.cache.mk diff --git a/contrib/extract-handshakes/.gitignore b/contrib/extract-handshakes/.gitignore new file mode 100644 index 0000000..4196119 --- /dev/null +++ b/contrib/extract-handshakes/.gitignore @@ -0,0 +1,3 @@ +offset-finder.o +offset-finder +offsets.include diff --git a/contrib/extract-handshakes/Makefile b/contrib/extract-handshakes/Makefile new file mode 100644 index 0000000..36e951e --- /dev/null +++ b/contrib/extract-handshakes/Makefile @@ -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 diff --git a/contrib/extract-handshakes/README b/contrib/extract-handshakes/README new file mode 100644 index 0000000..1d030fa --- /dev/null +++ b/contrib/extract-handshakes/README @@ -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= diff --git a/contrib/extract-handshakes/extract-handshakes.sh b/contrib/extract-handshakes/extract-handshakes.sh new file mode 100755 index 0000000..16ed630 --- /dev/null +++ b/contrib/extract-handshakes/extract-handshakes.sh @@ -0,0 +1,80 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (C) 2015-2018 Jason A. Donenfeld . All Rights Reserved. +# Copyright (C) 2017-2018 Peter Wu . 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 diff --git a/contrib/extract-handshakes/offset-finder.c b/contrib/extract-handshakes/offset-finder.c new file mode 100644 index 0000000..d0bc69c --- /dev/null +++ b/contrib/extract-handshakes/offset-finder.c @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2015-2018 Jason A. Donenfeld . 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 +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