nfqws: DHT and tamper

This commit is contained in:
bol-van 2023-09-07 19:03:37 +03:00
parent 91ac09a8bd
commit c91542d516
18 changed files with 97 additions and 33 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -237,3 +237,9 @@ nfqws : udplen fooling supports packet shrinking (negative increment value)
v49
QUIC support integrated to the main system and setup
v50
DHT protocol support.
DPI desync mode 'tamper' for DHT.
HEX string support in addition to binary files.

View File

@ -154,7 +154,7 @@ nfqws takes the following parameters:
--hostspell ; exact spelling of "Host" header. must be 4 chars. default is "host"
--hostnospace ; remove space after Host: and add it to User-Agent: to preserve packet size
--domcase ; mix domain case : Host: TeSt.cOm
--dpi-desync=[<mode0>,]<mode>[,<mode2>] ; try to desync dpi state. modes : synack fake fakeknown rst rstack hopbyhop destopt ipfrag1 disorder disorder2 split split2 ipfrag2 udplen
--dpi-desync=[<mode0>,]<mode>[,<mode2>] ; try to desync dpi state. modes : synack fake fakeknown rst rstack hopbyhop destopt ipfrag1 disorder disorder2 split split2 ipfrag2 udplen tamper
--dpi-desync-fwmark=<int|0xHEX> ; override fwmark for desync packet. default = 0x40000000 (1073741824)
--dpi-desync-ttl=<int> ; set ttl for desync packet
--dpi-desync-ttl6=<int> ; set ipv6 hop limit for desync packet. by default ttl value is used.
@ -173,6 +173,7 @@ nfqws takes the following parameters:
--dpi-desync-fake-unknown=<filename>|0xHEX ; file containing unknown protocol fake payload
--dpi-desync-fake-quic=<filename>|0xHEX ; file containing fake QUIC Initial
--dpi-desync-fake-wireguard=<filename>|0xHEX ; file containing fake wireguard handshake initiation
--dpi-desync-fake-dht=<filename>|0xHEX ; file containing fake DHT (d1..e)
--dpi-desync-fake-unknown-udp=<filename>|0xHEX ; file containing unknown udp protocol fake payload
--dpi-desync-udplen-increment=<int> ; increase or decrease udp packet length by N bytes (default 2). negative values decrease length.
--dpi-desync-udplen-pattern=<filename>|0xHEX ; udp tail fill pattern
@ -427,14 +428,15 @@ Set conntrack timeouts appropriately.
UDP attacks are limited. Its not possible to fragment UDP on transport level, only on network (ip) level.
Only desync modes `fake`,`hopbyhop`,`destopt`,`ipfrag1` and `ipfrag2` are applicable.
`fake`,`hopbyhop`,`destopt` can be used in combo with `ipfrag2` and `udplen`.
`fake`,`hopbyhop`,`destopt` can be used in combo with `ipfrag2`.
`fake` can be used in combo with `udplen` and `tamper`.
`udplen` increases udp payload size by `--dpi-desync-udplen-increment` bytes. Padding is filled with zeroes.
`udplen` increases udp payload size by `--dpi-desync-udplen-increment` bytes. Padding is filled with zeroes by default but can be overriden with a pattern.
This option can resist DPIs that track outgoing UDP packet sizes.
Requires that application protocol does not depend on udp payload size.
QUIC initial packets are recognized. Decryption and hostname extraction is supported so `--hostlist` parameter will work.
Wireguard handshake initiation is also recognized.
Wireguard handshake initiation and DHT packets are also recognized.
For other protocols desync use `--dpi-desync-any-protocol`.
Conntrack supports udp. `--dpi-desync-cutoff` will work. UDP conntrack timeout can be set in the 4th parameter of `--ctrack-timeouts`.

View File

