Browse Source

nfqws: fakeknown, udplen desync modes

pull/101/head
bol-van 3 years ago
parent
commit
ffda684a43
  1. BIN
      binaries/aarch64/nfqws
  2. BIN
      binaries/arm/nfqws
  3. BIN
      binaries/freebsd-x64/dvtws
  4. BIN
      binaries/mips32r1-lsb/nfqws
  5. BIN
      binaries/mips32r1-msb/nfqws
  6. BIN
      binaries/mips64r2-msb/nfqws
  7. BIN
      binaries/ppc/nfqws
  8. BIN
      binaries/x86/nfqws
  9. BIN
      binaries/x86_64/nfqws
  10. 20
      nfq/darkmagic.c
  11. 3
      nfq/darkmagic.h
  12. 59
      nfq/desync.c
  13. 6
      nfq/desync.h
  14. 19
      nfq/nfqws.c
  15. 3
      nfq/params.h

BIN
binaries/aarch64/nfqws

Binary file not shown.

BIN
binaries/arm/nfqws

Binary file not shown.

BIN
binaries/freebsd-x64/dvtws

Binary file not shown.

BIN
binaries/mips32r1-lsb/nfqws

Binary file not shown.

BIN
binaries/mips32r1-msb/nfqws

Binary file not shown.

BIN
binaries/mips64r2-msb/nfqws

Binary file not shown.

BIN
binaries/ppc/nfqws

Binary file not shown.

BIN
binaries/x86/nfqws

Binary file not shown.

BIN
binaries/x86_64/nfqws

Binary file not shown.

20
nfq/darkmagic.c

