]> git.ipfire.org Git - thirdparty/wireguard-tools.git/commitdiff
contrib: add extract-handshakes kprobe example
authorJason A. Donenfeld <Jason@zx2c4.com>
Tue, 27 Feb 2018 23:17:43 +0000 (00:17 +0100)
committerJason A. Donenfeld <Jason@zx2c4.com>
Sun, 4 Mar 2018 17:50:25 +0000 (18:50 +0100)
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
.gitignore
contrib/extract-handshakes/.gitignore [new file with mode: 0644]
contrib/extract-handshakes/Makefile [new file with mode: 0644]
contrib/extract-handshakes/README [new file with mode: 0644]
contrib/extract-handshakes/extract-handshakes.sh [new file with mode: 0755]
contrib/extract-handshakes/offset-finder.c [new file with mode: 0644]

index 83768f6b3c7745dd8e3807e647c4d5fa897499d3..4f9e9fcc5203c98f80f49fd3ff93342448c33009 100644 (file)
@@ -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 (file)
index 0000000..4196119
--- /dev/null
@@ -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 (file)
index 0000000..36e951e
--- /dev/null
@@ -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 (file)
index 0000000..1d030fa
--- /dev/null
@@ -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 (executable)
index 0000000..16ed630
--- /dev/null
@@ -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
diff --git a/contrib/extract-handshakes/offset-finder.c b/contrib/extract-handshakes/offset-finder.c
new file mode 100644 (file)
index 0000000..d0bc69c
--- /dev/null
@@ -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