Browse Source

nfqws: combine desync and tamper logic

pull/53/head
bol-van 5 years ago
parent
commit
c2c8c83c03
  1. BIN
      binaries/aarch64/nfqws
  2. BIN
      binaries/armhf/nfqws
  3. BIN
      binaries/mips32r1-lsb/nfqws
  4. BIN
      binaries/mips32r1-msb/nfqws
  5. BIN
      binaries/mips64r2-msb/nfqws
  6. BIN
      binaries/ppc/nfqws
  7. BIN
      binaries/x86/nfqws
  8. BIN
      binaries/x86_64/nfqws
  9. 9
      nfq/checksum.c
  10. 3
      nfq/checksum.h
  11. 2
      nfq/darkmagic.c
  12. 4
      nfq/darkmagic.h
  13. 94
      nfq/desync.c
  14. 3
      nfq/desync.h
  15. 98
      nfq/nfqws.c
  16. 6
      nfq/nfqws.h

BIN
binaries/aarch64/nfqws

Binary file not shown.

BIN
binaries/armhf/nfqws

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.

9
nfq/checksum.c

@ -119,7 +119,7 @@ uint16_t csum_ipv6_magic(const void *saddr, const void *daddr, size_t len, uint8
}
void tcp_fix_checksum(struct tcphdr *tcp,int len, in_addr_t src_addr, in_addr_t dest_addr)
void tcp4_fix_checksum(struct tcphdr *tcp,int len, in_addr_t src_addr, in_addr_t dest_addr)
{
tcp->check = 0;
tcp->check = csum_tcpudp_magic(src_addr,dest_addr,len,IPPROTO_TCP,csum_partial(tcp, len));
@ -129,3 +129,10 @@ void tcp6_fix_checksum(struct tcphdr *tcp,int len, const struct in6_addr *src_ad
tcp->check = 0;
tcp->check = csum_ipv6_magic(src_addr,dest_addr,len,IPPROTO_TCP,csum_partial(tcp, len));
}
void tcp_fix_checksum(struct tcphdr *tcp,int len,const struct iphdr *iphdr,const struct ip6_hdr *ip6hdr)
{
if (iphdr)
tcp4_fix_checksum(tcp, len, iphdr->saddr, iphdr->daddr);
else if (ip6hdr)
tcp6_fix_checksum(tcp, len, &ip6hdr->ip6_src, &ip6hdr->ip6_dst);
}

3
nfq/checksum.h

@ -12,5 +12,6 @@ uint16_t csum_ipv6_magic(const void *saddr, const void *daddr, size_t len, uint8
uint16_t ip4_compute_csum(const void *buff, size_t len);
void ip4_fix_checksum(struct iphdr *ip);
void tcp_fix_checksum(struct tcphdr *tcp,int len, in_addr_t src_addr, in_addr_t dest_addr);
void tcp4_fix_checksum(struct tcphdr *tcp,int len, in_addr_t src_addr, in_addr_t dest_addr);
void tcp6_fix_checksum(struct tcphdr *tcp,int len, const struct in6_addr *src_addr, const struct in6_addr *dest_addr);
void tcp_fix_checksum(struct tcphdr *tcp,int len,const struct iphdr *iphdr,const struct ip6_hdr *ip6hdr);

2
nfq/darkmagic.c

@ -192,7 +192,7 @@ bool prepare_tcp_segment4(
fill_tcphdr(tcp,tcp_flags,seq,ack_seq,fooling,src->sin_port,dst->sin_port,wsize,timestamps);
memcpy((char*)tcp+sizeof(struct tcphdr)+tcpoptlen,data,len);
tcp_fix_checksum(tcp,sizeof(struct tcphdr)+tcpoptlen+len,ip->saddr,ip->daddr);
tcp4_fix_checksum(tcp,sizeof(struct tcphdr)+tcpoptlen+len,ip->saddr,ip->daddr);
if (fooling & TCP_FOOL_BADSUM) tcp->check^=0xBEAF;
*buflen = pktlen;

4
nfq/darkmagic.h

@ -1,5 +1,7 @@
#pragma once
#include "checksum.h"
#include <stdint.h>
#include <stdbool.h>
#include <netinet/ip.h>
@ -7,7 +9,7 @@
#include <netinet/tcp.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include "checksum.h"
// returns netorder value
uint32_t net32_add(uint32_t netorder_value, uint32_t cpuorder_increment);

94
nfq/desync.c

@ -58,9 +58,12 @@ void desync_init()
// result : true - drop original packet, false = dont drop
bool dpi_desync_packet(const uint8_t *data_pkt, size_t len_pkt, struct iphdr *iphdr, struct ip6_hdr *ip6hdr, struct tcphdr *tcphdr, uint8_t *data_payload, size_t len_payload)
packet_process_result dpi_desync_packet(uint8_t *data_pkt, size_t len_pkt, struct iphdr *iphdr, struct ip6_hdr *ip6hdr, struct tcphdr *tcphdr, size_t len_tcp, uint8_t *data_payload, size_t len_payload)
{
if (!!iphdr == !!ip6hdr) return false; // one and only one must be present
packet_process_result res=pass;
if (!!iphdr == !!ip6hdr) return res; // one and only one must be present
if (params.desync_mode==DESYNC_NONE && !params.hostcase && !params.hostnospace) return res; // nothing to do. do not waste cpu
if (!tcphdr->syn && len_payload)
{
@ -69,8 +72,9 @@ bool dpi_desync_packet(const uint8_t *data_pkt, size_t len_pkt, struct iphdr *ip
size_t fake_size;
char host[256];
bool bHaveHost=false;
bool bIsHttp;
if (IsHttp(data_payload,len_payload))
if (bIsHttp = IsHttp(data_payload,len_payload))
{
DLOG("packet contains HTTP request\n")
fake = (uint8_t*)fake_http_request;
@ -78,8 +82,8 @@ bool dpi_desync_packet(const uint8_t *data_pkt, size_t len_pkt, struct iphdr *ip
if (params.hostlist || params.debug) bHaveHost=HttpExtractHost(data_payload,len_payload,host,sizeof(host));
if (params.hostlist && !bHaveHost)
{
DLOG("not applying dpi-desync to HTTP without Host:\n")
return false;
DLOG("not applying tampering to HTTP without Host:\n")
return res;
}
}
else if (IsTLSClientHello(data_payload,len_payload))
@ -92,16 +96,15 @@ bool dpi_desync_packet(const uint8_t *data_pkt, size_t len_pkt, struct iphdr *ip
bHaveHost=TLSHelloExtractHost(data_payload,len_payload,host,sizeof(host));
if (params.desync_skip_nosni && !bHaveHost)
{
DLOG("not applying dpi-desync to TLS ClientHello without hostname in the SNI\n")
return false;
DLOG("not applying tampering to TLS ClientHello without hostname in the SNI\n")
return res;
}
}
}
else
{
if (!params.desync_any_proto) return false;
DLOG("applying dpi-desync to unknown protocol\n")
if (!params.desync_any_proto) return res;
DLOG("applying tampering to unknown protocol\n")
fake = zeropkt;
fake_size = 256;
}
@ -111,11 +114,42 @@ bool dpi_desync_packet(const uint8_t *data_pkt, size_t len_pkt, struct iphdr *ip
DLOG("hostname: %s\n",host)
if (params.hostlist && !SearchHostList(params.hostlist,host,params.debug))
{
DLOG("not applying dpi-desync to this request\n")
return false;
DLOG("not applying tampering to this request\n")
return res;
}
uint8_t *phost;
if (bIsHttp && (params.hostcase || params.hostnospace) && (phost = (uint8_t*)memmem(data_payload, len_payload, "\r\nHost: ", 8)))
{
if (params.hostcase)
{
DLOG("modifying Host: => %c%c%c%c:\n", params.hostspell[0], params.hostspell[1], params.hostspell[2], params.hostspell[3])
memcpy(phost + 2, params.hostspell, 4);
res=modify;
}
uint8_t *pua;
if (params.hostnospace &&
(pua = (uint8_t*)memmem(data_payload, len_payload, "\r\nUser-Agent: ", 14)) &&
(pua = (uint8_t*)memmem(pua + 1, len_payload - (pua - data_payload) - 1, "\r\n", 2)))
{
DLOG("removing space after Host: and adding it to User-Agent:\n")
if (pua > phost)
{
memmove(phost + 7, phost + 8, pua - phost - 8);
phost[pua - phost - 1] = ' ';
}
else
{
memmove(pua + 1, pua, phost - pua + 7);
*pua = ' ';
}
res=modify;
}
}
}
if (params.desync_mode==DESYNC_NONE) return res;
extract_endpoints(iphdr, ip6hdr, tcphdr, &src, &dst);
if (params.debug)
{
@ -150,7 +184,7 @@ bool dpi_desync_packet(const uint8_t *data_pkt, size_t len_pkt, struct iphdr *ip
data_payload+split_pos, len_payload-split_pos, newdata, &newlen) ||
!rawsend((struct sockaddr *)&dst, params.desync_fwmark, newdata, newlen))
{
return false;
return res;
}
}
@ -164,7 +198,7 @@ bool dpi_desync_packet(const uint8_t *data_pkt, size_t len_pkt, struct iphdr *ip
zeropkt, split_pos, fakeseg, &fakeseg_len) ||
!rawsend((struct sockaddr *)&dst, params.desync_fwmark, fakeseg, fakeseg_len))
{
return false;
return res;
}
}
@ -176,17 +210,17 @@ bool dpi_desync_packet(const uint8_t *data_pkt, size_t len_pkt, struct iphdr *ip
data_payload, split_pos, newdata, &newlen) ||
!rawsend((struct sockaddr *)&dst, params.desync_fwmark, newdata, newlen))
{
return false;
return res;
}
if (params.desync_mode==DESYNC_DISORDER)
{
DLOG("sending fake(2) 1st out-of-order tcp segment 0-%zu len=%zu\n",split_pos-1, split_pos)
if (!rawsend((struct sockaddr *)&dst, params.desync_fwmark, fakeseg, fakeseg_len))
return false;
return res;
}
return true;
return drop;
}
break;
case DESYNC_SPLIT:
@ -205,7 +239,7 @@ bool dpi_desync_packet(const uint8_t *data_pkt, size_t len_pkt, struct iphdr *ip
zeropkt, split_pos, fakeseg, &fakeseg_len) ||
!rawsend((struct sockaddr *)&dst, params.desync_fwmark, fakeseg, fakeseg_len))
{
return false;
return res;
}
}
@ -216,14 +250,14 @@ bool dpi_desync_packet(const uint8_t *data_pkt, size_t len_pkt, struct iphdr *ip
data_payload, split_pos, newdata, &newlen) ||
!rawsend((struct sockaddr *)&dst, params.desync_fwmark, newdata, newlen))
{
return false;
return res;
}
if (params.desync_mode==DESYNC_SPLIT)
{
DLOG("sending fake(2) 1st tcp segment 0-%zu len=%zu\n",split_pos-1, split_pos)
if (!rawsend((struct sockaddr *)&dst, params.desync_fwmark, fakeseg, fakeseg_len))
return false;
return res;
}
if (split_pos<len_payload)
@ -235,11 +269,11 @@ bool dpi_desync_packet(const uint8_t *data_pkt, size_t len_pkt, struct iphdr *ip
data_payload+split_pos, len_payload-split_pos, newdata, &newlen) ||
!rawsend((struct sockaddr *)&dst, params.desync_fwmark, newdata, newlen))
{
return false;
return res;
}
}
return true;
return drop;
}
break;
@ -248,7 +282,7 @@ bool dpi_desync_packet(const uint8_t *data_pkt, size_t len_pkt, struct iphdr *ip
ttl_fake,params.desync_tcp_fooling_mode,
fake, fake_size, newdata, &newlen))
{
return false;
return res;
}
break;
case DESYNC_RST:
@ -257,27 +291,29 @@ bool dpi_desync_packet(const uint8_t *data_pkt, size_t len_pkt, struct iphdr *ip
ttl_fake,params.desync_tcp_fooling_mode,
NULL, 0, newdata, &newlen))
{
return false;
return res;
}
break;
default:
return false;
return res;
}
if (!rawsend((struct sockaddr *)&dst, params.desync_fwmark, newdata, newlen))
return false;
return res;
if (params.desync_retrans)
DLOG("dropping packet to force retransmission. len=%zu len_payload=%zu\n", len_pkt, len_payload)
else
{
DLOG("reinjecting original packet. len=%zu len_payload=%zu\n", len_pkt, len_payload)
// if original packet was tampered earlier it needs checksum fixed
if (res==modify) tcp_fix_checksum(tcphdr,len_tcp,iphdr,ip6hdr);
if (!rawsend((struct sockaddr *)&dst, params.desync_fwmark, data_pkt, len_pkt))
return false;
return res;
}
return true;
return drop;
}
return false;
return res;
}