@ -1,4 +1,4 @@
zapret v.49
zapret v.50
English
-------
@ -207,7 +207,7 @@ nfqws
--hostnospace ; убрать пробел после "Host:" и переместить его в конец значения "User-Agent:" для сохранения длины пакета
--hostspell=HoST ; точное написание заголовка Host (можно "HOST" или "HoSt"). автоматом включает --hostcase
--domcase ; домен после Host: сделать таким : TeSt.cOm
--dpi-desync=[<mode0>,]<mode>[,<mode2] ; атака по десинхронизации DPI. mode : synack fake fakeknown rst rstack hopbyhop destopt ipfrag1 disorder disorder2 split split2 ipfrag2 udplen
--dpi-desync=[<mode0>,]<mode>[,<mode2] ; атака по десинхронизации DPI. mode : synack fake fakeknown rst rstack hopbyhop destopt ipfrag1 disorder disorder2 split split2 ipfrag2 udplen tamper
--dpi-desync-fwmark=<int|0xHEX> ; бит fwmark для пометки десинхронизирующих пакетов, чтобы они повторно не падали в очередь. default = 0x40000000
--dpi-desync-ttl=<int> ; установить ttl для десинхронизирующих пакетов
--dpi-desync-ttl6=<int> ; установить ipv6 hop limit для десинхронизирующих пакетов. если не указано, используется значение ttl
@ -223,6 +223,7 @@ nfqws
--dpi-desync-fake-tls=<filename>|0xHEX ; файл, содержащий фейковый tls clienthello для dpi-desync=fake, на замену стандартному w3.org
--dpi-desync-fake-unknown=<filename>|0xHEX ; файл, содержащий фейковый пейлоад неизвестного протокола для dpi-desync=fake, на замену стандартным нулям 256 байт
--dpi-desync-fake-quic=<filename>|0xHEX ; файл, содержащий фейковый QUIC Initial
--dpi-desync-fake-dht=<filename>|0xHEX ; файл, содержащий фейковый пейлоад DHT протокола для dpi-desync=fake, на замену стандартным нулям 64 байт
--dpi-desync-fake-unknown-udp=<filename>|0xHEX ; файл, содержащий фейковый пейлоад неизвестного udp протокола для dpi-desync=fake, на замену стандартным нулям 64 байт
--dpi-desync-udplen-increment=<int> ; насколько увеличивать длину udp пейлоада в режиме udplen
--dpi-desync-udplen-pattern=<filename>|0xHEX ; чем добивать udp пакет в режиме udplen. по умолчанию - нули
@ -464,14 +465,17 @@ window size итоговый размер окна стал максимальн
ПОДДЕРЖКА UDP
Атаки на udp более ограничены в возможностях. udp нельзя фрагментировать иначе, чем на уровне ip.
Для UDP действуют только режимы десинхронизации fake,hopbyhop,destopt,ipfrag1,ipfrag2,udplen.
Возможно сочетание fake,hopbyhop,destopt с ipfrag2 и udplen.
Для UDP действуют только режимы десинхронизации fake,hopbyhop,destopt,ipfrag1,ipfrag2,udplen,tamper.
Возможно сочетание fake,hopbyhop,destopt с ipfrag2, fake,fakeknown с udplen и tamper.
udplen увеличивает размер udp пакета на указанное в --dpi-desync-udplen-increment количество байтов.
Паддинг заполняется нулями. Предназначено для обмана DPI, ориентирующегося на размеры пакетов.
Паддинг заполняется нулями по умолчанию, но можно задать свой паттерн.
Предназначено для обмана DPI, ориентирующегося на размеры пакетов.
Может сработать, если пользовательсткий протокол не привязан жестко к размеру udp пейлоада.
Режим tamper означает модификацию пакетов известных протоколов особенным для протокола образом.
На текущий момент работает только с DHT.
Поддерживается определение пакетов QUIC Initial с расшифровкой содержимого и имени хоста, то есть параметр
--hostlist будет работать.
Определяется пакет wireguard handshake initiation.
Определяются пакеты wireguard handshake initiation и DHT (начинается с 'd1', кончается 'e').
Для десинхронизации других протоколов обязательно указывать --dpi-desync-any-protocol.
Реализован conntrack для udp. Можно пользоваться --dpi-desync-cutoff. Таймаут conntrack для udp
можно изменить 4-м параметром в --ctrack-timeouts.

View File

