From 674fa53b19378a44725ab8d1f61cd69116865fc1 Mon Sep 17 00:00:00 2001 From: bolvan Date: Mon, 29 Apr 2019 12:50:56 +0300 Subject: [PATCH] wireguard modding guide --- wireguard/010-wg-mod.patch | 138 ++++++++++++ wireguard/wireguard-mod.txt | 205 ++++++++++++++++++ .../wireguard_iproute_openwrt.txt | 0 3 files changed, 343 insertions(+) create mode 100644 wireguard/010-wg-mod.patch create mode 100644 wireguard/wireguard-mod.txt rename wireguard_iproute_openwrt.txt => wireguard/wireguard_iproute_openwrt.txt (100%) diff --git a/wireguard/010-wg-mod.patch b/wireguard/010-wg-mod.patch new file mode 100644 index 0000000..892c6e1 --- /dev/null +++ b/wireguard/010-wg-mod.patch @@ -0,0 +1,138 @@ +Index: WireGuard-0.0.20190123/src/cookie.c +=================================================================== +--- WireGuard-0.0.20190123.orig/src/cookie.c ++++ WireGuard-0.0.20190123/src/cookie.c +@@ -193,6 +193,8 @@ void wg_cookie_message_create(struct mes + xchacha20poly1305_encrypt(dst->encrypted_cookie, cookie, COOKIE_LEN, + macs->mac1, COOKIE_LEN, dst->nonce, + checker->cookie_encryption_key); ++ // MOD : randomize trash ++ dst->header.trash = gen_trash(); + } + + void wg_cookie_message_consume(struct message_handshake_cookie *src, +Index: WireGuard-0.0.20190123/src/messages.h +=================================================================== +--- WireGuard-0.0.20190123.orig/src/messages.h ++++ WireGuard-0.0.20190123/src/messages.h +@@ -53,23 +53,41 @@ enum limits { + MAX_QUEUED_PACKETS = 1024 /* TODO: replace this with DQL */ + }; + ++/* + enum message_type { +- MESSAGE_INVALID = 0, +- MESSAGE_HANDSHAKE_INITIATION = 1, +- MESSAGE_HANDSHAKE_RESPONSE = 2, +- MESSAGE_HANDSHAKE_COOKIE = 3, +- MESSAGE_DATA = 4 ++ MESSAGE_INVALID = 0, ++ MESSAGE_HANDSHAKE_INITIATION = 1, ++ MESSAGE_HANDSHAKE_RESPONSE = 2, ++ MESSAGE_HANDSHAKE_COOKIE = 3, ++ MESSAGE_DATA = 4 + }; ++*/ ++ ++// MOD : message type ++enum message_type { ++ MESSAGE_INVALID = 0xE319CCD0, ++ MESSAGE_HANDSHAKE_INITIATION = 0x48ADE198, ++ MESSAGE_HANDSHAKE_RESPONSE = 0xFCA6A8F3, ++ MESSAGE_HANDSHAKE_COOKIE = 0x64A3BB18, ++ MESSAGE_DATA = 0x391820AA ++}; ++ ++// MOD : generate fast trash without true RNG ++__le32 gen_trash(void); + + struct message_header { +- /* The actual layout of this that we want is: +- * u8 type +- * u8 reserved_zero[3] +- * +- * But it turns out that by encoding this as little endian, +- * we achieve the same thing, and it makes checking faster. +- */ +- __le32 type; ++ /* The actual layout of this that we want is: ++ * u8 type ++ * u8 reserved_zero[3] ++ * ++ * But it turns out that by encoding this as little endian, ++ * we achieve the same thing, and it makes checking faster. ++ */ ++ ++ // MOD : trash field to change message size and add 4 byte offset to all fields ++ __le32 trash; ++ ++ __le32 type; + }; + + struct message_macs { +Index: WireGuard-0.0.20190123/src/noise.c +=================================================================== +--- WireGuard-0.0.20190123.orig/src/noise.c ++++ WireGuard-0.0.20190123/src/noise.c +@@ -17,6 +17,24 @@ + #include + #include + ++ ++// MOD : trash generator ++__le32 gtrash = 0; ++__le32 gen_trash(void) ++{ ++ if (gtrash) ++ { ++ gtrash = gtrash*1103515243 + 12345; ++ } ++ else ++ { ++ // first value is true random ++ wait_for_random_bytes(); ++ get_random_bytes_wait(>rash, sizeof(gtrash)); ++ } ++ return gtrash; ++} ++ + /* This implements Noise_IKpsk2: + * + * <- s +@@ -515,6 +533,10 @@ wg_noise_handshake_create_initiation(str + &handshake->entry); + + handshake->state = HANDSHAKE_CREATED_INITIATION; ++ ++ // MOD : randomize trash ++ dst->header.trash = gen_trash(); ++ + ret = true; + + out: +@@ -655,6 +677,10 @@ bool wg_noise_handshake_create_response( + &handshake->entry); + + handshake->state = HANDSHAKE_CREATED_RESPONSE; ++ ++ // MOD : randomize trash ++ dst->header.trash = gen_trash(); ++ + ret = true; + + out: +Index: WireGuard-0.0.20190123/src/send.c +=================================================================== +--- WireGuard-0.0.20190123.orig/src/send.c ++++ WireGuard-0.0.20190123/src/send.c +@@ -200,6 +200,10 @@ static bool encrypt_packet(struct sk_buf + header->header.type = cpu_to_le32(MESSAGE_DATA); + header->key_idx = keypair->remote_index; + header->counter = cpu_to_le64(PACKET_CB(skb)->nonce); ++ ++ // MOD : randomize trash ++ header->header.trash = gen_trash(); ++ + pskb_put(skb, trailer, trailer_len); + + /* Now we can encrypt the scattergather segments */ diff --git a/wireguard/wireguard-mod.txt b/wireguard/wireguard-mod.txt new file mode 100644 index 0000000..b626af0 --- /dev/null +++ b/wireguard/wireguard-mod.txt @@ -0,0 +1,205 @@ +Посвящено возможной блокировке в РФ VPN протоколов через DPI. +Предпосылками являются последние законодательные акты и во всю сочащиеся "секретные" записки. +В РФ разрабатываются и готовятся к применению более продвинутые решения по блокировке трафика. +Вполне вероятно будут резать стандартные VPN протоколы. Нам надо быть к этому готовыми. + +Один из возможных и перспективных путей решения данного вопроса - кустомная модификация +исходников VPN с целью незначительного изменения протокола, ломающего стандартные модули обнаружения в DPI. +Это относительно сложно, доступно только для гиков. +Никто не будет разрабатывать специальные модули обнаружения в DPI, если только кто-то не сделает простое и +удобное решение для всех, и его станут широко применять. Но это маловероятно, и даже если и так, +то всегда можно модифицировать протокол чуток по другому. Делать моды для DPI несравненно дольше +и дороже, чем клепать на коленке изменения протокола для wireguard. + +Рассмотрю что нам надо пропатчить в wireguard. Модифицированный wireguard проверен на виртуалках +с десктопным linux, он работает, сообщения в wireshark действительно не вписываются в стандартный +протокол и не опознаются. + +Wireguard протокол очень простой. Все сообщения описаны в messages.h +Поставим себе целью сделать 2 простые модификации : +1) Добавим в начало всех сообщений немного мусора, чтобы изменить размер сообщений и смещения полей +2) Изменим коды типов сообщений +Этого может быть вполне достаточно для обмана DPI + +--messages.h-------------------------- +/* +enum message_type { + MESSAGE_INVALID = 0, + MESSAGE_HANDSHAKE_INITIATION = 1, + MESSAGE_HANDSHAKE_RESPONSE = 2, + MESSAGE_HANDSHAKE_COOKIE = 3, + MESSAGE_DATA = 4 +}; +*/ + +// MOD : message type +enum message_type { + MESSAGE_INVALID = 0xE319CCD0, + MESSAGE_HANDSHAKE_INITIATION = 0x48ADE198, + MESSAGE_HANDSHAKE_RESPONSE = 0xFCA6A8F3, + MESSAGE_HANDSHAKE_COOKIE = 0x64A3BB18, + MESSAGE_DATA = 0x391820AA +}; + +// MOD : generate fast trash without true RNG +__le32 gen_trash(void); + +struct message_header { + /* The actual layout of this that we want is: + * u8 type + * u8 reserved_zero[3] + * + * But it turns out that by encoding this as little endian, + * we achieve the same thing, and it makes checking faster. + */ + + // MOD : trash field to change message size and add 4 byte offset to all fields + __le32 trash; + + __le32 type; +}; +-------------------------------------- + +Напишем функцию для генерации trash. Функция должна быть быстрая, важно не замедлить скорость. +Мы не расчитываем, что нас будут специально ловить, иначе бы пришлось делать полноценный обфускатор. +Задача лишь сломать стандартный модуль обнаружения протокола wireguard. Потому истинная рандомность +trash не важна. +Но все же немного "трэша" не повредит. Гонки между тредами так же пофигистичны. Это же трэш. + +--noise.c----------------------------- +// MOD : trash generator +__le32 gtrash = 0; +__le32 gen_trash(void) +{ + if (gtrash) + { + gtrash = gtrash*1103515243 + 12345; + } + else + { + // first value is true random + wait_for_random_bytes(); + get_random_bytes_wait(>rash, sizeof(gtrash)); + } + return gtrash; +} +-------------------------------------- + +Теперь осталось найти все места, где создаются сообщения и внести туда заполнение поля trash. +Сообщений всего 4. Их можно найти по присваиванию полю type одного из значений enum message_type. + +2 места в noise.c в функциях wg_noise_handshake_create_initiation и wg_noise_handshake_create_response, +1 место в cookie.c в функции wg_cookie_message_create +Дописываем в конец инициализации структуры сообщения : + +-------------------------------------- + // MOD : randomize trash + dst->header.trash = gen_trash(); +-------------------------------------- + +и 1 место в send.c в функции encrypt_packet + +-------------------------------------- + // MOD : randomize trash + header->header.trash = gen_trash(); +-------------------------------------- + + +Вот и весь патчинг. Полный patch (версия wireguard 0.0.20190123) лежит в 010-wg-mod.patch. +Патчинг кода - самое простое. Для десктопного linux дальше все просто. +Пересобираем через make, устанавливаем через make install, перегружаем +модуль wireguard, перезапускаем интерфейсы, и все готово. + +Настоящий геморой начнется когда вы это попытаетесь засунуть на роутер под openwrt. +Одна из больших проблем linux - отсутствие совместимости драйверов на уровне бинариков. +Поэтому собирать необходимо в точности под вашу версию ядра и в точности под его .config. +Вам придется либо полностью самостоятельно собирать всю прошивку, либо найти SDK в точности +от вашей версии прошивки для вашей архитектуры и собрать модуль с помощью этого SDK. +Последний вариант более легкий. +Для сборки вам понадобится система на linux x86_64. Ее можно установить в виртуалке. +Теоретически можно пользоваться WSL из win10, но на практике там очень медленное I/O, +по крайней мере на старых версиях win10. Безумно медленное. Будете собирать вечность. +Может в новых win10 что-то и улучшили, но я бы сразу расчитывал на полноценный linux. + +Находим здесь вашу версию : https://downloads.openwrt.org/ +Скачиваем файл openwrt-sdk-*.tar.xz или lede-sdk-*.tar.xz +Например : https://downloads.openwrt.org/releases/18.06.2/targets/ar71xx/generic/openwrt-sdk-18.06.2-ar71xx-generic_gcc-7.3.0_musl.Linux-x86_64.tar.xz +Если ваша версия непонятна или стара, то проще будет найти последнюю прошивку и перешить роутер. +Распаковываем SDK. Следующими командами можно собрать оригинальный вариант wireguard : + +# scripts/feeds update -a +# scripts/feeds install -a +# make defconfig +# make -j 4 package/wireguard + +Сборка будет довольно долгой. Ведь придется подтащить ядро, собрать его, собрать зависимости. +"-j 4" означает использовать 4 потока. Впишите вместо 4 количество доступных cpu cores. + +Получим следующие файлы : + +openwrt-sdk-18.06.2-ar71xx-generic_gcc-7.3.0_musl.Linux-x86_64/bin/targets/ar71xx/generic/packages/kmod-wireguard_4.9.152+0.0.20190123-1_mips_24kc.ipk + +openwrt-sdk-18.06.2-ar71xx-generic_gcc-7.3.0_musl.Linux-x86_64/bin/packages/mips_24kc/base/wireguard-tools_0.0.20190123-1_mips_24kc.ipk + + + +Но это будет оригинальный wireguard. Нам нужен патченый. +Установим quilt и mc для нормального редактора вместо vim : + +# sudo apt-get update +# sudo apt-get install quilt mc + +# make package/wireguard/clean + +# make package/wireguard/prepare V=s QUILT=1 + + +Сорцы приготовлены для сборки в : + openwrt-sdk-18.06.2-ar71xx-generic_gcc-7.3.0_musl.Linux-x86_64/build_dir/target-mips_24kc_musl/linux-ar71xx_generic/WireGuard-0.0.20190123/src + +# cd build_dir/target-mips_24kc_musl/linux-ar71xx_generic/WireGuard-0.0.20190123/src +# quilt push -a +# quilt new 010-wg-mod.patch +# export EDITOR=mcedit + +Далее будет открываться редактор mcedit, в который нужно вносить изменения в каждый файл : + +# quilt edit messages.h +# quilt edit cookie.c +# quilt edit noise.c +# quilt edit send.c +# quilt diff +# quilt refresh + +Получили файл патча в : +openwrt-sdk-18.06.2-ar71xx-generic_gcc-7.3.0_musl.Linux-x86_64/build_dir/target-mips_24kc_musl/linux-ar71xx_generic/WireGuard-0.0.20190123/patches/010-wg-mod.patch + +Выходим в корень SDK. + +# make package/wireguard/compile V=99 + +Если не было ошибок, то получили измененные ipk. +Патч можно зафиксировать в описании пакета : + +# make package/wireguard/update + +Получим : +openwrt-sdk-18.06.2-ar71xx-generic_gcc-7.3.0_musl.Linux-x86_64/feeds/base/package/network/services/wireguard/patches/010-wg-mod.patch +При последующей очистке и пересборке он будет автоматом применяться. + +Полученные ipk копируем на роутер в /tmp, устанавливаем через +# cd /tmp +# opkg install *.ipk +Если требует зависимостей, то +# opkg update +# opkg install .... <зависимости> +# opkg install *.ipk + +Если раньше уже был wireguard, то проще всего будет на всякий случай ребутнуться. + +Когда поднимите линк, и вдруг ничего не будет работать, то посмотрите в wireshark udp пакеты +на порт endpoint. Они не должны начинаться с 0,1,2,3,4. В первых 4 байтах должны быть +значения из измененного enum message_type. Если там все еще 0..4, значит модуль wireguard +оригинальный, что-то не собралось, не скопировалось, не перезапустилось. +В противном случае должен подняться линк, пинги ходить. Значит вы победили, поздравляю. +Регулятору будет намного сложнее поймать ваш VPN. diff --git a/wireguard_iproute_openwrt.txt b/wireguard/wireguard_iproute_openwrt.txt similarity index 100% rename from wireguard_iproute_openwrt.txt rename to wireguard/wireguard_iproute_openwrt.txt