diff --git a/docs/changes.txt b/docs/changes.txt index d03d8d85..9bb2902d 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -545,3 +545,4 @@ readme: hardware problems description v71.5 winws: --wf-raw-part +nfqws: --dpi-desync=hostfakesplit diff --git a/nfq/desync.c b/nfq/desync.c index a8277532..16e78af4 100644 --- a/nfq/desync.c +++ b/nfq/desync.c @@ -170,18 +170,20 @@ 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_FAKEDDISORDER || mode==DESYNC_FAKEDSPLIT || mode==DESYNC_MULTISPLIT || mode==DESYNC_MULTIDISORDER || mode==DESYNC_IPFRAG2 || mode==DESYNC_UDPLEN || mode==DESYNC_TAMPER; -} bool desync_valid_second_stage_tcp(enum dpi_desync_mode mode) { - return mode==DESYNC_NONE || mode==DESYNC_FAKEDDISORDER || mode==DESYNC_FAKEDSPLIT || mode==DESYNC_MULTISPLIT || mode==DESYNC_MULTIDISORDER || mode==DESYNC_IPFRAG2; + return + mode==DESYNC_NONE || mode==DESYNC_FAKEDDISORDER || mode==DESYNC_FAKEDSPLIT || mode==DESYNC_MULTISPLIT || mode==DESYNC_MULTIDISORDER || mode==DESYNC_HOSTFAKESPLIT || + mode==DESYNC_IPFRAG2; } bool desync_valid_second_stage_udp(enum dpi_desync_mode mode) { return mode==DESYNC_NONE || mode==DESYNC_UDPLEN || mode==DESYNC_TAMPER || mode==DESYNC_IPFRAG2; } +bool desync_valid_second_stage(enum dpi_desync_mode mode) +{ + return desync_valid_second_stage_tcp(mode) || desync_valid_second_stage_udp(mode); +} enum dpi_desync_mode desync_mode_from_string(const char *s) { if (!s) @@ -206,6 +208,8 @@ enum dpi_desync_mode desync_mode_from_string(const char *s) return DESYNC_MULTISPLIT; else if (!strcmp(s,"multidisorder") || !strcmp(s,"disorder2")) return DESYNC_MULTIDISORDER; + else if (!strcmp(s,"hostfakesplit")) + return DESYNC_HOSTFAKESPLIT; else if (!strcmp(s,"ipfrag2")) return DESYNC_IPFRAG2; else if (!strcmp(s,"hopbyhop")) @@ -1813,6 +1817,51 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint else DLOG("regular split pos is outside of this packet\n"); } + else if (dp->desync_mode==DESYNC_HOSTFAKESPLIT || dp->desync_mode2==DESYNC_HOSTFAKESPLIT) + { + struct proto_pos splits[2] = { + { marker: PM_HOST, pos: 0}, + { marker: PM_HOST_END, pos: 0} + }; + split_pos=0; + ResolveMultiPos(rdata_payload, rlen_payload, l7proto, splits, 2, multisplit_pos, &multisplit_count); + if (multisplit_count!=2) + { + DLOG("hostfakesplit: host and endhost positions not found\n"); + multisplit_count=0; + } + else + { + int j; + for (i=j=0;ilen_payload); + if (multisplit_pos[j]) j++; + } + multisplit_count=j; + if (multisplit_count!=2) + { + DLOG("hostfakesplit: host or endhost are outside of this packet\n"); + multisplit_count=0; + } + else + { + DLOG("normalized hostfakesplit pos: "); + for (i=0;ihostfakesplit_midhost); + if (multisplit_pos[2]) + { + multisplit_pos[2]=pos_normalize(multisplit_pos[2],reasm_offset,dis->len_payload); + if (multisplit_pos[2]>multisplit_pos[0] && multisplit_pos[2]desync_mode==DESYNC_HOPBYHOP) ? FOOL_HOPBYHOP : (dp->desync_mode==DESYNC_DESTOPT) ? FOOL_DESTOPT : FOOL_IPFRAG1; if (dis->ip6 && (dp->desync_mode2==DESYNC_NONE || !desync_valid_second_stage_tcp(dp->desync_mode2) || (!split_pos && (dp->desync_mode2==DESYNC_FAKEDSPLIT || dp->desync_mode2==DESYNC_FAKEDDISORDER)) || + (multisplit_count<2 && dp->desync_mode2==DESYNC_HOSTFAKESPLIT) || (!multisplit_count && (dp->desync_mode2==DESYNC_MULTISPLIT || dp->desync_mode2==DESYNC_MULTIDISORDER)))) { reasm_orig_cancel(ctrack); @@ -1947,6 +1997,114 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint enum dpi_desync_mode desync_mode = dp->desync_mode2==DESYNC_NONE ? dp->desync_mode : dp->desync_mode2; switch(desync_mode) { + case DESYNC_HOSTFAKESPLIT: + // can be 2 or 3 split pos + // if 2 split pos : host, endhost + // if 3 split pos : host, endhost, midhost + if (multisplit_count>=2) + { + uint8_t *seg; + size_t seg_len, host_size, pos_host, pos_endhost, pos_split_host, sz; + char *fakehost; + + seg = dis->data_payload; + seg_len = dis->len_payload; + pos_host = multisplit_pos[0]; + pos_endhost = multisplit_pos[1]; + pos_split_host = multisplit_count>=3 ? multisplit_pos[2] : 0; + host_size = pos_endhost-pos_host; + + ip_id = IP4_IP_ID_FIX(dis->ip); + + pkt1_len = sizeof(pkt1); + if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0, + dis->tcp->th_seq, dis->tcp->th_ack, + dis->tcp->th_win, scale_factor, timestamps, + DF,ttl_orig,IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6), + fooling_orig,0,0,0, + seg, pos_host, pkt1, &pkt1_len)) + goto send_orig; + ip_id=IP4_IP_ID_NEXT(ip_id); + DLOG("sending hostfakesplit before_host part 0-%zu len=%zu : ",pos_host-1,pos_host); + hexdump_limited_dlog(seg,pos_host,PKTDATA_MAXDUMP); DLOG("\n"); + if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) + goto send_orig; + + if (!(fakehost=malloc(host_size+1))) + { + DLOG("fakehost out of memory\n"); + goto send_orig; + } + fill_random_az09(fakehost,host_size); + if (host_size>=7) fakehost[host_size-4] = '.'; + DLOG("generated fake host: %s\n",fakehost); + + pkt1_len = sizeof(pkt1); + if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0, + net32_add(dis->tcp->th_seq,pos_host), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, + DF,ttl_fake,IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6), + dp->desync_fooling_mode,dp->desync_ts_increment,dp->desync_badseq_increment,dp->desync_badseq_ack_increment, + fakehost, host_size, pkt1, &pkt1_len)) + { + free(fakehost); + goto send_orig; + } + ip_id=IP4_IP_ID_NEXT(ip_id); + DLOG("sending hostfakesplit fake host %zu-%zu len=%zu : ",pos_host,pos_endhost-1,host_size); + hexdump_limited_dlog(fakehost,host_size,PKTDATA_MAXDUMP); DLOG("\n"); + free(fakehost); + if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) + goto send_orig; + + sz = pos_split_host ? pos_split_host-pos_host : host_size; + pkt1_len = sizeof(pkt1); + if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0, + net32_add(dis->tcp->th_seq,pos_host), dis->tcp->th_ack, + dis->tcp->th_win, scale_factor, timestamps, + DF,ttl_orig,IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6), + fooling_orig,0,0,0, + seg+pos_host, sz, pkt1, &pkt1_len)) + goto send_orig; + ip_id=IP4_IP_ID_NEXT(ip_id); + DLOG("sending hostfakesplit real host %s%zu-%zu len=%zu : ",pos_split_host ? "part 1 " : "",pos_host,pos_host+sz-1,sz); + hexdump_limited_dlog(seg+pos_host,sz,PKTDATA_MAXDUMP); DLOG("\n"); + if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) + goto send_orig; + + if (pos_split_host) + { + sz = pos_endhost - pos_split_host; + pkt1_len = sizeof(pkt1); + if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0, + net32_add(dis->tcp->th_seq,pos_split_host), dis->tcp->th_ack, + dis->tcp->th_win, scale_factor, timestamps, + DF,ttl_orig,IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6), + fooling_orig,0,0,0, + seg+pos_split_host, sz, pkt1, &pkt1_len)) + goto send_orig; + ip_id=IP4_IP_ID_NEXT(ip_id); + DLOG("sending hostfakesplit real host part 2 %zu-%zu len=%zu : ",pos_split_host,pos_endhost-1,sz); + hexdump_limited_dlog(seg+pos_split_host,sz,PKTDATA_MAXDUMP); DLOG("\n"); + if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) + goto send_orig; + } + + pkt1_len = sizeof(pkt1); + if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0, + net32_add(dis->tcp->th_seq,pos_endhost), dis->tcp->th_ack, + dis->tcp->th_win, scale_factor, timestamps, + DF,ttl_orig,IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6), + fooling_orig,0,0,0, + seg+pos_endhost, seg_len-pos_endhost, pkt1, &pkt1_len)) + goto send_orig; + DLOG("sending hostfakesplit after_host part %zu-%zu len=%zu : ",pos_endhost,seg_len-1,seg_len-pos_endhost); + hexdump_limited_dlog(seg+pos_endhost,seg_len-pos_endhost,PKTDATA_MAXDUMP); DLOG("\n"); + if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) + goto send_orig; + + return VERDICT_DROP; + } + break; case DESYNC_MULTISPLIT: if (multisplit_count) { diff --git a/nfq/desync.h b/nfq/desync.h index 82f8f780..4eb73613 100644 --- a/nfq/desync.h +++ b/nfq/desync.h @@ -32,6 +32,7 @@ enum dpi_desync_mode { DESYNC_FAKEDDISORDER, DESYNC_MULTISPLIT, DESYNC_MULTIDISORDER, + DESYNC_HOSTFAKESPLIT, DESYNC_IPFRAG2, DESYNC_HOPBYHOP, DESYNC_DESTOPT, diff --git a/nfq/nfqws.c b/nfq/nfqws.c index ab509dcf..ac3d558d 100644 --- a/nfq/nfqws.c +++ b/nfq/nfqws.c @@ -1165,6 +1165,7 @@ static void SplitDebug(void) for(int x=0;xsplit_count;x++) DLOG("profile %d multisplit %s %d\n",dp->n,posmarker_name(dp->splits[x].marker),dp->splits[x].pos); if (!PROTO_POS_EMPTY(&dp->seqovl)) DLOG("profile %d seqovl %s %d\n",dp->n,posmarker_name(dp->seqovl.marker),dp->seqovl.pos); + if (!PROTO_POS_EMPTY(&dp->hostfakesplit_midhost)) DLOG("profile %d hostfakesplit midhost %s %d\n",dp->n,posmarker_name(dp->hostfakesplit_midhost.marker),dp->hostfakesplit_midhost.pos); } } @@ -1620,7 +1621,7 @@ static void exithelp(void) " --methodeol\t\t\t\t\t; add '\\n' before method and remove space from Host:\n" " --dpi-desync=[,][,]\t; try to desync dpi state. modes :\n" "\t\t\t\t\t\t; synack syndata fake fakeknown rst rstack hopbyhop destopt ipfrag1\n" - "\t\t\t\t\t\t; multisplit multidisorder fakedsplit fakeddisorder ipfrag2 udplen tamper\n" + "\t\t\t\t\t\t; multisplit multidisorder fakedsplit fakeddisorder hostfakesplit ipfrag2 udplen tamper\n" #ifdef __linux__ " --dpi-desync-fwmark=\t\t; override fwmark for desync packet. default = 0x%08X (%u)\n" #elif defined(SO_USER_COOKIE) @@ -1640,6 +1641,7 @@ static void exithelp(void) " --dpi-desync-split-seqovl=N|-N|marker+N|marker-N ; use sequence overlap before first sent original split segment\n" " --dpi-desync-split-seqovl-pattern=|0xHEX ; pattern for the fake part of overlap\n" " --dpi-desync-fakedsplit-pattern=|0xHEX ; fake pattern for fakedsplit/fakeddisorder\n" + " --dpi-desync-hostfakesplit-midhost=marker+N|marker-N ; additionally split real hostname at specified marker. must be within host..endhost or won't be splitted.\n" " --dpi-desync-ipfrag-pos-tcp=<8..%u>\t\t; ip frag position starting from the transport header. multiple of 8, default %u.\n" " --dpi-desync-ipfrag-pos-udp=<8..%u>\t\t; ip frag position starting from the transport header. multiple of 8, default %u.\n" " --dpi-desync-ts-increment=\t\t; ts fooling TSval signed increment. default %d\n" @@ -1716,7 +1718,8 @@ void check_dp(const struct desync_profile *dp) // only linux has connbytes limiter if ((dp->desync_any_proto && !dp->desync_cutoff && (dp->desync_mode==DESYNC_FAKE || dp->desync_mode==DESYNC_RST || dp->desync_mode==DESYNC_RSTACK || - dp->desync_mode==DESYNC_FAKEDSPLIT || dp->desync_mode==DESYNC_FAKEDDISORDER || dp->desync_mode2==DESYNC_FAKEDSPLIT || dp->desync_mode2==DESYNC_FAKEDDISORDER)) + dp->desync_mode==DESYNC_FAKEDSPLIT || dp->desync_mode==DESYNC_FAKEDDISORDER || dp->desync_mode==DESYNC_HOSTFAKESPLIT || + dp->desync_mode2==DESYNC_FAKEDSPLIT || dp->desync_mode2==DESYNC_FAKEDDISORDER || dp->desync_mode2==DESYNC_HOSTFAKESPLIT)) || dp->dup_repeats && !dp->dup_cutoff) { @@ -1817,6 +1820,7 @@ enum opt_indices { IDX_DPI_DESYNC_SPLIT_SEQOVL, IDX_DPI_DESYNC_SPLIT_SEQOVL_PATTERN, IDX_DPI_DESYNC_FAKEDSPLIT_PATTERN, + IDX_DPI_DESYNC_HOSTFAKESPLIT_MIDHOST, IDX_DPI_DESYNC_IPFRAG_POS_TCP, IDX_DPI_DESYNC_IPFRAG_POS_UDP, IDX_DPI_DESYNC_TS_INCREMENT, @@ -1945,6 +1949,7 @@ static const struct option long_options[] = { [IDX_DPI_DESYNC_SPLIT_SEQOVL] = {"dpi-desync-split-seqovl", required_argument, 0, 0}, [IDX_DPI_DESYNC_SPLIT_SEQOVL_PATTERN] = {"dpi-desync-split-seqovl-pattern", required_argument, 0, 0}, [IDX_DPI_DESYNC_FAKEDSPLIT_PATTERN] = {"dpi-desync-fakedsplit-pattern", required_argument, 0, 0}, + [IDX_DPI_DESYNC_HOSTFAKESPLIT_MIDHOST] = {"dpi-desync-hostfakesplit-midhost", required_argument, 0, 0}, [IDX_DPI_DESYNC_IPFRAG_POS_TCP] = {"dpi-desync-ipfrag-pos-tcp", required_argument, 0, 0}, [IDX_DPI_DESYNC_IPFRAG_POS_UDP] = {"dpi-desync-ipfrag-pos-udp", required_argument, 0, 0}, [IDX_DPI_DESYNC_TS_INCREMENT] = {"dpi-desync-ts-increment", required_argument, 0, 0}, @@ -2581,6 +2586,19 @@ int main(int argc, char **argv) fill_pattern(dp->fsplit_pattern,sizeof(dp->fsplit_pattern),buf,sz); } break; + case IDX_DPI_DESYNC_HOSTFAKESPLIT_MIDHOST: + if (!strcmp(optarg,"0")) + { + // allow zero = disable midhost split + dp->hostfakesplit_midhost.marker=PM_ABS; + dp->hostfakesplit_midhost.pos=0; + } + else if (!parse_split_pos(optarg, &dp->hostfakesplit_midhost)) + { + DLOG_ERR("Invalid argument for dpi-desync-hostfakesplit-midhost\n"); + exit_clean(1); + } + break; case IDX_DPI_DESYNC_IPFRAG_POS_TCP: if (sscanf(optarg,"%u",&dp->desync_ipfrag_pos_tcp)<1 || dp->desync_ipfrag_pos_tcp<1 || dp->desync_ipfrag_pos_tcp>DPI_DESYNC_MAX_FAKE_LEN) { diff --git a/nfq/params.h b/nfq/params.h index 34780459..cbf37a3f 100644 --- a/nfq/params.h +++ b/nfq/params.h @@ -102,7 +102,7 @@ struct desync_profile // multisplit struct proto_pos splits[MAX_SPLITS]; int split_count; - struct proto_pos seqovl; + struct proto_pos seqovl,hostfakesplit_midhost; char dup_start_mode, dup_cutoff_mode; // n - packets, d - data packets, s - relative sequence bool dup_replace;