@ -75,7 +75,7 @@ bool desync_only_first_stage(enum dpi_desync_mode mode)
}
bool desync_valid_second_stage(enum dpi_desync_mode mode)
{
return mode==DESYNC_NONE || mode==DESYNC_DISORDER || mode==DESYNC_DISORDER2 || mode==DESYNC_SPLIT || mode==DESYNC_SPLIT2 || mode==DESYNC_IPFRAG2 || mode==DESYNC_UDPLEN;
return mode==DESYNC_NONE || mode==DESYNC_DISORDER || mode==DESYNC_DISORDER2 || mode==DESYNC_SPLIT || mode==DESYNC_SPLIT2 || mode==DESYNC_IPFRAG2 || mode==DESYNC_UDPLEN || mode==DESYNC_TAMPER;
}
bool desync_valid_second_stage_tcp(enum dpi_desync_mode mode)
{
@ -83,7 +83,7 @@ bool desync_valid_second_stage_tcp(enum dpi_desync_mode mode)
}
bool desync_valid_second_stage_udp(enum dpi_desync_mode mode)
{
return mode==DESYNC_NONE || mode==DESYNC_UDPLEN || mode==DESYNC_IPFRAG2;
return mode==DESYNC_NONE || mode==DESYNC_UDPLEN || mode==DESYNC_TAMPER || mode==DESYNC_IPFRAG2;
}
enum dpi_desync_mode desync_mode_from_string(const char *s)
{
@ -117,6 +117,8 @@ enum dpi_desync_mode desync_mode_from_string(const char *s)
return DESYNC_IPFRAG1;
else if (!strcmp(s,"udplen"))
return DESYNC_UDPLEN;
else if (!strcmp(s,"tamper"))
return DESYNC_TAMPER;
return DESYNC_INVALID;
}
@ -734,6 +736,13 @@ packet_process_result dpi_desync_udp_packet(uint32_t fwmark, const char *ifout,
fake_size = params.fake_wg_size;
bKnownProtocol = true;
}
else if (IsDhtD1(data_payload,len_payload))
{
DLOG("packet contains DHT d1...e\n")
fake = params.fake_dht;
fake_size = params.fake_dht_size;
bKnownProtocol = true;
}
else
{
if (!params.desync_any_proto) return res;
@ -846,6 +855,37 @@ packet_process_result dpi_desync_udp_packet(uint32_t fwmark, const char *ifout,
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len))
return res;
return drop;
case DESYNC_TAMPER:
if (IsDhtD1(data_payload,len_payload))
{
size_t szbuf,szcopy;
memcpy(pkt2,"d2:zz1:x",8);
pkt2_len=8;
szbuf=sizeof(pkt2)-pkt2_len;
szcopy=len_payload-1;
if (szcopy>szbuf)
{
DLOG("packet is too long to tamper");
return res;
}
memcpy(pkt2+pkt2_len,data_payload+1,szcopy);
pkt2_len+=szcopy;
pkt1_len = sizeof(pkt1);
if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, ttl_orig,fooling_orig, NULL, 0 , 0, pkt2, pkt2_len, pkt1, &pkt1_len))
{
DLOG("could not construct packet with modified length. too large ?\n");
return res;
}
DLOG("resending tampered DHT\n");
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len))
return res;
return drop;
}
else
{
DLOG("payload is not tamperable\n");
return res;
}
case DESYNC_IPFRAG2:
{

View File

@ -34,7 +34,8 @@ enum dpi_desync_mode {
DESYNC_HOPBYHOP,
DESYNC_DESTOPT,
DESYNC_IPFRAG1,
DESYNC_UDPLEN
DESYNC_UDPLEN,
DESYNC_TAMPER
};
extern const char *fake_http_request_default;

View File

@ -522,7 +522,7 @@ static void exithelp()
" --hostspell\t\t\t\t\t; exact spelling of \"Host\" header. must be 4 chars. default is \"host\"\n"
" --hostnospace\t\t\t\t\t; remove space after Host: and add it to User-Agent: to preserve packet size\n"
" --domcase\t\t\t\t\t; mix domain case : Host: TeSt.cOm\n"
" --dpi-desync=[<mode0>,]<mode>[,<mode2>]\t; try to desync dpi state. modes : synack fake fakeknown rst rstack hopbyhop destopt ipfrag1 disorder disorder2 split split2 ipfrag2 udplen\n"
" --dpi-desync=[<mode0>,]<mode>[,<mode2>]\t; try to desync dpi state. modes : synack fake fakeknown rst rstack hopbyhop destopt ipfrag1 disorder disorder2 split split2 ipfrag2 udplen tamper\n"
#ifdef __linux__
" --dpi-desync-fwmark=<int|0xHEX>\t\t; override fwmark for desync packet. default = 0x%08X (%u)\n"
#elif defined(SO_USER_COOKIE)
@ -547,6 +547,7 @@ static void exithelp()
" --dpi-desync-fake-unknown=<filename>|0xHEX\t; file containing unknown protocol fake payload\n"
" --dpi-desync-fake-quic=<filename>|0xHEX\t; file containing fake QUIC Initial\n"
" --dpi-desync-fake-wireguard=<filename>|0xHEX\t; file containing fake wireguard handshake initiation\n"
" --dpi-desync-fake-dht=<filename>|0xHEX\t\t; file containing DHT protocol fake payload (d1...e)\n"
" --dpi-desync-fake-unknown-udp=<filename>|0xHEX\t; file containing unknown udp protocol fake payload\n"
" --dpi-desync-udplen-increment=<int>\t\t; increase or decrease udp packet length by N bytes (default %u). negative values decrease length.\n"
" --dpi-desync-udplen-pattern=<filename>|0xHEX\t; udp tail fill pattern\n"
@ -660,6 +661,7 @@ int main(int argc, char **argv)
params.fake_quic_size = 620; // must be 601+ for TSPU hack
params.fake_quic[0] = 0x40; // russian TSPU QUIC short header fake
params.fake_wg_size = 64;
params.fake_dht_size = 64;
params.fake_unknown_size = 256;
params.fake_unknown_udp_size = 64;
params.wscale=-1; // default - dont change scale factor (client)
@ -728,15 +730,16 @@ int main(int argc, char **argv)
{"dpi-desync-fake-unknown",required_argument,0,0},// optidx=30
{"dpi-desync-fake-quic",required_argument,0,0},// optidx=31
{"dpi-desync-fake-wireguard",required_argument,0,0},// optidx=32
{"dpi-desync-fake-unknown-udp",required_argument,0,0},// optidx=33
{"dpi-desync-udplen-increment",required_argument,0,0},// optidx=34
{"dpi-desync-udplen-pattern",required_argument,0,0},// optidx=35
{"dpi-desync-cutoff",required_argument,0,0},// optidx=36
{"hostlist",required_argument,0,0}, // optidx=37
{"hostlist-exclude",required_argument,0,0}, // optidx=38
{"dpi-desync-fake-dht",required_argument,0,0},// optidx=33
{"dpi-desync-fake-unknown-udp",required_argument,0,0},// optidx=34
{"dpi-desync-udplen-increment",required_argument,0,0},// optidx=35
{"dpi-desync-udplen-pattern",required_argument,0,0},// optidx=36
{"dpi-desync-cutoff",required_argument,0,0},// optidx=37
{"hostlist",required_argument,0,0}, // optidx=38
{"hostlist-exclude",required_argument,0,0}, // optidx=39
#ifdef __linux__
{"bind-fix4",no_argument,0,0}, // optidx=39
{"bind-fix6",no_argument,0,0}, // optidx=40
{"bind-fix4",no_argument,0,0}, // optidx=40
{"bind-fix6",no_argument,0,0}, // optidx=41
#endif
{NULL,0,NULL,0}
};
@ -1022,18 +1025,22 @@ int main(int argc, char **argv)
params.fake_wg_size = sizeof(params.fake_wg);
load_file_or_exit(optarg,params.fake_wg,&params.fake_wg_size);
break;
case 33: /* dpi-desync-fake-unknown-udp */
case 33: /* dpi-desync-fake-dht */
params.fake_dht_size = sizeof(params.fake_dht);
load_file_or_exit(optarg,params.fake_dht,&params.fake_dht_size);
break;
case 34: /* dpi-desync-fake-unknown-udp */
params.fake_unknown_udp_size = sizeof(params.fake_unknown_udp);
load_file_or_exit(optarg,params.fake_unknown_udp,&params.fake_unknown_udp_size);
break;
case 34: /* dpi-desync-udplen-increment */
case 35: /* dpi-desync-udplen-increment */
if (sscanf(optarg,"%d",&params.udplen_increment)<1 || params.udplen_increment>0x7FFF || params.udplen_increment<-0x8000)
{
fprintf(stderr, "dpi-desync-udplen-increment must be integer within -32768..32767 range\n");
exit_clean(1);
}
break;
case 35: /* dpi-desync-udplen-pattern */
case 36: /* dpi-desync-udplen-pattern */
{
char buf[sizeof(params.udplen_pattern)];
size_t sz=sizeof(buf);
@ -1041,21 +1048,21 @@ int main(int argc, char **argv)
fill_pattern(params.udplen_pattern,sizeof(params.udplen_pattern),buf,sz);
}
break;
case 36: /* desync-cutoff */
case 37: /* desync-cutoff */
if (!parse_cutoff(optarg, &params.desync_cutoff, &params.desync_cutoff_mode))
{
fprintf(stderr, "invalid desync-cutoff value\n");
exit_clean(1);
}
break;
case 37: /* hostlist */
case 38: /* hostlist */
if (!strlist_add(&params.hostlist_files, optarg))
{
fprintf(stderr, "strlist_add failed\n");
exit_clean(1);
}
break;
case 38: /* hostlist-exclude */
case 39: /* hostlist-exclude */
if (!strlist_add(&params.hostlist_exclude_files, optarg))
{
fprintf(stderr, "strlist_add failed\n");
@ -1063,10 +1070,10 @@ int main(int argc, char **argv)
}
break;
#ifdef __linux__
case 39: /* bind-fix4 */
case 40: /* bind-fix4 */
params.bind_fix4 = true;
break;
case 40: /* bind-fix6 */
case 41: /* bind-fix6 */
params.bind_fix6 = true;
break;
#endif

