From 810aef6aedf2f14f25e5726736c0baa635c18eb0 Mon Sep 17 00:00:00 2001 From: RknMustDie512 Date: Wed, 25 Sep 2024 21:56:10 +0300 Subject: [PATCH] Add TLS ClientHello fake packet generator --- README.md | 4 ++ src/fakepackets.c | 128 ++++++++++++++++++++++++++++++++++++++++++++++ src/fakepackets.h | 1 + src/goodbyedpi.c | 10 ++++ 4 files changed, 143 insertions(+) diff --git a/README.md b/README.md index 2c29957..6d53625 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,10 @@ Usage: goodbyedpi.exe [OPTION...] --fake-from-hex Load fake packets for Fake Request Mode from HEX values (like 1234abcDEF). This option can be supplied multiple times, in this case each fake packet would be sent on every request in the command line argument order. + --fake-with-sni Generate fake packets for Fake Request Mode with given SNI domain name. + The packets mimic Mozilla Firefox 130 TLS ClientHello packet + (with random generated fake SessionID, key shares and ECH grease). + Can be supplied multiple times for multiple fake packets. --fake-gen Generate random-filled fake packets for Fake Request Mode, value of them (up to 30). --fake-resend Send each fake packet value number of times. diff --git a/src/fakepackets.c b/src/fakepackets.c index 1cf262e..d4d2254 100644 --- a/src/fakepackets.c +++ b/src/fakepackets.c @@ -57,6 +57,91 @@ static const unsigned char fake_https_request[] = { 0x00, 0x00, 0x00, 0x00, 0x00 }; +// Captured from Firefox 130.0.1 +static const unsigned char fake_clienthello_part0[] = { // 116 bytes + // TLS 1.2 ClientHello header (DD for length placeholder) + 0x16, 0x03, 0x01, 0xDD, 0xDD, 0x01, 0x00, 0xDD, 0xDD, 0x03, 0x03, + // Random bytes (AA for placeholder) + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + // Random Session ID + 0x20, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + // Cipher Suites + 0x00, 0x22, 0x13, 0x01, 0x13, 0x03, 0x13, 0x02, 0xC0, 0x2B, 0xC0, 0x2F, 0xCC, 0xA9, 0xCC, 0xA8, + 0xC0, 0x2C, 0xC0, 0x30, 0xC0, 0x0A, 0xC0, 0x09, 0xC0, 0x13, 0xC0, 0x14, 0x00, 0x9C, 0x00, 0x9D, + 0x00, 0x2F, 0x00, 0x35, + // Compression Methods + 0x01, 0x00, + // Extensions Length + 0xDD, 0xDD, +}; +// SNI: 00 00 L1 L1 L2 L2 00 L3 L3 (sni) +// L1 = L+5, L2 = L+3, L3 = L // 9 + L bytes +static const unsigned char fake_clienthello_part1[] = { // 523 bytes + // extended_master_secret + 0x00, 0x17, 0x00, 0x00, + // renegotiation_info + 0xFF, 0x01, 0x00, 0x01, 0x00, + // supported_groups + 0x00, 0x0A, 0x00, 0x0E, + 0x00, 0x0C, 0x00, 0x1D, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, 0x01, 0x00, 0x01, 0x01, + // ex_point_formats + 0x00, 0x0B, 0x00, 0x02, 0x01, 0x00, + // session_ticket + 0x00, 0x23, 0x00, 0x00, + // ALPN + 0x00, 0x10, 0x00, 0x0E, + 0x00, 0x0C, 0x02, 0x68, 0x32, 0x08, 0x68, 0x74, 0x74, 0x70, 0x2F, 0x31, 0x2E, 0x31, + // status_request + 0x00, 0x05, 0x00, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, + // delegated_credentials + 0x00, 0x22, 0x00, 0x0A, 0x00, 0x08, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x02, 0x03, + // key_share + 0x00, 0x33, 0x00, 0x6B, 0x00, 0x69, 0x00, 0x1D, 0x00, 0x20, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0x00, 0x17, 0x00, 0x41, 0x04, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + // supported_versions + 0x00, 0x2B, 0x00, 0x05, 0x04, 0x03, 0x04, 0x03, 0x03, + // signature_algorithms + 0x00, 0x0D, 0x00, 0x18, 0x00, 0x16, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x08, 0x04, 0x08, 0x05, + 0x08, 0x06, 0x04, 0x01, 0x05, 0x01, 0x06, 0x01, 0x02, 0x03, 0x02, 0x01, + // psk_key_exchange_modes + 0x00, 0x2D, 0x00, 0x02, 0x01, 0x01, + // record_size_limit + 0x00, 0x1C, 0x00, 0x02, 0x40, 0x01, + // encrypted_client_hello + 0xFE, 0x0D, 0x01, 0x19, 0x00, 0x00, 0x01, 0x00, 0x01, 0xAA, 0x00, 0x20, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0x00, 0xEF, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA +}; +// JA4: t13d1715h2_5b57614c22b0_5c2c66f702b0 +// JA4_r: t13d1715h2_002f,0035,009c,009d,1301,1302,1303,c009,c00a,c013,c014,c02b,c02c,c02f,c030,cca8,cca9_0005,000a,000b,000d,0017,001c,0022,0023,002b,002d,0033,fe0d,ff01_0403,0503,0603,0804,0805,0806,0401,0501,0601,0203,0201 +// JA3 Fullstring: 771,4865-4867-4866-49195-49199-52393-52392-49196-49200-49162-49161-49171-49172-156-157-47-53,0-23-65281-10-11-35-16-5-34-51-43-13-45-28-65037,29-23-24-25-256-257,0 +// JA3: b5001237acdf006056b409cc433726b0 + static int send_fake_data(const HANDLE w_filter, const PWINDIVERT_ADDRESS addr, const char *pkt, @@ -311,3 +396,46 @@ int fake_load_random(unsigned int count, unsigned int maxsize) { } return 0; } + +void set_uint16be(unsigned char *buffer, int offset, int value) { + buffer[offset] = (value >> 8) & 0xFF; + buffer[offset + 1] = value & 0xFF; +} + +int fake_load_from_sni(const char *domain_name) { + if (!domain_name) { + return 1; // just extra safeguard against NPE + } + // calculate sizes + const int name_size = strlen(domain_name); + const int part0_size = sizeof(fake_clienthello_part0); + const int part1_size = sizeof(fake_clienthello_part1); + const int sni_head_size = 9; + const int packet_size = part0_size + part1_size + sni_head_size + name_size; + // allocate memory + unsigned char *packet = malloc(packet_size); + // copy major parts of packet + memcpy(packet, fake_clienthello_part0, part0_size); + memcpy(&packet[part0_size + sni_head_size + name_size], fake_clienthello_part1, part1_size); + // replace placeholders with random generated values + unsigned int random = 0; + for (int i = 0; i < packet_size; i++) { + if (packet[i] == 0xAA) { + rand_s(&random); + packet[i] = random & 0xFF; + } + } + // write size fields into packet + set_uint16be(packet, 0x0003, packet_size - 5); + set_uint16be(packet, 0x0007, packet_size - 9); + set_uint16be(packet, 0x0072, packet_size - 116); + // write SNI extension + set_uint16be(packet, part0_size + 0, 0x0000); + set_uint16be(packet, part0_size + 2, name_size + 5); + set_uint16be(packet, part0_size + 4, name_size + 3); + packet[part0_size + 6] = 0x00; + set_uint16be(packet, part0_size + 7, name_size); + memcpy(&packet[part0_size + sni_head_size], domain_name, name_size); + // add packet to fakes + return fake_add(packet, packet_size); +} diff --git a/src/fakepackets.h b/src/fakepackets.h index 60de5ac..3bc6de6 100644 --- a/src/fakepackets.h +++ b/src/fakepackets.h @@ -19,4 +19,5 @@ int send_fake_https_request(const HANDLE w_filter, const BYTE set_seq ); int fake_load_from_hex(const char *data); +int fake_load_from_sni(const char *domain_name); int fake_load_random(unsigned int count, unsigned int maxsize); diff --git a/src/goodbyedpi.c b/src/goodbyedpi.c index f8a06a1..2ec31a8 100644 --- a/src/goodbyedpi.c +++ b/src/goodbyedpi.c @@ -189,6 +189,7 @@ static struct option long_options[] = { {"reverse-frag",no_argument, 0, '(' }, {"max-payload", optional_argument, 0, '|' }, {"fake-from-hex", required_argument, 0, 'u' }, + {"fake-with-sni", required_argument, 0, '}' }, {"fake-gen", required_argument, 0, 'j' }, {"fake-resend", required_argument, 0, 't' }, {"debug-exit", optional_argument, 0, 'x' }, @@ -948,6 +949,11 @@ int main(int argc, char *argv[]) { printf("WARNING: bad fake HEX value %s\n", optarg); } break; + case '}': // --fake-with-sni + if (fake_load_from_sni(optarg)) { + printf("WARNING: bad domain name for SNI: %s\n", optarg); + } + break; case 'j': // --fake-gen if (fake_load_random(atoub(optarg, "Fake generator parameter error!"), 200)) { puts("WARNING: fake generator has failed!"); @@ -1013,6 +1019,10 @@ int main(int argc, char *argv[]) { " --fake-from-hex Load fake packets for Fake Request Mode from HEX values (like 1234abcDEF).\n" " This option can be supplied multiple times, in this case each fake packet\n" " would be sent on every request in the command line argument order.\n" + " --fake-with-sni Generate fake packets for Fake Request Mode with given SNI domain name.\n" + " The packets mimic Mozilla Firefox 130 TLS ClientHello packet\n" + " (with random generated fake SessionID, key shares and ECH grease).\n" + " Can be supplied multiple times for multiple fake packets.\n" " --fake-gen Generate random-filled fake packets for Fake Request Mode, value of them\n" " (up to 30).\n" " --fake-resend Send each fake packet value number of times.\n"