mirror of
https://github.com/bol-van/ipobfs.git
synced 2025-12-16 20:07:08 +03:00
280 lines
29 KiB
Plaintext
280 lines
29 KiB
Plaintext
English
|
||
-------
|
||
|
||
see readme.eng.txt
|
||
|
||
Для чего это нужно
|
||
------------------
|
||
|
||
На нас надвигается эпоха, когда повсеместно могут начать блокировать уже не отдельные IP адреса или домены, а протоколы.
|
||
Одним из способов возможного преодоления сигнатурного анализа на DPI является модификация протокола.
|
||
Лучший способ - модифицировать сам софт, работающий с этими протоколами. Но не всегда это бывает просто или возможно.
|
||
Для TCP существует obfsproxy. Однако, в случае VPN - по TCP работают только не очень быстрые решения (openvpn).
|
||
|
||
Что же делать в случае udp ?
|
||
Если оба endpoint-а находятся на белом IP, то можно как следует поизвращаться прямо на уровне IP и дальше.
|
||
Например, если у вас VPS, а дома роутер на openwrt, вы имеете прямой IP от провайдера, то можно применить эту технику.
|
||
Если один endpoint находится за NAT, то можно как следует поизвращаться на уровне udp или tcp,
|
||
не трогая IP и начало заголовков tcp/udp.
|
||
|
||
Схема выглядит следующим образом :
|
||
peer 1 <=> обфускатор/деобфускатор IP <=> сеть <=> обфускатор/деобфускатор IP <=> peer 2
|
||
|
||
Чтобы пакет был доставлен от peer 1 до peer 2, оба имеющих белые IP, достаточно лишь иметь корректные IP заголовки.
|
||
Можно выставить любой protocol number, проксорить или зашифровать IP payload, включая tcp/udp хедеры.
|
||
DPI от такого может выпасть в осадок. Оно не будет понимать с чем имеет дело.
|
||
Какие-то нестандартные IP протоколы с непонятно каким наполнением.
|
||
Конечно, DPI может обрезать весь мусор (по его мнению), но совсем не обязательно будет это делать.
|
||
Обычная программа не может сгененировать подобного типа "мусор", если только не использует raw sockets.
|
||
Значит разработчики DPI вряд ли поставят себе целью ловить рыбку в "мутной воде", если только какое-то решение
|
||
по обходу DPI на базе этой техники не станет достаточно популярным или белосписочность фильтров не достигнет высокого уровня.
|
||
|
||
|
||
ipobfs
|
||
------
|
||
|
||
Обработчик очереди NFQUEUE, обфускатор/деобфускатор пакетов.
|
||
|
||
--daemon ; демонизировать прогу
|
||
--pidfile=<file> ; сохранить PID в файл
|
||
--user=<username> ; менять uid процесса
|
||
--uid=uid[:gid] ; менять uid процесса
|
||
--qnum=200 ; номер очереди
|
||
--debug ; вывод отладочной информации
|
||
--ipproto-xor=0..255|0x00..0xFF; проксорить protocol number с указанным значением
|
||
--data-xor=0xDEADBEAF ; проксорить содержимое IP payload указанным 32-битным HEX значением
|
||
--data-xor-offset=<position> ; начинать проксоривание со смещения position после IP хедера
|
||
--data-xor-len=<bytes> ; ксорить не более указанного количества байтов, начиная с позиции data-xor-offset
|
||
--csum=none|fix|valid ; режим работы с чексуммой транспортных хедеров tcp и udp
|
||
|
||
Операция xor симметрична, поэтому для обфускатора и деобфускатора задаются одни и те же параметры.
|
||
На каждой стороне запускается по одному экземпляру программы.
|
||
|
||
Придется немного повозиться с iptables. Отфильтровать исходящий пакет просто, потому что он
|
||
идет "в открытую". На входящий пакет придется писать фильтры через u32.
|
||
Номер протокола ("-p") в фильтре - это результат xor исходного протокола с ipproto-xor.
|
||
|
||
server ipv4 udp:16 :
|
||
iptables -t mangle -I PREROUTING -i eth0 -p 145 -m u32 --u32 "0>>22&0x3C@0&0xFFFF=16" -j NFQUEUE --queue-num 300 --queue-bypass
|
||
iptables -t mangle -I POSTROUTING -o eth0 -p udp --sport 16 -j NFQUEUE --queue-num 300 --queue-bypass
|
||
|
||
client ipv4 udp:16 :
|
||
iptables -t mangle -I PREROUTING -i eth0 -p 145 -m u32 --u32 "0>>22&0x3C@0>>16&0xFFFF=16" -j NFQUEUE --queue-num 300 --queue-bypass
|
||
iptables -t mangle -I POSTROUTING -o eth0 -p udp --dport 16 -j NFQUEUE --queue-num 300 --queue-bypass
|
||
|
||
ipobfs --qnum=300 --ipproto-xor=128 --data-xor=0x458A2ECD --data-xor-offset=4 --data-xor-len=44
|
||
|
||
Почему data-xor-offset=4 : у tcp и udp в начале загловка идут номера порта источника и приемника, по 2 байта на каждый.
|
||
Чтобы проще было писать u32 не трогаем номера портов. Можно и тронуть, но тогда придется вычислить что же получится
|
||
после проксоривания и писать в u32 уже эти значения.
|
||
Почему data-xor-len=44 : пример приведен для wireguard. 44 байта достаточно, чтобы заксорить udp header и все заголовки wireguard.
|
||
Дальше идут шифрованные данные wireguard, их ксорить смысла нет.
|
||
|
||
Можно даже превратить udp в "tcp мусор" при ipproto-xor=23. Согласно заголовку ip это tcp, но на месте tcp хедера мусор.
|
||
Такого рода пакеты с одной стороны могут нарваться на middle-боксы, и на них сойдет с ума conntrack.
|
||
С другой стороны это может оказаться даже хорошо.
|
||
|
||
С ipv6 есть нюансы. В ipv6 нет понятия номера протокола. Зато есть понятие "next header".
|
||
Как и в ipv4 можно туда записать все что угодно. Но на практике это может вызвать лавину ICMPv6 собщений "Type 4 - Parameter Problem".
|
||
Чтобы этого избежать, надо приводить протокол к значению 59. Оно означает "no Next Header".
|
||
Проксорьте 59 с номером исходного протокола, получите параметр для "ipproto-xor".
|
||
Например, для udp номер протокола - 17. ipproto-xor=17^59=42
|
||
Для tcp номер протокола - 6. ipproto-xor=6^59=61
|
||
|
||
server ipv6 tcp:12345 :
|
||
ip6tables -t mangle -I PREROUTING -i eth0 -p 59 -m u32 --u32 "40&0xFFFF=12345" -j NFQUEUE --queue-num 300 --queue-bypass
|
||
ip6tables -t mangle -I POSTROUTING -o eth0 -p tcp --sport 12345 -j NFQUEUE --queue-num 300 --queue-bypass
|
||
|
||
client ipv6 tcp:12345 :
|
||
ip6tables -t mangle -I PREROUTING -i eth0 -p 59 -m u32 --u32 "38&0xFFFF=12345" -j NFQUEUE --queue-num 300 --queue-bypass
|
||
ip6tables -t mangle -I POSTROUTING -o eth0 -p tcp --dport 12345 -j NFQUEUE --queue-num 300 --queue-bypass
|
||
|
||
ipobfs --qnum=300 --ipproto-xor=61 --data-xor=0x458A2ECD --data-xor-offset=4
|
||
|
||
|
||
IP ФРАГМЕНТАЦИЯ
|
||
Если отсылающий хост посылает слишком длинный пакет, он фрагментируется на уровне IP.
|
||
Принимающий хост собирает пакеты только адресованные самому хосту.
|
||
В цепочке PREROUTING идут еще фрагментированные пакеты. При применении деобфускации
|
||
только к части пакета чексумма неизбежно оказывается инвалидной. csum=fix не помогает.
|
||
Для ipv4 помогает добавление правила в цепочку INPUT вместо PREROUTING.
|
||
Само собой, так ловятся только пакеты, адресованные самому хосту, зато они приходят
|
||
в NFQEUEUE уже собранными и корректно деобфусцируются.
|
||
Фрагментация IP - нежелательное явление, с ней следует бороться выставлением корректного mtu
|
||
внутри тоннеля. Есть некоторые протоколы, которые расчитывают на ip фрагментацию. К ним относится IKE (без rfc7383).
|
||
|
||
IPV6 ФРАГМЕНТАЦИЯ
|
||
В ipv6 тоже возможна фрагментация, однако она выполняется только отсылающим хостом, как правило только для
|
||
udp и icmp, когда фрейм не влезает в mtu. Ко всем фрагментам сразу после ipv6 хедера добавляется хедер "44".
|
||
К сожалению, все попытки поймать реконструированный полный фрейм в различных таблицах не приводят к успеху.
|
||
Ловится только первый фрагмент. Причину так и не удалось выяснить. Баг это или фича известно разве что Торвальдсу.
|
||
Так что лучший совет - не допускать фрагментации вовсе.
|
||
|
||
ЧЕКСУММЫ :
|
||
Работа с чексуммами начинается, когда через обфускатор проходит пакет tcp или udp.
|
||
Для входящих пакетов сначала выполняется операция ipproto-xor, и уже после нее анализируется получился ли пакет tcp или udp.
|
||
Для исходящих - наоборот.
|
||
--csum=none - не трогать чексуммы вообще. если после деобфускации чексумма окажется инвалидной, система отбросит пакет.
|
||
--csum=fix - режим игнорирования чексуммы. технически невозможно в NFQUEUE отключить проверку чексумм, потому чексумма
|
||
приводится к валидному значению, чтобы система не отбросила пакет. работает только для входящих пакетов.
|
||
--csum=valid - приводить чексумму к валидному состоянию для всех пакетов - входящих и исходящих. Режим полезен при работе через NAT,
|
||
не пропускающие пакеты с инвалидной чексуммой.
|
||
Пересчет чексумм увеличивает нагрузку на cpu.
|
||
См. так же раздел "пробитие NAT".
|
||
|
||
НЕДОСТАТКИ :
|
||
Каждый пакет будет забрасываться в nfqueue, потому скорость значительно снизится. В 2-3 раза.
|
||
Если сравнивать wireguard+ipobfs с openvpn на soho роутере, то openvpn все равно окажется медленней.
|
||
|
||
|
||
ipobfs_mod
|
||
-----------
|
||
|
||
То же самое, что и ipobfs, только выполнен в виде модуля ядра linux. Дает просадку производительности всего в пределах 20%.
|
||
|
||
По логике функционирования дублирует ipobfs и совместим с ним.
|
||
Значит можно на 1 хосте включить ipobfs, на другом ipobfs_mod, и они вместе будут работать.
|
||
Однако, по умолчанию ipobfs_mod будет продуцировать tcp и udp пакеты с инвалидной чексуммой, система
|
||
с ipobfs их будет отбрасывать. Используйте csum=fix на стороне ipobfs_mod.
|
||
|
||
Команды iptables те же самые, только вместо направления на очередь NFQEUEUE выставляется бит в fmwark.
|
||
ipobfs_mod реагирует на выставленные биты и производит обработку пакетов.
|
||
|
||
Настройки передаются через параметры модуля ядра, задаваемые командой insmod.
|
||
|
||
server ipv4 udp:16 :
|
||
iptables -t mangle -I PREROUTING -i eth0 -p 145 -m u32 --u32 "0>>22&0x3C@0&0xFFFF=16" -j MARK --set-xmark 0x100/0x100
|
||
iptables -t mangle -I POSTROUTING -o eth0 -p udp --sport 16 -j MARK --set-xmark 0x100/0x100
|
||
|
||
client ipv4 udp:16 :
|
||
iptables -t mangle -I PREROUTING -i eth0 -p 145 -m u32 --u32 "0>>22&0x3C@0>>16&0xFFFF=16" -j MARK --set-xmark 0x100/0x100
|
||
iptables -t mangle -I POSTROUTING -o eth0 -p udp --dport 16 -j MARK --set-xmark 0x100/0x100
|
||
|
||
rmmod ipobfs
|
||
insmod /lib/modules/`uname -r`/extra/ipobfs.ko mark=0x100 ipp_xor=128 data_xor=0x458A2ECD data_xor_offset=4 data_xor_len=44
|
||
|
||
Модуль поддерживает до 32 профилей. Настройки параметров для каждого профиля идут через запятую.
|
||
Например, следующая команда объединит функции 2 обработчиков NFQUEUE из предыдущих примеров :
|
||
insmod /lib/modules/`uname -r`/extra/ipobfs.ko mark=0x100,0x200 ipp_xor=128,61 data_xor=0x458A2ECD,0x458A2ECD data_xor_offset=4,4 data_xor_len=44,0
|
||
Возможно применение разных профилей для исходящих и входящих пакетов. Так вы еще больше запутаете DPI, уменьшив корреляцию in/out потоков.
|
||
Если задан параметр markmask, то профиль ищется по маске mask/markmask, в противном случае по маске mark/mark.
|
||
markmask - один на все профили, через запятую перечилять для каждого профиля не нужно.
|
||
Используйте markmask, когда у вас много профилей, чтобы не расходовать по биту на каждый.
|
||
Например, следующий вариант может вместить 15 профилей в 4 бита : 0x10/0xf0, 0x20/0xf0, ..., 0xf0/0xf0
|
||
0x00/0xf0 означает, что пакет не обрабатывается модулем.
|
||
|
||
По умолчанию модуль устанавливает хук на входящие пакеты с приоритетом mangle+1, чтобы к моменту вызова была выполнена таблица mangle.
|
||
Если на вход поступают нестандартные протоколы, все в порядке. Но если идут пакеты с транспортным протоколом, в которых предусмотрена
|
||
чексумма, такие как tcp или udp, то модифицированные пакеты с инвалидной чексуммой до хука mangle+1 не доходят. Модуль их не получает.
|
||
Чтобы решить эту проблему, укажите параметр pre=raw и делайте : iptables -t raw -I PREROUTING ...
|
||
Исходящие пакеты можно обрабатывать в обычном порядке через mangle.
|
||
|
||
Если необходимо работать с фрагментированными ipv4 протоколами, замените в iptables PREROUTING на INPUT (см замечание в разделе ipobfs),
|
||
укажите параметр модуля "prehook=input".
|
||
|
||
Параметры pre,prehook,post,posthook задаются индивидуально для каждого профиля, поэтому если профилей несколько, их нужно перечислять
|
||
через запятую.
|
||
|
||
Модуль отключает проверку и подсчет чексумм на уровне ОС для обрабатываемых пакетов, в некоторых случаях пересчитывая
|
||
чексуммы tcp и udp самостоятельно.
|
||
Если параметр csum=none, модуль не считает суммы вообще. Сумма исходящего пакета может оказаться невалидной.
|
||
При csum=fix модуль считает сумму исходящего пакета до модификации пейлоада, тем самым повторяя функции ОС
|
||
или offload-а на сетевой карточке, чтобы они не сделали это на уже модифицированном пейлоаде и не испортили 2 байта данных,
|
||
а передаваемый пакет после деобфускации содержал корректную чексумму.
|
||
Если csum=valid, пересчет чексуммы производится после модификации пейлоада, как для исходящих, так и для входящих пакетов.
|
||
Тем самым обеспечивается видимость передачи пакетов с валидной чексуммой. Коррекция чексуммы на входящем пакете необходима,
|
||
если устройство с ipobfs не является получателем пакета, а выполняет функцию роутера (forward). Чтобы на выходном интерфейсе был валидный пакет.
|
||
Обычный получатель не примет пакеты с инвалидной чексуммой.
|
||
|
||
Параметр debug=1 включает вывод отладочной информации. Вы увидите что делается с каждым обрабатываемым пакетом в dmesg.
|
||
Его стоит применять только для отладки. При большом количестве пакетов система сильно затормозится из-за избыточного вывода в dmesg.
|
||
|
||
Посмотреть и изменить некоторые параметры ipobfs можно без перезагрузки модуля : /sys/module/ipobfs/parameters
|
||
|
||
СБОРКА МОДУЛЯ ЯДРА на традиционной linux системе :
|
||
установить заголовки ядра. для debian :
|
||
sudo apt-get install linux-headers.....
|
||
cd ipobfs_mod
|
||
make
|
||
sudo make install
|
||
|
||
ЗАМЕЧАНИЕ ПО СКОРОСТИ :
|
||
Если задан только ipproto-xor, замеделение можно считать нулевым. Выполняется простейшая операция изменения 1 байта.
|
||
Тем не менее даже такой трюк может помочь обойти dpi.
|
||
Если используется data-xor, то старайтесь ксорить только начало пакета. Если ксорение не выходит за пределы ~100-140 байт,
|
||
скорее всего не придется выполнять ресурсоемкую операцию skb_linearize. Именно на ней тратится больше всего ресурсов cpu.
|
||
С debug=1 можно проверить выполняется ли linearize.
|
||
|
||
openwrt
|
||
-------
|
||
|
||
На системе linux скачайте и распакуйте SDK от вашей версии прошивки для вашего девайса.
|
||
Версия SDK должна в точности соответствовать версии прошивки, иначе вы не соберете подходящий модуль ядра.
|
||
Если вы собирали прошивку самостоятельно, вместо SDK можно и нужно использовать этот buildroot.
|
||
scripts/feeds update -a
|
||
scripts/feeds install -a
|
||
Скопируйте openwrt/* в SDK, сохраняя структуру директорий.
|
||
В packages/ipobfs, там где Makefile, поместите каталоги ipobfs и ipobfs_mod с исходниками.
|
||
Из корня SDK : make package/ipobfs/compile V=99
|
||
Должны получиться 2 ipk : bin/packages/..../ipobfs..ipk и bin/targets/..../kmod-ipobfs..ipk
|
||
Переносите их на девайс, устанавливаете через "opkg install ...ipk". Устанавливать можно только то, что вам нужно : ipobfs или kmod-ipobfs.
|
||
|
||
|
||
Пробитие NAT
|
||
------------
|
||
|
||
В общем случае можно утверждать, что NAT способны пропускать лишь трафик tcp, udp, icmp.
|
||
+ некоторые NAT еще содержат хелперы для пропуска особых протоколов (GRE). Но не все и не на всех устройствах.
|
||
NAT может пропускать нестандартные IP протоколы, но у него нет средств отследить исходный IP, который инициировал
|
||
отсылку. Если нестандартные протоколы и будут работать через NAT, то только для одного устройства за NAT.
|
||
Использование одного IP протокола более чем одним устройством за NAT невозможно. Будет конфликт.
|
||
Учитывая этот факт, ipproto-xor применять можно, но осторожно.
|
||
|
||
Рассмотрим NAT на базе linux (почти все домашние роутеры) без хелперов.
|
||
Как показывает исследование, для него важны поля транспортного хедера, содержащие длину пейлоада и флаги.
|
||
Поэтому, минимальный xor-data-offset для tcp - 14 , для udp - 6. Иначе пакет вовсе не пройдет NAT.
|
||
|
||
Любой NAT обязательно будет следить за флагами tcp, ведь по ним conntrack определяет начало установки соединения.
|
||
Без conntrack не работает ни один NAT. Смещение флагов в tcp header - 13.
|
||
|
||
Linux conntrack по умолчанию проверяет чексуммы транспортных протоколов и не учитывает пакеты с инвалидной чексуммой.
|
||
Такие пакеты не вызывают появление или изменение записей в таблице conntrack, статус пакетов - INVALID, операция SNAT
|
||
к ним применена не будет, тем не менее форвардинг пакета все равно случится в неизменном виде, с сохранением адреса источника
|
||
из внутренней сети. Чтобы этого избежать, правильно настроенные роутеры применяет правила вида
|
||
"-m state --state INVALID -j DROP" или "-m conntrack --ctstate INVALID -j DROP", тем самым запрещая форвардинг
|
||
пакетов, от которых отказался conntrack.
|
||
Поведение можно изменить командой "sysctl -w net.netfilter.nf_conntrack_checksum=0". В этом случае чексуммы считаться не будут,
|
||
conntrack будет принимать пакеты даже с инвалидной чексуммой, NAT работать будет.
|
||
В openwrt по умолчанию net.netfilter.nf_conntrack_checksum=0, так что система пропускает инвалидные пакеты.
|
||
Но остальные роутеры как правило не меняют значение по умолчанию, которое =1.
|
||
|
||
Все без исключения NAT будут исправлять 2-байтовую чексумму в tcp (смещение 18) и udp (смещение 6),
|
||
поскольку она считается с учетом ip источника и назначения. NAT меняет ip источника при отсылке, при невозможности
|
||
сохранить исходный source port меняется и он. Для экономии ресурсов полный пересчет суммы обычно не производится.
|
||
За основу берется исходная сумма, к ней добавляется разница между исходными и измененными значениями.
|
||
К получателю приходит пакет с инвалидной суммой, далее он деобфусцируется средствами ipobfs и сумма становится валидной,
|
||
если при обфускации не была затронута исходная сумма, то есть data-xor-offset>=20 для tcp и data-xor-offset>=8 для udp.
|
||
Обфускатор работает по xor, checksum считается сложением, поэтому они несовместимы.
|
||
ipobfs по умолчанию не пересчитывает чексуммы транспортных хедеров, поэтому если на принимающем конце используется он, то
|
||
data-xor-offset необходимо делать таким, чтобы чексумма не затрагивалась, иначе пакет будет отброшен системой после деобфускации.
|
||
альтернатива - использовать опцию --csum=fix
|
||
ipobfs_mod отключает проверку чексумм, поэтому при его использовании этой проблемы нет. поведение по умолчанию аналогично --csum=fix
|
||
Если применяется ipproto_xor, то роутер не будет пересчитывать суммы, пакет придет с инвалидной суммой после деобфускации.
|
||
|
||
Большинство роутеров выполняют mss fix ( -j TCPMSS --clamp-mss-to-pmtu или -j TCPMSS --set-mss ).
|
||
mss находится в опциях tcp header. Windows и linux шлют mss первой опцией. Сама опция занимает 4 байта.
|
||
Выходит, минимальный xor-data-offset для tcp поднимается до 24, чтобы не трогать mss, который попортит роутер.
|
||
|
||
ИТОГ :
|
||
tcp : data-xor-offset>=24
|
||
udp : data-xor-offset>=8
|
||
|
||
Если NAT не пропускает пакеты с инвалидной чексуммой, используйте настройку --csum=valid.
|
||
С точки зрения нагрузки на cpu предпочительней будет не использовать режим --csum=valid, если NAT пропускает пакеты с инвалидной чексуммой.
|
||
|
||
Есть информация, что некоторые мобильные операторы производят терминацию tcp на своих серверах для последующего
|
||
проксирования к точке исходного назначения. В этом случае любая модификация tcp не на уровне потока данных обречена на провал.
|
||
Терминирующий middlebox отвергнет пакеты с испорченным заголовком или неверной чексуммой.
|
||
Исходящее соединение от middlebox не будет повторять такое же разбиение на пакеты, как исходное соединение.
|
||
Пользуйтесь obfsproxy.
|