mirror of
https://github.com/bol-van/zapret.git
synced 2025-05-24 22:32:58 +03:00
Compare commits
13 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
46284938ce | ||
|
09378553b9 | ||
|
6b85884cdf | ||
|
1b14a8210c | ||
|
182fe850db | ||
|
62b081e9fb | ||
|
e3e7449d74 | ||
|
669f1978a3 | ||
|
57c4b1a2b2 | ||
|
ac7385391e | ||
|
50a52d79ec | ||
|
d77a1c8cd6 | ||
|
395b9480c5 |
@@ -125,3 +125,13 @@ resolve_lower_devices()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
default_route_interfaces6()
|
||||
{
|
||||
sed -nre 's/^00000000000000000000000000000000 00 [0-9a-f]{32} [0-9a-f]{2} [0-9a-f]{32} [0-9a-f]{8} [0-9a-f]{8} [0-9a-f]{8} [0-9a-f]{8} +(.*)$/\1/p' /proc/net/ipv6_route | grep -v '^lo$' | sort -u | xargs
|
||||
}
|
||||
|
||||
default_route_interfaces4()
|
||||
{
|
||||
sed -nre 's/^([^\t]+)\t00000000\t[0-9A-F]{8}\t[0-9A-F]{4}\t[0-9]+\t[0-9]+\t[0-9]+\t00000000.*$/\1/p' /proc/net/route | sort -u | xargs
|
||||
}
|
||||
|
@@ -325,9 +325,9 @@ dvtws, собираемый из тех же исходников (см. [док
|
||||
|
||||
* **method** - начало метода HTTP ('GET', 'POST', 'HEAD', ...). Метод обычно всегда находится на позиции 0, но поддерживается и нахождение метода после дурение методом `--methodeol` от tpws. Тогда позиция может стать 1 или 2.
|
||||
* **host** - начало имени хоста в известном протоколе (http, TLS)
|
||||
* **endhost** - конец имени хоста
|
||||
* **endhost** - байт, следующий за последним байтом имени хоста
|
||||
* **sld** - начало домена 2 уровня в имени хоста
|
||||
* **endsld** - конец домена 2 уровня в имени хоста
|
||||
* **endsld** - байт, следующий за последним байтом домена 2 уровня в имени хоста
|
||||
* **midsld** - середина домена 2 уровня в имени хоста
|
||||
* **sniext** - начало поля данных SNI extension в TLS. Любой extension состоит из 2-байтовых полей type и length, за ними идет поле данных.
|
||||
|
||||
@@ -381,7 +381,7 @@ Windows оставляет старые данные, поэтому disorder с
|
||||
|
||||
### СПЕЦИФИЧЕСКИЕ РЕЖИМЫ IPV6
|
||||
|
||||
Режимы десинхронизации `hopbyhop`, `destopt` и `ipfrag1` (не путать с fooling !) относятся только к `ipv6` и заключается
|
||||
Режимы десинхронизации `hopbyhop`, `destopt` и `ipfrag1` (не путать с fooling !) относятся только к ipv6 и заключается
|
||||
в добавлении хедера `hop-by-hop options`, `destination options` или `fragment` во все пакеты, попадающие под десинхронизацию.
|
||||
Здесь надо обязательно понимать, что добавление хедера увеличивает размер пакета, потому не может быть применено
|
||||
к пакетам максимального размера. Это имеет место при передаче больших сообщений.
|
||||
@@ -398,7 +398,7 @@ extension хедерам в поисках транспортного хедер
|
||||
|
||||
В параметре dpi-desync можно указать до 3 режимов через запятую.
|
||||
|
||||
* 0 фаза - предполагает работу на этапе установления соединения : `synack`, `syndata` `--wsize`, `--wssize`. На эту фазу не действуют фильтры по [hostlist](((#множественные-стратегии))).
|
||||
* 0 фаза - предполагает работу на этапе установления соединения : `synack`, `syndata`, `--wsize`, `--wssize`. На эту фазу не действуют фильтры по [hostlist](#множественные-стратегии).
|
||||
* 1 фаза - отсылка чего-либо до оригинального пакета данных : `fake`, `rst`, `rstack`.
|
||||
* 2 фаза - отсылка в модифицированном виде оригинального пакета данных (например, `fakedsplit` или `ipfrag2`).
|
||||
|
||||
@@ -424,29 +424,10 @@ DPI может отстать от потока, если ClientHello его у
|
||||
|
||||
В документации по geneva это называется "TCB turnaround". Попытка ввести DPI в заблуждение относительно
|
||||
ролей клиента и сервера.
|
||||
!!! Поскольку режим нарушает работу NAT, техника может сработать только если между атакующим устройством
|
||||
|
||||
Поскольку режим нарушает работу NAT, техника может сработать только если между атакующим устройством
|
||||
и DPI нет NAT. Атака не сработает через NAT роутер, но может сработать с него.
|
||||
Для реализации атаки в linux обязательно требуется отключить стандартное правило firewall,
|
||||
дропающее инвалидные пакеты в цепочке OUTPUT. Например : `-A OUTPUT -m state --state INVALID -j DROP`
|
||||
В openwrt можно отключить drop INVALID в OUTPUT и FORWARD через опцию в /etc/config/firewall:
|
||||
|
||||
```
|
||||
config zone
|
||||
option name 'wan'
|
||||
.........
|
||||
option masq_allow_invalid '1'
|
||||
```
|
||||
|
||||
К сожалению, отключить только в OUTPUT таким образом нельзя. Но можно сделать иначе. Вписать в `/etc/firewall.user`:
|
||||
|
||||
```
|
||||
iptables -D zone_wan_output -m comment --comment '!fw3' -j zone_wan_dest_ACCEPT
|
||||
ip6tables -D zone_wan_output -m comment --comment '!fw3' -j zone_wan_dest_ACCEPT
|
||||
```
|
||||
|
||||
Лучше делать так, потому что отсутствие дропа INVALID в FORWARD может привести к нежелательным утечкам пакетов из LAN.
|
||||
Если не принять эти меры, отсылка SYN,ACK сегмента вызовет ошибку и операция будет прервана.
|
||||
Остальные режимы тоже не сработают. Если поймете, что вам synack не нужен, обязательно верните правило дропа INVALID.
|
||||
Для реализации атаки на проходящий трафик требуются nftables и схема [POSTNAT](#nftables-для-nfqws).
|
||||
|
||||
### РЕЖИМ SYNDATA
|
||||
|
||||
@@ -480,7 +461,7 @@ conntrack - простенький, он не писался с учетом в
|
||||
|
||||
`--wssize` позволяет изменить с клиента размер tcp window для сервера, чтобы он послал следующие ответы разбитыми на части.
|
||||
Чтобы это подействовало на все серверные ОС, необходимо менять window size в каждом исходящем с клиента пакете до отсылки сообщения,
|
||||
ответ на который должен быть разбит (например, TLS ClientHello). Именно поэтому и необходим conntrack, чтобы
|
||||
ответ на которое должен быть разбит (например, TLS ClientHello). Именно поэтому и необходим conntrack, чтобы
|
||||
знать когда надо остановиться. Если не остановиться и все время устанавливать низкий wssize, скорость упадет катастрофически.
|
||||
В linux это может быть купировано через connbytes, но в BSD системах такой возможности нет.
|
||||
В случае http(s) останавливаемся сразу после отсылки первого http запроса или TLS ClientHello.
|
||||
@@ -521,7 +502,7 @@ nfqws поддерживает реассемблинг некоторых ви
|
||||
На текущий момент это TLS и QUIC ClientHello. Они бывает длинными, если в chrome включить пост-квантовую
|
||||
криптографию tls-kyber, и занимают как правило 2 или 3 пакета. kyber включен по умолчанию, начиная с chromium 124.
|
||||
chrome рандомизирует фингерпринт TLS. SNI может оказаться как в начале, так и в конце, то есть
|
||||
попасть любой пакет. stateful DPI обычно реассемблирует запрос целиком, и только потом
|
||||
попасть в любой пакет. stateful DPI обычно реассемблирует запрос целиком, и только потом
|
||||
принимает решение о блокировке.
|
||||
В случае получения TLS или QUIC пакета с частичным ClientHello начинается процесс сборки, а пакеты
|
||||
задерживаются и не отсылаются до ее окончания. По окончании сборки пакеты проходит через десинхронизацию
|
||||
|
22
init.d/sysv/custom.d.examples/10-keenetic-udp-fix
Normal file
22
init.d/sysv/custom.d.examples/10-keenetic-udp-fix
Normal file
@@ -0,0 +1,22 @@
|
||||
# This script fixes keenetic issue with nfqws generated udp packets
|
||||
# Keenetic uses proprietary ndmmark and does not masquerade without this mark
|
||||
# If not masqueraded packets go to WAN with LAN IP and get dropped by ISP
|
||||
|
||||
# It's advised to set IFACE_WAN in config
|
||||
|
||||
zapret_custom_firewall()
|
||||
{
|
||||
# $1 - 1 - add, 0 - stop
|
||||
|
||||
local wan wanif rule
|
||||
|
||||
[ "$DISABLE_IPV4" = "1" ] || {
|
||||
# use IFACE_WAN if defined. if not - search for interfaces with default route.
|
||||
wanif=${IFACE_WAN:-$(sed -nre 's/^([^\t]+)\t00000000\t[0-9A-F]{8}\t[0-9A-F]{4}\t[0-9]+\t[0-9]+\t[0-9]+\t00000000.*$/\1/p' /proc/net/route | sort -u | xargs)}
|
||||
for wan in $wanif; do
|
||||
rule="-o $wan -p udp -m mark --mark $DESYNC_MARK/$DESYNC_MARK"
|
||||
ipt_print_op $1 "$rule" "keenetic udp fix"
|
||||
ipt_add_del $1 POSTROUTING -t nat $rule -j MASQUERADE
|
||||
done
|
||||
}
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
CC ?= gcc
|
||||
CFLAGS += -std=gnu99 -Os
|
||||
CFLAGS += -std=gnu99 -Os -flto=auto
|
||||
CFLAGS_BSD = -Wno-address-of-packed-member
|
||||
CFLAGS_WIN = -static
|
||||
LIBS =
|
||||
|
@@ -1,5 +1,5 @@
|
||||
CC ?= cc
|
||||
CFLAGS += -std=gnu99 -s -Os -Wno-address-of-packed-member
|
||||
CFLAGS += -std=gnu99 -s -Os -Wno-address-of-packed-member -flto=auto
|
||||
LIBS = -lz
|
||||
SRC_FILES = *.c crypto/*.c
|
||||
|
||||
|
@@ -1,7 +1,6 @@
|
||||
CC ?= gcc
|
||||
CFLAGS += -std=gnu99 -Os
|
||||
CFLAGS_BSD = -Wno-address-of-packed-member
|
||||
CFLAGS_MAC = -mmacosx-version-min=10.8
|
||||
CFLAGS_BSD = -Wno-address-of-packed-member -flto=auto
|
||||
CFLAGS_CYGWIN = -Wno-address-of-packed-member -static
|
||||
LIBS_LINUX = -lnetfilter_queue -lnfnetlink -lz
|
||||
LIBS_BSD = -lz
|
||||
|
@@ -1395,7 +1395,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
||||
if (i==0)
|
||||
{
|
||||
if (seqovl_pos>=from)
|
||||
DLOG("seqovl>=split_pos (%u>=%zu). cancelling seqovl for part %d.\n",seqovl,from,i+2);
|
||||
DLOG("seqovl>=split_pos (%zu>=%zu). cancelling seqovl for part %d.\n",seqovl,from,i+2);
|
||||
else
|
||||
{
|
||||
seqovl = seqovl_pos;
|
||||
@@ -1440,7 +1440,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
||||
|
||||
if (seqovl_pos>=split_pos)
|
||||
{
|
||||
DLOG("seqovl>=split_pos (%u>=%zu). cancelling seqovl.\n",seqovl_pos,split_pos);
|
||||
DLOG("seqovl>=split_pos (%zu>=%zu). cancelling seqovl.\n",seqovl_pos,split_pos);
|
||||
seqovl = 0;
|
||||
}
|
||||
else
|
||||
|
@@ -1,5 +1,5 @@
|
||||
CC ?= cc
|
||||
CFLAGS += -std=gnu99 -s -Os
|
||||
CFLAGS += -std=gnu99 -s -Os -flto=auto
|
||||
LIBS = -lz -lpthread
|
||||
SRC_FILES = *.c
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
CC ?= gcc
|
||||
CFLAGS += -std=gnu99 -Os
|
||||
CFLAGS += -std=gnu99 -Os -flto=auto
|
||||
CFLAGS_BSD = -Wno-address-of-packed-member
|
||||
LIBS = -lz -lpthread
|
||||
LIBS_ANDROID = -lz
|
||||
|
@@ -140,11 +140,6 @@ void tamper_out(t_ctrack *ctrack, const struct sockaddr *dest, uint8_t *segment,
|
||||
|
||||
if (bHaveHost)
|
||||
VPRINT("request hostname: %s\n", Host);
|
||||
if (ctrack->b_not_act)
|
||||
{
|
||||
VPRINT("Not acting on this request\n");
|
||||
return;
|
||||
}
|
||||
|
||||
bool bDiscoveredL7 = ctrack->l7proto==UNKNOWN && l7proto!=UNKNOWN;
|
||||
if (bDiscoveredL7)
|
||||
@@ -169,17 +164,25 @@ void tamper_out(t_ctrack *ctrack, const struct sockaddr *dest, uint8_t *segment,
|
||||
struct desync_profile *dp_prev = ctrack->dp;
|
||||
apply_desync_profile(ctrack, dest);
|
||||
if (ctrack->dp!=dp_prev)
|
||||
{
|
||||
VPRINT("desync profile changed by revealed l7 protocol or hostname !\n");
|
||||
ctrack->b_host_checked = ctrack->b_ah_check = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (bDiscoveredHostname && ctrack->dp->hostlist_auto)
|
||||
if (l7proto!=UNKNOWN && ctrack->dp->hostlist_auto)
|
||||
{
|
||||
bool bHostExcluded;
|
||||
if (!HostlistCheck(ctrack->dp, Host, &bHostExcluded, false))
|
||||
if (bHaveHost && !ctrack->b_host_checked)
|
||||
{
|
||||
bool bHostExcluded;
|
||||
ctrack->b_host_matches = HostlistCheck(ctrack->dp, Host, &bHostExcluded, false);
|
||||
ctrack->b_host_checked = true;
|
||||
if (!ctrack->b_host_matches)
|
||||
ctrack->b_ah_check = !bHostExcluded;
|
||||
}
|
||||
if (!ctrack->b_host_matches)
|
||||
{
|
||||
ctrack->b_ah_check = !bHostExcluded;
|
||||
VPRINT("Not acting on this request\n");
|
||||
ctrack->b_not_act = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@@ -14,8 +14,7 @@ typedef struct
|
||||
// common state
|
||||
t_l7proto l7proto;
|
||||
bool bTamperInCutoff;
|
||||
bool b_ah_check;
|
||||
bool b_not_act;
|
||||
bool b_host_checked,b_host_matches,b_ah_check;
|
||||
char *hostname;
|
||||
struct desync_profile *dp; // desync profile cache
|
||||
} t_ctrack;
|
||||
|
@@ -479,6 +479,30 @@ static int connect_remote(const struct sockaddr *remote_addr, int mss)
|
||||
return remote_fd;
|
||||
}
|
||||
|
||||
static bool connect_remote_conn(tproxy_conn_t *conn)
|
||||
{
|
||||
int mss=0;
|
||||
|
||||
apply_desync_profile(&conn->track, (struct sockaddr *)&conn->dest);
|
||||
|
||||
if (conn->track.dp)
|
||||
{
|
||||
mss = conn->track.dp->mss;
|
||||
if (conn->track.dp->hostlist_auto)
|
||||
{
|
||||
if (conn->track.hostname)
|
||||
{
|
||||
bool bHostExcluded;
|
||||
conn->track.b_host_matches = HostlistCheck(conn->track.dp, conn->track.hostname, &bHostExcluded, false);
|
||||
conn->track.b_host_checked = true;
|
||||
if (!conn->track.b_host_matches) conn->track.b_ah_check = !bHostExcluded;
|
||||
if (!conn->track.b_host_matches) mss = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (conn->partner->fd = connect_remote((struct sockaddr *)&conn->dest, mss))>=0;
|
||||
}
|
||||
|
||||
//Free resources occupied by this connection
|
||||
static void free_conn(tproxy_conn_t *conn)
|
||||
@@ -636,9 +660,7 @@ static tproxy_conn_t* add_tcp_connection(int efd, struct tailhead *conn_list,int
|
||||
conn->partner->client = conn->client;
|
||||
conn->partner->dest = conn->dest;
|
||||
|
||||
apply_desync_profile(&conn->track, (struct sockaddr *)&conn->dest);
|
||||
|
||||
if ((conn->partner->fd = connect_remote((struct sockaddr *)&orig_dst, conn->track.dp ? conn->track.dp->mss : 0)) < 0)
|
||||
if (!connect_remote_conn(conn))
|
||||
{
|
||||
DLOG_ERR("Failed to connect\n");
|
||||
free_conn(conn->partner);
|
||||
@@ -811,14 +833,7 @@ static bool proxy_mode_connect_remote(tproxy_conn_t *conn, struct tailhead *conn
|
||||
return false;
|
||||
}
|
||||
|
||||
apply_desync_profile(&conn->track, (struct sockaddr *)&conn->dest);
|
||||
|
||||
if ((remote_fd = connect_remote((struct sockaddr *)&conn->dest, conn->track.dp ? conn->track.dp->mss : 0)) < 0)
|
||||
{
|
||||
DLOG_ERR("socks failed to connect (1) errno=%d\n", errno);
|
||||
socks_send_rep_errno(conn->socks_ver, conn->fd, errno);
|
||||
return false;
|
||||
}
|
||||
if (!(conn->partner = new_conn(remote_fd, true)))
|
||||
{
|
||||
close(remote_fd);
|
||||
@@ -830,6 +845,15 @@ static bool proxy_mode_connect_remote(tproxy_conn_t *conn, struct tailhead *conn
|
||||
conn->partner->efd = conn->efd;
|
||||
conn->partner->client = conn->client;
|
||||
conn->partner->dest = conn->dest;
|
||||
|
||||
if (!connect_remote_conn(conn))
|
||||
{
|
||||
free_conn(conn->partner); conn->partner = NULL;
|
||||
DLOG_ERR("socks failed to connect (1) errno=%d\n", errno);
|
||||
socks_send_rep_errno(conn->socks_ver, conn->fd, errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!epoll_set(conn->partner, EPOLLOUT))
|
||||
{
|
||||
DLOG_ERR("socks epoll_set error %d\n", errno);
|
||||
|
Reference in New Issue
Block a user