Browse Source

tpws: memmem nfqws: memmem, nfqws check hostlist in hostcase and hostnospace options

pull/53/head
bol-van 5 years ago
parent
commit
b430221cd6
  1. BIN
      binaries/aarch64/nfqws
  2. BIN
      binaries/aarch64/tpws
  3. BIN
      binaries/armhf/nfqws
  4. BIN
      binaries/armhf/tpws
  5. BIN
      binaries/mips32r1-lsb/nfqws
  6. BIN
      binaries/mips32r1-lsb/tpws
  7. BIN
      binaries/mips32r1-msb/nfqws
  8. BIN
      binaries/mips32r1-msb/tpws
  9. BIN
      binaries/mips64r2-msb/nfqws
  10. BIN
      binaries/mips64r2-msb/tpws
  11. BIN
      binaries/ppc/nfqws
  12. BIN
      binaries/ppc/tpws
  13. BIN
      binaries/x86/nfqws
  14. BIN
      binaries/x86/tpws
  15. BIN
      binaries/x86_64/nfqws
  16. BIN
      binaries/x86_64/tpws
  17. 5
      docs/readme.eng.txt
  18. 5
      docs/readme.txt
  19. 5
      nfq/desync.c
  20. 49
      nfq/helpers.c
  21. 7
      nfq/helpers.h
  22. 66
      nfq/nfqws.c
  23. 5
      nfq/protocol.c
  24. 18
      tpws/tamper.c
  25. 1
      tpws/tamper.h
  26. 1
      tpws/tpws_conn.c

BIN
binaries/aarch64/nfqws

Binary file not shown.

BIN
binaries/aarch64/tpws

Binary file not shown.

BIN
binaries/armhf/nfqws

Binary file not shown.

BIN
binaries/armhf/tpws

Binary file not shown.

BIN
binaries/mips32r1-lsb/nfqws

Binary file not shown.

BIN
binaries/mips32r1-lsb/tpws

Binary file not shown.

BIN
binaries/mips32r1-msb/nfqws

Binary file not shown.

BIN
binaries/mips32r1-msb/tpws

Binary file not shown.

BIN
binaries/mips64r2-msb/nfqws

Binary file not shown.

BIN
binaries/mips64r2-msb/tpws

Binary file not shown.

BIN
binaries/ppc/nfqws

Binary file not shown.

BIN
binaries/ppc/tpws

Binary file not shown.

BIN
binaries/x86/nfqws

Binary file not shown.

BIN
binaries/x86/tpws

Binary file not shown.

BIN
binaries/x86_64/nfqws

Binary file not shown.

BIN
binaries/x86_64/tpws

Binary file not shown.

5
docs/readme.eng.txt

@ -135,7 +135,7 @@ It takes the following parameters:
--dpi-desync-skip-nosni=0|1 ; 1(default)=do not apply desync to requests without hostname in the SNI
--dpi-desync-split-pos=<1..1500> ; (for disorder only) split TCP packet at specified position
--dpi-desync-any-protocol=0|1 ; 0(default)=desync only http and tls 1=desync any nonempty data packet
--hostlist=<filename> ; apply dpi desync only to the listed hosts (one host per line, subdomains auto apply)
--hostlist=<filename> ; apply fooling only to the listed hosts (one host per line, subdomains auto apply)
The manipulation parameters can be combined in any way.
@ -189,7 +189,7 @@ Split mode is very similar to disorder but without segment reordering :
4. 2nd segment
Mode 'split2' disables sending of fake segments. It can be used as a faster alternative to --wsize.
In disorder2 and split2 modes no fake packets are sent, so no fooling options are required.
In disorder2 and split2 modes no fake packets are sent, so ttl and fooling options are not required.
There are DPIs that analyze responses from the server, particularly the certificate from the ServerHello
that contain domain name(s). The ClientHello delivery confirmation is an ACK packet from the server
@ -204,7 +204,6 @@ doing something about it is hardly possible without the help of the server.
The best solution is to enable TLS 1.3 support on the server. TLS 1.3 sends the server certificate in encrypted form.
This is recommendation to all admins of blocked sites. Enable TLS 1.3. You will give more opportunities to overcome DPI.
Hostlist is applicable only to desync attack. It does not work for other options.
Hosts are extracted from plain http request Host: header and SNI of ClientHelllo TLS message.
Subdomains are applied automatically. gzip lists are supported.

5
docs/readme.txt