View File

@ -50,8 +50,8 @@ struct params_s
uint8_t desync_fooling_mode;
uint32_t desync_fwmark; // unused in BSD
uint32_t desync_badseq_increment, desync_badseq_ack_increment;
uint8_t fake_http[1432],fake_tls[1432],fake_quic[1472],fake_wg[1472],fake_unknown[1432],fake_unknown_udp[1472], udplen_pattern[1472];
size_t fake_http_size,fake_tls_size,fake_quic_size,fake_wg_size,fake_unknown_size,fake_unknown_udp_size;
uint8_t fake_http[1432],fake_tls[1432],fake_quic[1472],fake_wg[1472],fake_dht[1472],fake_unknown[1432],fake_unknown_udp[1472], udplen_pattern[1472];
size_t fake_http_size,fake_tls_size,fake_quic_size,fake_wg_size,fake_dht_size,fake_unknown_size,fake_unknown_udp_size;
int udplen_increment;
bool droproot;
uid_t uid;

View File

@ -192,7 +192,10 @@ bool IsWireguardHandshakeInitiation(const uint8_t *data, size_t len)
{
return len==148 && data[0]==1 && data[1]==0 && data[2]==0 && data[3]==0;
}
bool IsDhtD1(const uint8_t *data, size_t len)
{
return len>=3 && data[0]=='d' && data[1]=='1' && data[len-1]=='e';
}
/* Returns the QUIC draft version or 0 if not applicable. */
uint8_t QUICDraftVersion(uint32_t version)

View File

@ -16,6 +16,7 @@ bool TLSHelloExtractHost(const uint8_t *data, size_t len, char *host, size_t len
bool TLSHelloExtractHostFromHandshake(const uint8_t *data, size_t len, char *host, size_t len_host);
bool IsWireguardHandshakeInitiation(const uint8_t *data, size_t len);
bool IsDhtD1(const uint8_t *data, size_t len);
#define QUIC_MAX_CID_LENGTH 20
typedef struct quic_cid {