@ -298,10 +298,12 @@ bool prepare_udp_segment4(
const struct sockaddr_in *src, const struct sockaddr_in *dst,
uint8_t ttl,
uint8_t fooling,
uint16_t padlen,
const void *data, uint16_t len,
uint8_t *buf, size_t *buflen)
{
uint16_t ip_payload_len = sizeof(struct udphdr) + len;
uint16_t datalen = len + padlen;
uint16_t ip_payload_len = sizeof(struct udphdr) + datalen;
uint16_t pktlen = sizeof(struct ip) + ip_payload_len;
if (pktlen>*buflen) return false;
@ -309,10 +311,12 @@ bool prepare_udp_segment4(
struct udphdr *udp = (struct udphdr*)(ip+1);
uint8_t *payload = (uint8_t*)(udp+1);
fill_iphdr(ip, &src->sin_addr, &dst->sin_addr, pktlen, IPPROTO_UDP, ttl);
fill_udphdr(udp, src->sin_port, dst->sin_port, len);
fill_udphdr(udp, src->sin_port, dst->sin_port, datalen);
memcpy(payload,data,len);
memset(payload+len,0,padlen);
udp4_fix_checksum(udp,ip_payload_len,&ip->ip_src,&ip->ip_dst);
if (fooling & FOOL_BADSUM) udp->uh_sum^=htons(0xBEAF);
@ -323,10 +327,12 @@ bool prepare_udp_segment6(
const struct sockaddr_in6 *src, const struct sockaddr_in6 *dst,
uint8_t ttl,
uint8_t fooling,
uint16_t padlen,
const void *data, uint16_t len,
uint8_t *buf, size_t *buflen)
{
uint16_t transport_payload_len = sizeof(struct udphdr) + len;
uint16_t datalen = len + padlen;
uint16_t transport_payload_len = sizeof(struct udphdr) + datalen;
uint16_t ip_payload_len = transport_payload_len +
8*!!((fooling & (FOOL_HOPBYHOP|FOOL_HOPBYHOP2))==FOOL_HOPBYHOP) +
16*!!(fooling & FOOL_HOPBYHOP2) +
@ -384,9 +390,10 @@ bool prepare_udp_segment6(
uint8_t *payload = (uint8_t*)(udp+1);
fill_ip6hdr(ip6, &src->sin6_addr, &dst->sin6_addr, ip_payload_len, proto, ttl);
fill_udphdr(udp, src->sin6_port, dst->sin6_port, len);
fill_udphdr(udp, src->sin6_port, dst->sin6_port, datalen);
memcpy(payload,data,len);
memset(payload+len,0,padlen);
udp6_fix_checksum(udp,transport_payload_len,&ip6->ip6_src,&ip6->ip6_dst);
if (fooling & FOOL_BADSUM) udp->uh_sum^=htons(0xBEAF);
@ -397,13 +404,14 @@ bool prepare_udp_segment(
const struct sockaddr *src, const struct sockaddr *dst,
uint8_t ttl,
uint8_t fooling,
uint16_t padlen,
const void *data, uint16_t len,
uint8_t *buf, size_t *buflen)
{
return (src->sa_family==AF_INET && dst->sa_family==AF_INET) ?
prepare_udp_segment4((struct sockaddr_in *)src,(struct sockaddr_in *)dst,ttl,fooling,data,len,buf,buflen) :
prepare_udp_segment4((struct sockaddr_in *)src,(struct sockaddr_in *)dst,ttl,fooling,padlen,data,len,buf,buflen) :
(src->sa_family==AF_INET6 && dst->sa_family==AF_INET6) ?
prepare_udp_segment6((struct sockaddr_in6 *)src,(struct sockaddr_in6 *)dst,ttl,fooling,data,len,buf,buflen) :
prepare_udp_segment6((struct sockaddr_in6 *)src,(struct sockaddr_in6 *)dst,ttl,fooling,padlen,data,len,buf,buflen) :
false;
}

3
nfq/darkmagic.h

@ -73,18 +73,21 @@ bool prepare_udp_segment4(
const struct sockaddr_in *src, const struct sockaddr_in *dst,
uint8_t ttl,
uint8_t fooling,
uint16_t padlen,
const void *data, uint16_t len,
uint8_t *buf, size_t *buflen);
bool prepare_udp_segment6(
const struct sockaddr_in6 *src, const struct sockaddr_in6 *dst,
uint8_t ttl,
uint8_t fooling,
uint16_t padlen,
const void *data, uint16_t len,
uint8_t *buf, size_t *buflen);
bool prepare_udp_segment(
const struct sockaddr *src, const struct sockaddr *dst,
uint8_t ttl,
uint8_t fooling,
uint16_t padlen,
const void *data, uint16_t len,
uint8_t *buf, size_t *buflen);

59
nfq/desync.c

@ -67,22 +67,32 @@ bool desync_valid_zero_stage(enum dpi_desync_mode mode)
}
bool desync_valid_first_stage(enum dpi_desync_mode mode)
{
return mode==DESYNC_FAKE || mode==DESYNC_RST || mode==DESYNC_RSTACK || mode==DESYNC_HOPBYHOP || mode==DESYNC_DESTOPT || mode==DESYNC_IPFRAG1;
return mode==DESYNC_FAKE || mode==DESYNC_FAKE_KNOWN || mode==DESYNC_RST || mode==DESYNC_RSTACK || mode==DESYNC_HOPBYHOP || mode==DESYNC_DESTOPT || mode==DESYNC_IPFRAG1;
}
bool desync_only_first_stage(enum dpi_desync_mode mode)
{
return false;
}
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;
}
bool desync_valid_second_stage_tcp(enum dpi_desync_mode mode)
{
return mode==DESYNC_NONE || mode==DESYNC_DISORDER || mode==DESYNC_DISORDER2 || mode==DESYNC_SPLIT || mode==DESYNC_SPLIT2 || mode==DESYNC_IPFRAG2;
}
bool desync_valid_second_stage_udp(enum dpi_desync_mode mode)
{
return mode==DESYNC_NONE || mode==DESYNC_UDPLEN || mode==DESYNC_IPFRAG2;
}
enum dpi_desync_mode desync_mode_from_string(const char *s)
{
if (!s)
return DESYNC_NONE;
else if (!strcmp(s,"fake"))
return DESYNC_FAKE;
else if (!strcmp(s,"fakeknown"))
return DESYNC_FAKE_KNOWN;
else if (!strcmp(s,"rst"))
return DESYNC_RST;
else if (!strcmp(s,"rstack"))
@ -105,6 +115,8 @@ enum dpi_desync_mode desync_mode_from_string(const char *s)
return DESYNC_DESTOPT;
else if (!strcmp(s,"ipfrag1"))
return DESYNC_IPFRAG1;
else if (!strcmp(s,"udplen"))
return DESYNC_UDPLEN;
return DESYNC_INVALID;
}
@ -262,6 +274,7 @@ packet_process_result dpi_desync_tcp_packet(uint8_t *data_pkt, size_t len_pkt, s
char host[256];
bool bHaveHost=false;
bool bIsHttp;
bool bKnownProtocol = false;
uint8_t *p, *phost;
if ((bIsHttp = IsHttp(data_payload,len_payload)))
@ -277,6 +290,7 @@ packet_process_result dpi_desync_tcp_packet(uint8_t *data_pkt, size_t len_pkt, s
DLOG("not applying tampering to HTTP without Host:\n")
return res;
}
bKnownProtocol = true;
}
else if (IsTLSClientHello(data_payload,len_payload))
{
@ -294,6 +308,7 @@ packet_process_result dpi_desync_tcp_packet(uint8_t *data_pkt, size_t len_pkt, s
return res;
}
}
bKnownProtocol = true;
}
else
{
@ -367,6 +382,13 @@ packet_process_result dpi_desync_tcp_packet(uint8_t *data_pkt, size_t len_pkt, s
b = false;
switch(desync_mode)
{
case DESYNC_FAKE_KNOWN:
if (!bKnownProtocol)
{
DLOG("not applying fake because of unknown protocol\n");
desync_mode = params.desync_mode2;
break;
}
case DESYNC_FAKE:
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, tcphdr->th_seq, tcphdr->th_ack, tcphdr->th_win, scale_factor, timestamps,
ttl_fake,params.desync_fooling_mode,params.desync_badseq_increment,params.desync_badseq_ack_increment,
@ -393,7 +415,7 @@ packet_process_result dpi_desync_tcp_packet(uint8_t *data_pkt, size_t len_pkt, s
case DESYNC_DESTOPT:
case DESYNC_IPFRAG1:
fooling_orig = (desync_mode==DESYNC_HOPBYHOP) ? FOOL_HOPBYHOP : (desync_mode==DESYNC_DESTOPT) ? FOOL_DESTOPT : FOOL_IPFRAG1;
if (ip6hdr && params.desync_mode2==DESYNC_NONE)
if (ip6hdr && (params.desync_mode2==DESYNC_NONE || !desync_valid_second_stage_tcp(params.desync_mode2)))
{
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, tcphdr->th_seq, tcphdr->th_ack, tcphdr->th_win, scale_factor, timestamps,
ttl_orig,fooling_orig,0,0,
@ -414,7 +436,7 @@ packet_process_result dpi_desync_tcp_packet(uint8_t *data_pkt, size_t len_pkt, s
{
if (!rawsend_rep((struct sockaddr *)&dst, params.desync_fwmark, pkt1, pkt1_len))
return res;
if (params.desync_mode2==DESYNC_NONE)
if (params.desync_mode2==DESYNC_NONE || !desync_valid_second_stage_tcp(params.desync_mode2))
{
if (params.desync_retrans)
{
@ -657,6 +679,7 @@ packet_process_result dpi_desync_udp_packet(uint8_t *data_pkt, size_t len_pkt, s
bool b;
char host[256];
bool bHaveHost=false;
bool bKnownProtocol=false;
if (IsQUICInitial(data_payload,len_payload))
{
@ -700,6 +723,7 @@ packet_process_result dpi_desync_udp_packet(uint8_t *data_pkt, size_t len_pkt, s
return res;
}
}
bKnownProtocol = true;
}
else
{
@ -738,24 +762,32 @@ packet_process_result dpi_desync_udp_packet(uint8_t *data_pkt, size_t len_pkt, s
pkt1_len = sizeof(pkt1);
b = false;
switch(desync_mode)
{
case DESYNC_FAKE_KNOWN:
if (!bKnownProtocol)
{
DLOG("not applying fake because of unknown protocol\n");
desync_mode = params.desync_mode2;
break;
}
case DESYNC_FAKE:
if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, ttl_fake, params.desync_fooling_mode, fake, fake_size, pkt1, &pkt1_len))
if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, ttl_fake, params.desync_fooling_mode, 0, fake, fake_size, pkt1, &pkt1_len))
return res;
DLOG("sending fake request : ");
hexdump_limited_dlog(fake,fake_size,PKTDATA_MAXDUMP); DLOG("\n")
if (!rawsend_rep((struct sockaddr *)&dst, params.desync_fwmark, pkt1, pkt1_len))
return res;
b = true;
break;
case DESYNC_HOPBYHOP:
case DESYNC_DESTOPT:
case DESYNC_IPFRAG1:
fooling_orig = (desync_mode==DESYNC_HOPBYHOP) ? FOOL_HOPBYHOP : (desync_mode==DESYNC_DESTOPT) ? FOOL_DESTOPT : FOOL_IPFRAG1;
if (ip6hdr && params.desync_mode2==DESYNC_NONE)
if (ip6hdr && (params.desync_mode2==DESYNC_NONE || !desync_valid_second_stage_udp(params.desync_mode2)))
{
if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst,
ttl_orig,fooling_orig,
ttl_orig,fooling_orig,0,
data_payload, len_payload, pkt1, &pkt1_len))
{
return res;
@ -767,14 +799,13 @@ packet_process_result dpi_desync_udp_packet(uint8_t *data_pkt, size_t len_pkt, s
return drop;
}
desync_mode = params.desync_mode2;
break;
}
if (b)
{
if (params.desync_mode2==DESYNC_NONE)
if (params.desync_mode2==DESYNC_NONE || !desync_valid_second_stage_udp(params.desync_mode2))
{
if (!rawsend_rep((struct sockaddr *)&dst, params.desync_fwmark, pkt1, pkt1_len))
return res;
DLOG("reinjecting original packet. len=%zu len_payload=%zu\n", len_pkt, len_payload)
#ifdef __FreeBSD__
// FreeBSD tend to pass ipv6 frames with wrong checksum
@ -793,6 +824,14 @@ packet_process_result dpi_desync_udp_packet(uint8_t *data_pkt, size_t len_pkt, s
switch(desync_mode)
{
case DESYNC_UDPLEN:
pkt1_len = sizeof(pkt1);
if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, ttl_orig,fooling_orig, params.udplen_increment, data_payload, len_payload, pkt1, &pkt1_len))
return res;
DLOG("resending original packet with increased by %u length\n", params.udplen_increment);
if (!rawsend((struct sockaddr *)&dst, params.desync_fwmark, pkt1, pkt1_len))
return res;
return drop;
case DESYNC_IPFRAG2:
{

6
nfq/desync.h

@ -22,6 +22,7 @@ enum dpi_desync_mode {
DESYNC_NONE=0,
DESYNC_INVALID,
DESYNC_FAKE,
DESYNC_FAKE_KNOWN,
DESYNC_RST,
DESYNC_RSTACK,
DESYNC_SYNACK,
@ -32,7 +33,8 @@ enum dpi_desync_mode {
DESYNC_IPFRAG2,
DESYNC_HOPBYHOP,
DESYNC_DESTOPT,
DESYNC_IPFRAG1
DESYNC_IPFRAG1,
DESYNC_UDPLEN
};
extern const char *fake_http_request_default;
@ -43,6 +45,8 @@ bool desync_valid_zero_stage(enum dpi_desync_mode mode);
bool desync_valid_first_stage(enum dpi_desync_mode mode);
bool desync_only_first_stage(enum dpi_desync_mode mode);
bool desync_valid_second_stage(enum dpi_desync_mode mode);
bool desync_valid_second_stage_tcp(enum dpi_desync_mode mode);
bool desync_valid_second_stage_udp(enum dpi_desync_mode mode);
void desync_init();
packet_process_result dpi_desync_tcp_packet(uint8_t *data_pkt, size_t len_pkt, struct ip *ip, struct ip6_hdr *ip6hdr, struct tcphdr *tcphdr, size_t len_tcp, uint8_t *data_payload, size_t len_payload);

19
nfq/nfqws.c

@ -505,7 +505,7 @@ static void exithelp()
" --hostspell\t\t\t\t; exact spelling of \"Host\" header. must be 4 chars. default is \"host\"\n"
" --hostnospace\t\t\t\t; remove space after Host: and add it to User-Agent: to preserve packet size\n"
" --domcase\t\t\t\t; mix domain case : Host: TeSt.cOm\n"
" --dpi-desync=[<mode0>,]<mode>[,<mode2>] ; try to desync dpi state. modes : synack fake rst rstack hopbyhop destopt ipfrag1 disorder disorder2 split split2 ipfrag2\n"
" --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\n"
#ifdef __linux__
" --dpi-desync-fwmark=<int|0xHEX>\t; override fwmark for desync packet. default = 0x%08X (%u)\n"
#elif defined(SO_USER_COOKIE)
@ -530,6 +530,7 @@ static void exithelp()
" --dpi-desync-fake-unknown=<filename>\t; file containing unknown protocol fake payload\n"
" --dpi-desync-fake-quic=<filename>\t; file containing fake QUIC Initial\n"
" --dpi-desync-fake-unknown-udp=<filename> ; file containing unknown udp protocol fake payload\n"
" --dpi-desync-udplen-increment=<int>\t; increase udp packet length by N bytes (default %u)\n"
" --dpi-desync-cutoff=[n|d|s]N\t\t; apply dpi desync only to packet numbers (n, default), data packet numbers (d), relative sequence (s) less than N\n"
" --hostlist=<filename>\t\t\t; apply dpi desync only to the listed hosts (one host per line, subdomains auto apply)\n",
CTRACK_T_SYN, CTRACK_T_EST, CTRACK_T_FIN, CTRACK_T_UDP,
@ -539,7 +540,8 @@ static void exithelp()
DPI_DESYNC_MAX_FAKE_LEN,
DPI_DESYNC_MAX_FAKE_LEN, IPFRAG_UDP_DEFAULT,
DPI_DESYNC_MAX_FAKE_LEN, IPFRAG_TCP_DEFAULT,
BADSEQ_INCREMENT_DEFAULT, BADSEQ_ACK_INCREMENT_DEFAULT
BADSEQ_INCREMENT_DEFAULT, BADSEQ_ACK_INCREMENT_DEFAULT,
UDPLEN_INCREMENT_DEFAULT
);
exit(1);
}
@ -627,6 +629,7 @@ int main(int argc, char **argv)
params.desync_badseq_increment = BADSEQ_INCREMENT_DEFAULT;
params.desync_badseq_ack_increment = BADSEQ_ACK_INCREMENT_DEFAULT;
params.wssize_cutoff_mode = params.desync_cutoff_mode = 'n'; // packet number by default
params.udplen_increment = UDPLEN_INCREMENT_DEFAULT;
if (can_drop_root()) // are we root ?
{
@ -680,8 +683,9 @@ 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-unknown-udp",required_argument,0,0},// optidx=32
{"dpi-desync-cutoff",required_argument,0,0},// optidx=33
{"hostlist",required_argument,0,0}, // optidx=34
{"dpi-desync-udplen-increment",required_argument,0,0},// optidx=33
{"dpi-desync-cutoff",required_argument,0,0},// optidx=34
{"hostlist",required_argument,0,0}, // optidx=35
{NULL,0,NULL,0}
};
if (argc < 2) exithelp();
@ -966,14 +970,17 @@ int main(int argc, char **argv)
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 33: /* desync-cutoff */
case 33: /* dpi-desync-udplen-increment */
params.udplen_increment = (uint16_t)atoi(optarg);
break;
case 34: /* 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 34: /* hostlist */
case 35: /* hostlist */
if (!LoadHostList(&params.hostlist, optarg))
exit_clean(1);
strncpy(params.hostfile,optarg,sizeof(params.hostfile));

3
nfq/params.h

@ -23,6 +23,8 @@
#define IPFRAG_UDP_DEFAULT 8
#define IPFRAG_TCP_DEFAULT 32
#define UDPLEN_INCREMENT_DEFAULT 2
struct params_s
{
bool debug;
@ -50,6 +52,7 @@ struct params_s
strpool *hostlist;
uint8_t fake_http[1432],fake_tls[1432],fake_unknown[1432],fake_unknown_udp[1472],fake_quic[1472];
size_t fake_http_size,fake_tls_size,fake_unknown_size,fake_unknown_udp_size,fake_quic_size;
uint16_t udplen_increment;
bool droproot;
uid_t uid;
gid_t gid;

Loading…
Cancel
Save