Browse Source

tpws: --tlsrec

pull/172/head
bol-van 2 years ago
parent
commit
6dc413d0c9
  1. BIN
      binaries/aarch64/tpws
  2. BIN
      binaries/arm/tpws
  3. BIN
      binaries/freebsd-x64/tpws
  4. BIN
      binaries/mac64/tpws
  5. BIN
      binaries/mips32r1-lsb/tpws
  6. BIN
      binaries/mips32r1-msb/tpws
  7. BIN
      binaries/mips64r2-msb/tpws
  8. BIN
      binaries/ppc/tpws
  9. BIN
      binaries/x86/tpws
  10. BIN
      binaries/x86_64/tpws
  11. BIN
      binaries/x86_64/tpws_wsl.tgz
  12. 3
      blockcheck.sh
  13. 2
      docs/bsd.txt
  14. 4
      docs/changes.txt
  15. 2
      docs/nftables_notes.txt
  16. 2
      docs/quick_start.txt
  17. 1372
      docs/readme.eng.md
  18. 17
      docs/readme.txt
  19. 2
      docs/redsocks.txt
  20. 5
      tpws/helpers.h
  21. 3
      tpws/params.h
  22. 58
      tpws/tamper.c
  23. 5
      tpws/tamper.h
  24. 74
      tpws/tpws.c
  25. 8
      tpws/tpws_conn.c

BIN
binaries/aarch64/tpws

Binary file not shown.

BIN
binaries/arm/tpws

Binary file not shown.

BIN
binaries/freebsd-x64/tpws

Binary file not shown.

BIN
binaries/mac64/tpws

Binary file not shown.

BIN
binaries/mips32r1-lsb/tpws

Binary file not shown.

BIN
binaries/mips32r1-msb/tpws

Binary file not shown.

BIN
binaries/mips64r2-msb/tpws

Binary file not shown.

BIN
binaries/ppc/tpws

Binary file not shown.

BIN
binaries/x86/tpws

Binary file not shown.

BIN
binaries/x86_64/tpws

Binary file not shown.

BIN
binaries/x86_64/tpws_wsl.tgz

Binary file not shown.

3
blockcheck.sh

@ -645,6 +645,9 @@ tpws_check_domain_bypass()
tpws_curl_test_update $1 $3 $s $s2 && break
done
done
for s2 in '--tlsrec=sni' '--tlsrec=sni --split-pos=10' '--tlsrec=sni --split-pos=10 --disorder'; do
tpws_curl_test_update $1 $3 $s2 && [ "$FORCE" != 1 ] && break
done
fi
report_strategy $1 $3 tpws
}

2
docs/bsd.txt

@ -1,4 +1,4 @@
Поддерживаемые версии
Поддерживаемые версии
---------------------
FreeBSD 11.x+ , OpenBSD 6.x+, частично MacOS Sierra+

4
docs/changes.txt

@ -243,3 +243,7 @@ v50
DHT protocol support.
DPI desync mode 'tamper' for DHT.
HEX string support in addition to binary files.
v51
tpws --tlsrec attack.

2
docs/nftables_notes.txt

@ -1,4 +1,4 @@
nftables - это технология, пришедшая на замену iptables.
nftables - это технология, пришедшая на замену iptables.
В ней собрали все, что относилось к различным iptables. А их немало. iptables, ip6tables, ebtables, arptables, ipset.
Весь код из разрозненных, но похожих компонент, собрали в одно целое с единым синтаксисом.
Добавили различные конструкции языка, позволяющие писать правила более лаконично, не повторяя одни и те же команды с небольшими различиями.

2
docs/quick_start.txt

@ -1,4 +1,4 @@
Специально для тех, кто хочет побыстрее начать, но не хочет слишком углубляться в простыню readme.txt.
Специально для тех, кто хочет побыстрее начать, но не хочет слишком углубляться в простыню readme.txt.
Предупреждение : не пишите в issue вопросы типа "как скопировать файл", "как скачать", "как запустить", ...
То есть все , что касается базовых навыков обращения с ОС linux. Эти вопросы буду закрывать сразу.

