tpws: --tlsrec

This commit is contained in:
bol-van 2023-10-12 12:35:06 +03:00
parent 2456aae8ad
commit 6dc413d0c9
30 changed files with 3372 additions and 3493 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -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
}

View File

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

View File

@ -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.

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -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 ваши соединения неотличимы от тех, что сделал бы сам шлюз.

View File

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

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
}
}
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;
}
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;
}
else if (params.split_any_protocol)
*split_pos = params.split_pos;
}
}

View File

@ -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);

View File

@ -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

View File

@ -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)