@ -166,7 +166,7 @@ nfqws
--dpi-desync-skip-nosni=0|1 ; 1(default)=не применять dpi desync для запросов без hostname в SNI, в частности для ESNI
--dpi-desync-split-pos=<1..1500> ; (только для disorder) разбивать пакет на указанной позиции
--dpi-desync-any-protocol=0|1 ; 0(default)=работать только по http request и tls clienthello 1=по всем непустым пакетам данных
--hostlist=<filename> ; применять dpi-desync только к хостам из листа
--hostlist=<filename> ; применять дурение только к хостам из листа
Параметры манипуляции могут сочетаться в любых комбинациях.
@ -224,7 +224,7 @@ nfqws
Режим split2 отключает отправку поддельных частей.
Он может быть использован как более быстрая альтернатива --wsize.
disorder2 и split2 не предполагают отсылку фейк пакетов, поэтому опции дурения неактуальны.
disorder2 и split2 не предполагают отсылку фейк пакетов, поэтому опции ttl и fooling неактуальны.
Есть DPI, которые анализируют ответы от сервера, в частности сертификат из ServerHello, где прописаны домены.
Подтверждением доставки ClientHello является ACK пакет от сервера с номером ACK sequence, соответствующим длине ClientHello+1.
@ -239,7 +239,6 @@ DPI может отстать от потока, если ClientHello его у
Лучшее решение - включить на сервере поддержку TLS 1.3. В нем сертификат сервера передается в зашифрованном виде.
Это рекомендация ко всем админам блокируемых сайтов. Включайте TLS 1.3. Так вы дадите больше возможностей преодолеть DPI.
hostlist относится только к атаке desync. он не работает для других параметров. при попытке запустить nfqws с hostlist и без dpi-desync будет ошибка.
Хосты извлекаются из Host: хедера обычных http запросов и из SNI в TLS ClientHello.
Субдомены учитываются автоматически. Поддерживаются листы gzip.

5
nfq/desync.c

@ -76,6 +76,11 @@ bool dpi_desync_packet(const uint8_t *data_pkt, size_t len_pkt, struct iphdr *ip
fake = (uint8_t*)fake_http_request;
fake_size = sizeof(fake_http_request);
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;
}
}
else if (IsTLSClientHello(data_payload,len_payload))
{

49
nfq/helpers.c

@ -1,29 +1,9 @@
#define _GNU_SOURCE
#include "helpers.h"
#include <string.h>
#include <stdio.h>
const uint8_t *find_bin_const(const uint8_t *data, size_t len, const void *blk, size_t blk_len)
{
while (len >= blk_len)
{
if (!memcmp(data, blk, blk_len))
return data;
data++;
len--;
}
return NULL;
}
uint8_t *find_bin(uint8_t *data, size_t len, const void *blk, size_t blk_len)
{
while (len >= blk_len)
{
if (!memcmp(data, blk, blk_len))
return data;
data++;
len--;
}
return NULL;
}
#include <string.h>
#include <ctype.h>
void print_sockaddr(const struct sockaddr *sa)
{
@ -42,3 +22,24 @@ void print_sockaddr(const struct sockaddr *sa)
printf("UNKNOWN_FAMILY_%d", sa->sa_family);
}
}
char *strncasestr(const char *s,const char *find, size_t slen)
{
char c, sc;
size_t len;
if ((c = *find++) != '\0')
{
len = strlen(find);
do
{
do
{
if (slen-- < 1 || (sc = *s++) == '\0') return NULL;
} while (toupper(c) != toupper(sc));
if (len > slen) return NULL;
} while (strncasecmp(s, find, len) != 0);
s--;
}
return (char *)s;
}

7
nfq/helpers.h

@ -1,10 +1,7 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include <arpa/inet.h>
#include <stddef.h>
const uint8_t *find_bin_const(const uint8_t *data, size_t len, const void *blk, size_t blk_len);
uint8_t *find_bin(uint8_t *data, size_t len, const void *blk, size_t blk_len);
void print_sockaddr(const struct sockaddr *sa);
char *strncasestr(const char *s,const char *find, size_t slen);

66
nfq/nfqws.c