1372
docs/readme.eng.md

File diff suppressed because it is too large

17
docs/readme.txt

@ -1,4 +1,4 @@
zapret v.50
zapret v.51
English
-------
@ -592,6 +592,8 @@ tpws - это transparent proxy.
--methodspace ; добавить пробел после метода : "GET /" => "GET /"
--methodeol ; добавить перевод строки перед методом : "GET /" => "\r\nGET /"
--unixeol ; конвертировать 0D0A в 0A и использовать везде 0A
--tlsrec=sni ; разбивка TLS ClientHello на 2 TLS records. режем между 1 и 2 символами hostname в SNI. Если SNI нет - отмена.
--tlsrec-pos=<pos> ; разбивка TLS ClientHello на 2 TLS records. режем на указанной позиции, если длина слишком мелкая - на позиции 1.
--hostlist=<filename> ; действовать только над доменами, входящими в список из filename. поддомены автоматически учитываются.
; в файле должен быть хост на каждой строке.
; список читается 1 раз при старте и хранится в памяти в виде иерархической структуры для быстрого поиска.
@ -691,6 +693,19 @@ tpws полностью работает на асинхронных сокет
а потом полный запрос без сплита. На него может отреагировать DPI штатным образом.
--disorder является дополнительным флагом к любому сплиту. Сам по себе он не делает ничего.
--tlsrec и --tlsrec-pos позволяют внутри одного tcp сегмента разрезать TLS ClientHello на 2 TLS records.
--tlsrec=sni режет между 1 и 2 символами hostname в SNI, делая невозможным бинарный поиск паттерна без анализа структуры данных.
В случае отсутствия SNI разбиение отменяется.
--tlsrec-pos режет на указанной позиции. Если длина блока данных TLS меньше указанной позиции, режем на позиции 1.
Параметр сочетается с --split-pos. В этом случае происходит сначала разделение на уровне TLS record layer, потом на уровне TCP.
Самая изорщенная атака --tslrec, --split-pos и --disorder вместе.
--tlsrec ломает значительное количество сайтов. Криптобиблиотеки (openssl, ...) на оконечных http серверах без проблем
принимают разделенные tls сегменты, но мидлбоксы - не всегда. К мидлбоксам можно отнести CDN или системы ddos-защиты.
Поэтому применение --tlsrec без ограничителей вряд ли целесообразно.
В РФ --tlsrec обычно не работает с TLS 1.2, потому что цензор парсит сертификат сервера из ServerHello.
Работает только с TLS 1.3, поскольку там эта информация шифруется.
Впрочем, сейчас сайтов, не поддерживающих TLS 1.3, осталось немного.
--skip-nodelay может быть полезен, чтобы привести MTU к MTU системы, на которой работает tpws.
Это может быть полезно для скрытия факта использования VPN. Пониженный MTU - 1 из способов обнаружения
подозрительного подключения. С tcp proxy ваши соединения неотличимы от тех, что сделал бы сам шлюз.

2
docs/redsocks.txt

@ -1,4 +1,4 @@
Данный мануал пишется не как копипастная инструкция, а как помощь уже соображающему.
Данный мануал пишется не как копипастная инструкция, а как помощь уже соображающему.
Если вы не знаете основ сетей, linux, openwrt, а пытаетесь что-то скопипастить отсюда без малейшего
понимания смысла, то маловероятно, что у вас что-то заработает. Не тратье свое время напрасно.
Цель - донести принципы как это настраивается вообще, а не указать какую буковку где вписать.

5
tpws/helpers.h

@ -31,6 +31,11 @@ bool set_hl(int fd, int hl);
bool set_ttl_hl(int fd, int ttl);
int get_so_error(int fd);
// alignment-safe functions
static inline uint16_t pntoh16(const uint8_t *p) {
return ((uint16_t)p[0] << 8) | (uint16_t)p[1];
}
static inline void phton16(uint8_t *p, uint16_t v) {
p[0] = (uint8_t)(v>>8);
p[1] = (uint8_t)v;
}

