contrib: add extract-handshakes kprobe example
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
parent
e6ce5fd386
commit
d4421aea89
6 changed files with 176 additions and 0 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -20,3 +20,4 @@ src/tests/qemu/distfiles/
|
||||||
*.nam
|
*.nam
|
||||||
*.til
|
*.til
|
||||||
*.pro.user
|
*.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
|
Loading…
Reference in a new issue