@ -5,6 +5,7 @@
#include "helpers.h"
#include "checksum.h"
#include "params.h"
#include "protocol.h"
#include "hostlist.h"
#include <stdio.h>
@ -165,34 +166,57 @@ static bool modify_tcp_packet(uint8_t *data, size_t len, struct tcphdr *tcphdr)
uint8_t *phost, *pua;
bool bRet = false;
if (params.wsize && tcp_synack_segment(tcphdr))
if (tcp_synack_segment(tcphdr))
{
tcp_rewrite_winsize(tcphdr, (uint16_t)params.wsize);
bRet = true;
}
if ((params.hostcase || params.hostnospace) && (phost = find_bin(data, len, "\r\nHost: ", 8)))
{
if (params.hostcase)
if (params.wsize)
{
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);
tcp_rewrite_winsize(tcphdr, (uint16_t)params.wsize);
bRet = true;
}
if (params.hostnospace && (pua = find_bin(data, len, "\r\nUser-Agent: ", 14)) && (pua = find_bin(pua + 1, len - (pua - data) - 1, "\r\n", 2)))
}
else if ((params.hostcase || params.hostnospace) && IsHttp(data,len))
{
if (params.hostlist)
{
DLOG("removing space after Host: and adding it to User-Agent:\n")
if (pua > phost)
char host[256];
if (HttpExtractHost(data,len,host,sizeof(host)))
{
memmove(phost + 7, phost + 8, pua - phost - 8);
phost[pua - phost - 1] = ' ';
DLOG("hostname: %s\n",host)
if (!SearchHostList(params.hostlist,host,params.debug))
{
DLOG("not applying tampering to this request\n")
return false;
}
}
else
{
memmove(pua + 1, pua, phost - pua + 7);
*pua = ' ';
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;
}
bRet = true;
}
}
return bRet;
@ -531,12 +555,6 @@ int main(int argc, char **argv)
}
}
if (params.desync_mode==DESYNC_NONE && params.hostlist)
{
fprintf(stderr, "hostlist is applicable only to dpi-desync\n");
exit_clean(1);
}
if (daemon) daemonize();
h = NULL;

5
nfq/protocol.c

@ -1,8 +1,11 @@
#define _GNU_SOURCE
#include "protocol.h"
#include "helpers.h"
#include <string.h>
#include <ctype.h>
#include <arpa/inet.h>
#include <string.h>
const char *http_methods[] = { "GET /","POST /","HEAD /","OPTIONS /","PUT /","DELETE /","CONNECT /","TRACE /",NULL };
bool IsHttp(const char *data, size_t len)
@ -21,7 +24,7 @@ bool HttpExtractHost(const uint8_t *data, size_t len, char *host, size_t len_hos
{
const uint8_t *p, *s, *e=data+len;
p = find_bin_const(data, len, "\nHost:", 6);
p = (uint8_t*)strncasestr((char*)data, "\nHost:", len);
if (!p) return false;
p+=6;
while(p<e && (*p==' ' || *p=='\t')) p++;

18
tpws/tamper.c

@ -1,27 +1,17 @@
#define _GNU_SOURCE
#include "tamper.h"
#include "params.h"
#include "hostlist.h"
#include <string.h>
#include <stdio.h>
char *find_bin(void *data, size_t len, const void *blk, size_t blk_len)
{
while (len >= blk_len)
{
if (!memcmp(data, blk, blk_len))
return data;
data = (char*)data + 1;
len--;
}
return NULL;
}
// pHost points to "Host: ..."
bool find_host(char **pHost,char *buf,size_t bs)
{
if (!*pHost)
{
*pHost = find_bin(buf, bs, "\nHost:", 6);
*pHost = memmem(buf, bs, "\nHost:", 6);
if (*pHost)
{
(*pHost)++;
@ -74,7 +64,7 @@ void modify_tcp_segment(char *segment,size_t segment_buffer_size,size_t *size,si
if (params.unixeol)
{
p = pp = segment;
while (p = find_bin(p, segment + *size - p, "\r\n", 2))
while (p = memmem(p, segment + *size - p, "\r\n", 2))
{
*p = '\n'; p++;
memmove(p, p + 1, segment + *size - p - 1);

1
tpws/tamper.h

@ -3,6 +3,5 @@
#include <stdbool.h>
#include <sys/types.h>
char *find_bin(void *data, size_t len, const void *blk, size_t blk_len);
bool find_host(char **pHost,char *buf,size_t bs);
void modify_tcp_segment(char *segment,size_t segment_buffer_size,size_t *size,size_t *split_pos);

1
tpws/tpws_conn.c

@ -98,7 +98,6 @@ static int get_so_error(int fd)
socklen_t optlen = sizeof(errn);
if(getsockopt(fd, SOL_SOCKET, SO_ERROR, &errn, &optlen) == -1)
errn=errno;
return errn;
}
static bool proxy_remote_conn_ack(tproxy_conn_t *conn, int sock_err)

Loading…
Cancel
Save