3
tpws/params.h

@ -8,6 +8,7 @@
#include "strpool.h"
enum splithttpreq { split_none = 0, split_method, split_host };
enum tlsrec { tlsrec_none = 0, tlsrec_sni, tlsrec_pos };
enum bindll { unwanted=0, no, prefer, force };
#define MAX_BINDS 32
@ -41,6 +42,8 @@ struct params_s
int hostpad;
char hostspell[4];
enum splithttpreq split_http_req;
enum tlsrec tlsrec;
int tlsrec_pos;
bool split_any_protocol;
int split_pos;
bool disorder;

58
tpws/tamper.c

@ -4,11 +4,12 @@
#include "params.h"
#include "hostlist.h"
#include "protocol.h"
#include "helpers.h"
#include <string.h>
#include <stdio.h>
// pHost points to "Host: ..."
bool find_host(char **pHost,char *buf,size_t bs)
bool find_host(uint8_t **pHost,uint8_t *buf,size_t bs)
{
if (!*pHost)
{
@ -23,14 +24,15 @@ bool find_host(char **pHost,char *buf,size_t bs)
}
static const char *http_methods[] = { "GET /","POST /","HEAD /","OPTIONS /","PUT /","DELETE /","CONNECT /","TRACE /",NULL };
void modify_tcp_segment(char *segment,size_t segment_buffer_size,size_t *size,size_t *split_pos)
// segment buffer has at least 5 extra bytes to extend data block
void modify_tcp_segment(uint8_t *segment,size_t segment_buffer_size,size_t *size,size_t *split_pos)
{
char *p, *pp, *pHost = NULL;
uint8_t *p, *pp, *pHost = NULL;
size_t method_len = 0, pos;
const char **method;
bool bIsHttp = false, bBypass = false;
char bRemovedHostSpace = 0;
char Host[128];
char *pc, Host[128];
*split_pos=0;
@ -57,7 +59,7 @@ void modify_tcp_segment(char *segment,size_t segment_buffer_size,size_t *size,si
memcpy(Host, p, pp - p);
Host[pp - p] = '\0';
VPRINT("Requested Host is : %s", Host)
for(p = Host; *p; p++) *p=tolower(*p);
for(pc = Host; *pc; pc++) *pc=tolower(*pc);
bBypass = !HostlistCheck(params.hostlist, params.hostlist_exclude, Host);
}
if (!bBypass)
@ -208,13 +210,14 @@ void modify_tcp_segment(char *segment,size_t segment_buffer_size,size_t *size,si
{
VPRINT("Not acting on this request")
}
return;
}
else if (params.split_pos && params.split_pos < *size)
{
// split-pos is the only parameter applicable to non-http block (may be https ?)
if (IsTLSClientHello((uint8_t*)segment,*size))
if (IsTLSClientHello(segment,*size))
{
char host[256];
size_t tpos=0,elen;
const uint8_t *ext;
VPRINT("packet contains TLS ClientHello")
// we need host only if hostlist is present
@ -227,9 +230,42 @@ void modify_tcp_segment(char *segment,size_t segment_buffer_size,size_t *size,si
return;
}
}
*split_pos = params.split_pos;
switch(params.tlsrec)
{
case tlsrec_sni:
if (TLSFindExt(segment,*size,0,&ext,&elen))
tpos = ext-segment+1; // between typical 1st and 2nd char of hostname
break;
case tlsrec_pos:
tpos = params.tlsrec_pos;
break;
default:
break;
}
else if (params.split_any_protocol)
if (tpos)
{
// construct 2 TLS records from one
uint16_t l = pntoh16(segment+3); // length
if (l>=2)
{
// length is checked in IsTLSClientHello and cannot exceed buffer size
if (tpos>=l) tpos=1;
VPRINT("making 2 TLS records at pos %zu",tpos)
memmove(segment+5+tpos+5,segment+5+tpos,l-tpos);
segment[5+tpos] = segment[0];
segment[5+tpos+1] = segment[1];
segment[5+tpos+2] = segment[2];
phton16(segment+5+tpos+3,l-tpos);
phton16(segment+3,tpos);
*size += 5;
}
}
if (params.split_pos < *size)
*split_pos = params.split_pos;
return;
}
if (params.split_any_protocol && params.split_pos < *size)
*split_pos = params.split_pos;
}

5
tpws/tamper.h

@ -1,7 +1,8 @@
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include <sys/types.h>
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);
bool find_host(uint8_t **pHost,uint8_t *buf,size_t bs);
void modify_tcp_segment(uint8_t *segment,size_t segment_buffer_size,size_t *size,size_t *split_pos);