3
nfq/desync.h

@ -1,6 +1,7 @@
#pragma once
#include "darkmagic.h"
#include "nfqws.h"
#include <stdint.h>
#include <stdbool.h>
@ -24,4 +25,4 @@ enum dpi_desync_mode {
};
void desync_init();
bool dpi_desync_packet(const uint8_t *data_pkt, size_t len_pkt, struct iphdr *iphdr, struct ip6_hdr *ip6hdr, struct tcphdr *tcphdr, uint8_t *data_payload, size_t len_payload);
packet_process_result dpi_desync_packet(uint8_t *data_pkt, size_t len_pkt, struct iphdr *iphdr, struct ip6_hdr *ip6hdr, struct tcphdr *tcphdr, size_t len_tcp, uint8_t *data_payload, size_t len_payload);

98
nfq/nfqws.c

@ -1,5 +1,6 @@
#define _GNU_SOURCE
#include "nfqws.h"
#include "sec.h"
#include "desync.h"
#include "helpers.h"
@ -138,17 +139,6 @@ static inline bool tcp_synack_segment(const struct tcphdr *tcphdr)
tcphdr->syn == 1 &&
tcphdr->fin == 0;
}
static inline bool tcp_ack_segment(const struct tcphdr *tcphdr)
{
/* check for set bits in TCP hdr */
return tcphdr->urg == 0 &&
tcphdr->ack == 1 &&
tcphdr->rst == 0 &&
tcphdr->syn == 0 &&
tcphdr->fin == 0;
}
static void tcp_rewrite_winsize(struct tcphdr *tcp, uint16_t winsize)
{
uint16_t winsize_old;
@ -157,77 +147,19 @@ static void tcp_rewrite_winsize(struct tcphdr *tcp, uint16_t winsize)
DLOG("Window size change %u => %u\n", winsize_old, winsize)
}
// data/len points to data payload
static bool modify_tcp_packet(uint8_t *data, size_t len, struct tcphdr *tcphdr)
{
const char **method;
size_t method_len = 0;
uint8_t *phost, *pua;
bool bRet = false;
if (tcp_synack_segment(tcphdr))
if (tcp_synack_segment(tcphdr) && params.wsize)
{
if (params.wsize)
{
tcp_rewrite_winsize(tcphdr, (uint16_t)params.wsize);
bRet = true;
}
}
else if ((params.hostcase || params.hostnospace) && IsHttp(data,len))
{
if (params.hostlist)
{
char host[256];
if (HttpExtractHost(data,len,host,sizeof(host)))
{
DLOG("hostname: %s\n",host)
if (!SearchHostList(params.hostlist,host,params.debug))
{
DLOG("not applying tampering to this request\n")
return false;
}
}
else
{
DLOG("could not extract host from http request. not applying tampering\n")
return false;
}
}
if (phost = (uint8_t*)memmem(data, len, "\r\nHost: ", 8))
{
if (params.hostcase)
{
DLOG("modifying Host: => %c%c%c%c:\n", params.hostspell[0], params.hostspell[1], params.hostspell[2], params.hostspell[3])
memcpy(phost + 2, params.hostspell, 4);
bRet = true;
}
if (params.hostnospace && (pua = (uint8_t*)memmem(data, len, "\r\nUser-Agent: ", 14)) && (pua = (uint8_t*)memmem(pua + 1, len - (pua - data) - 1, "\r\n", 2)))
{
DLOG("removing space after Host: and adding it to User-Agent:\n")
if (pua > phost)
{
memmove(phost + 7, phost + 8, pua - phost - 8);
phost[pua - phost - 1] = ' ';
}
else
{
memmove(pua + 1, pua, phost - pua + 7);
*pua = ' ';
}
bRet = true;
}
}
tcp_rewrite_winsize(tcphdr, (uint16_t)params.wsize);
return true;
}
return bRet;
return false;
}
typedef enum
{
pass = 0, modify, drop
} packet_process_result;
static packet_process_result processPacketData(uint8_t *data_pkt, size_t len_pkt, uint32_t *mark)
{
struct iphdr *iphdr = NULL;
@ -235,7 +167,7 @@ static packet_process_result processPacketData(uint8_t *data_pkt, size_t len_pkt
struct tcphdr *tcphdr = NULL;
size_t len = len_pkt, len_tcp;
uint8_t *data = data_pkt;
packet_process_result res = pass;
packet_process_result res = pass, res2;
uint8_t proto;
if (*mark & params.desync_fwmark) return res;
@ -266,18 +198,10 @@ static packet_process_result processPacketData(uint8_t *data_pkt, size_t len_pkt
if (modify_tcp_packet(data, len, tcphdr))
res = modify;
if (params.desync_mode!=DESYNC_NONE)
{
if (dpi_desync_packet(data_pkt, len_pkt, iphdr, ip6hdr, tcphdr, data, len))
res = drop;
}
if (res==modify)
{
if (iphdr)
tcp_fix_checksum(tcphdr, len_tcp, iphdr->saddr, iphdr->daddr);
else
tcp6_fix_checksum(tcphdr, len_tcp, &ip6hdr->ip6_src, &ip6hdr->ip6_dst);
}
res2 = dpi_desync_packet(data_pkt, len_pkt, iphdr, ip6hdr, tcphdr, len_tcp, data, len);
res = (res2==pass && res==modify) ? modify : res2;
if (res==modify) tcp_fix_checksum(tcphdr,len_tcp,iphdr,ip6hdr);
}
return res;
}
@ -320,7 +244,7 @@ static void exithelp()
" --pidfile=<filename>\t\t\t; write pid to file\n"
" --user=<username>\t\t\t; drop root privs\n"
" --uid=uid[:gid]\t\t\t; drop root privs\n"
" --wsize=<window_size>\t\t\t; set window size. 0 = do not modify\n"
" --wsize=<window_size>\t\t\t; set window size. 0 = do not modify. OBSOLETE !\n"
" --hostcase\t\t\t\t; change Host: => host:\n"
" --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"

6
nfq/nfqws.h

@ -0,0 +1,6 @@
#pragma once
typedef enum
{
pass = 0, modify, drop
} packet_process_result;
Loading…
Cancel
Save