74
tpws/tpws.c

@ -174,6 +174,8 @@ static void exithelp()
" --methodspace\t\t\t; add extra space after method\n"
" --methodeol\t\t\t; add end-of-line before method\n"
" --unixeol\t\t\t; replace 0D0A to 0A\n"
" --tlsrec=sni\t\t\t; make 2 TLS records. split at SNI. don't split if SNI is not present\n"
" --tlsrec-pos=<pos>\t\t; make 2 TLS records. split at specified pos\n"
);
exit(1);
}
@ -288,19 +290,21 @@ void parse_params(int argc, char *argv[])
{ "methodeol",no_argument,0,0 },// optidx=28
{ "hosttab",no_argument,0,0 },// optidx=29
{ "unixeol",no_argument,0,0 },// optidx=30
{ "hostlist",required_argument,0,0 },// optidx=31
{ "hostlist-exclude",required_argument,0,0 },// optidx=32
{ "pidfile",required_argument,0,0 },// optidx=33
{ "debug",optional_argument,0,0 },// optidx=34
{ "local-rcvbuf",required_argument,0,0 },// optidx=35
{ "local-sndbuf",required_argument,0,0 },// optidx=36
{ "remote-rcvbuf",required_argument,0,0 },// optidx=37
{ "remote-sndbuf",required_argument,0,0 },// optidx=38
{ "socks",no_argument,0,0 },// optidx=39
{ "no-resolve",no_argument,0,0 },// optidx=40
{ "skip-nodelay",no_argument,0,0 },// optidx=41
{ "tlsrec",required_argument,0,0 },// optidx=31
{ "tlsrec-pos",required_argument,0,0 },// optidx=32
{ "hostlist",required_argument,0,0 },// optidx=33
{ "hostlist-exclude",required_argument,0,0 },// optidx=34
{ "pidfile",required_argument,0,0 },// optidx=35
{ "debug",optional_argument,0,0 },// optidx=36
{ "local-rcvbuf",required_argument,0,0 },// optidx=37
{ "local-sndbuf",required_argument,0,0 },// optidx=38
{ "remote-rcvbuf",required_argument,0,0 },// optidx=39
{ "remote-sndbuf",required_argument,0,0 },// optidx=40
{ "socks",no_argument,0,0 },// optidx=41
{ "no-resolve",no_argument,0,0 },// optidx=42
{ "skip-nodelay",no_argument,0,0 },// optidx=43
#if defined(BSD) && !defined(__OpenBSD__) && !defined(__APPLE__)
{ "enable-pf",no_argument,0,0 },// optidx=42
{ "enable-pf",no_argument,0,0 },// optidx=44
#endif
{ NULL,0,NULL,0 }
};
@ -472,7 +476,7 @@ void parse_params(int argc, char *argv[])
break;
case 24: /* split-pos */
i = atoi(optarg);
if (i)
if (i>0)
params.split_pos = i;
else
{
@ -504,7 +508,27 @@ void parse_params(int argc, char *argv[])
params.unixeol = true;
params.tamper = true;
break;
case 31: /* hostlist */
case 31: /* tlsrec */
if (!strcmp(optarg, "sni"))
params.tlsrec = tlsrec_sni;
else
{
fprintf(stderr, "Invalid argument for tlsrec\n");
exit_clean(1);
}
params.tamper = true;
break;
case 32: /* tlsrec-pos */
if ((params.tlsrec_pos = atoi(optarg))>0)
params.tlsrec = tlsrec_pos;
else
{
fprintf(stderr, "Invalid argument for tlsrec-pos\n");
exit_clean(1);
}
params.tamper = true;
break;
case 33: /* hostlist */
if (!strlist_add(&params.hostlist_files, optarg))
{
fprintf(stderr, "strlist_add failed\n");
@ -512,7 +536,7 @@ void parse_params(int argc, char *argv[])
}
params.tamper = true;
break;
case 32: /* hostlist-exclude */
case 34: /* hostlist-exclude */
if (!strlist_add(&params.hostlist_exclude_files, optarg))
{
fprintf(stderr, "strlist_add failed\n");
@ -520,36 +544,36 @@ void parse_params(int argc, char *argv[])
}
params.tamper = true;
break;
case 33: /* pidfile */
case 35: /* pidfile */
strncpy(params.pidfile,optarg,sizeof(params.pidfile));
params.pidfile[sizeof(params.pidfile)-1]='\0';
break;
case 34:
case 36:
params.debug = optarg ? atoi(optarg) : 1;
break;
case 35: /* local-rcvbuf */
case 37: /* local-rcvbuf */
params.local_rcvbuf = atoi(optarg)/2;
break;
case 36: /* local-sndbuf */
case 38: /* local-sndbuf */
params.local_sndbuf = atoi(optarg)/2;
break;
case 37: /* remote-rcvbuf */
case 39: /* remote-rcvbuf */
params.remote_rcvbuf = atoi(optarg)/2;
break;
case 38: /* remote-sndbuf */
case 40: /* remote-sndbuf */
params.remote_sndbuf = atoi(optarg)/2;
break;
case 39: /* socks */
case 41: /* socks */
params.proxy_type = CONN_TYPE_SOCKS;
break;
case 40: /* no-resolve */
case 42: /* no-resolve */
params.no_resolve = true;
break;
case 41: /* skip-nodelay */
case 43: /* skip-nodelay */
params.skip_nodelay = true;
break;
#if defined(BSD) && !defined(__OpenBSD__) && !defined(__APPLE__)
case 42: /* enable-pf */
case 44: /* enable-pf */
params.pf_enable = true;
break;
#endif

8
tpws/tpws_conn.c

@ -133,7 +133,7 @@ ssize_t send_with_ttl(int fd, const void *buf, size_t len, int flags, int ttl)
}
static bool send_buffer_create(send_buffer_t *sb, char *data, size_t len, int ttl)
static bool send_buffer_create(send_buffer_t *sb, const void *data, size_t len, int ttl)
{
if (sb->data)
{
@ -258,7 +258,7 @@ static bool conn_has_unsent_pair(tproxy_conn_t *conn)
}
static ssize_t send_or_buffer(send_buffer_t *sb, int fd, char *buf, size_t len, int ttl)
static ssize_t send_or_buffer(send_buffer_t *sb, int fd, const void *buf, size_t len, int ttl)
{
ssize_t wr=0;
if (len)
@ -919,7 +919,7 @@ static bool handle_epoll(tproxy_conn_t *conn, struct tailhead *conn_list, uint32
if (!conn_partner_alive(conn))
{
// throw it to a black hole
char waste[65070];
uint8_t waste[65070];
ssize_t trd=0;
while((rd=recv(conn->fd, waste, sizeof(waste), MSG_DONTWAIT))>0 && trd<MAX_WASTE)
@ -969,7 +969,7 @@ static bool handle_epoll(tproxy_conn_t *conn, struct tailhead *conn_list, uint32
#endif
{
// incoming data from local leg
char buf[RD_BLOCK_SIZE + 4];
uint8_t buf[RD_BLOCK_SIZE + 5];
rd = recv(conn->fd, buf, RD_BLOCK_SIZE, MSG_DONTWAIT);
DBGPRINT("recv fd=%d rd=%zd err=%d",conn->fd, rd,errno)

Loading…
Cancel
Save