From e554958c75e71e39bccb412b2d8645014fabd99a Mon Sep 17 00:00:00 2001 From: lwthiker Date: Sat, 5 Mar 2022 13:03:27 +0200 Subject: [PATCH] Impersonate Chrome 99 and Edge 99 Add impersonation support for Chrome 99 and Edge 99 which were just released. Their TLS signature is identical to the previous versions (98). The only difference is in the user agents. curl patch from https://github.com/lwthiker/curl/commit/ca13947f003ee711367f0438693caee93ccee696 --- chrome/curl_chrome99 | 26 ++++ chrome/curl_edge99 | 26 ++++ chrome/patches/curl-impersonate.patch | 90 +++++++++++- tests/signatures.yaml | 192 ++++++++++++++++++++++++++ tests/test_impersonate.py | 18 +++ 5 files changed, 347 insertions(+), 5 deletions(-) create mode 100755 chrome/curl_chrome99 create mode 100755 chrome/curl_edge99 diff --git a/chrome/curl_chrome99 b/chrome/curl_chrome99 new file mode 100755 index 0000000..3919e2d --- /dev/null +++ b/chrome/curl_chrome99 @@ -0,0 +1,26 @@ +#!/bin/bash + +# Find the directory of this script +dir=`echo "$0" | sed 's%/[^/]*$%%'` + +# The list of ciphers can be obtained by looking at the Client Hello message in +# Wireshark, then converting it using this reference +# https://wiki.mozilla.org/Security/Cipher_Suites +"$dir/curl-impersonate" \ + --ciphers TLS_AES_128_GCM_SHA256,TLS_AES_256_GCM_SHA384,TLS_CHACHA20_POLY1305_SHA256,ECDHE-ECDSA-AES128-GCM-SHA256,ECDHE-RSA-AES128-GCM-SHA256,ECDHE-ECDSA-AES256-GCM-SHA384,ECDHE-RSA-AES256-GCM-SHA384,ECDHE-ECDSA-CHACHA20-POLY1305,ECDHE-RSA-CHACHA20-POLY1305,ECDHE-RSA-AES128-SHA,ECDHE-RSA-AES256-SHA,AES128-GCM-SHA256,AES256-GCM-SHA384,AES128-SHA,AES256-SHA \ + -H 'sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="99", "Google Chrome";v="99"' \ + -H 'sec-ch-ua-mobile: ?0' \ + -H 'sec-ch-ua-platform: "Windows"' \ + -H 'Upgrade-Insecure-Requests: 1' \ + -H 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36' \ + -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9' \ + -H 'Sec-Fetch-Site: none' \ + -H 'Sec-Fetch-Mode: navigate' \ + -H 'Sec-Fetch-User: ?1' \ + -H 'Sec-Fetch-Dest: document' \ + -H 'Accept-Encoding: gzip, deflate, br' \ + -H 'Accept-Language: en-US,en;q=0.9' \ + --http2 --false-start --compressed \ + --tlsv1.2 --no-npn --alps \ + --cert-compression brotli \ + "$@" diff --git a/chrome/curl_edge99 b/chrome/curl_edge99 new file mode 100755 index 0000000..0381d2b --- /dev/null +++ b/chrome/curl_edge99 @@ -0,0 +1,26 @@ +#!/bin/bash + +# Find the directory of this script +dir=`echo "$0" | sed 's%/[^/]*$%%'` + +# The list of ciphers can be obtained by looking at the Client Hello message in +# Wireshark, then converting it using this reference +# https://wiki.mozilla.org/Security/Cipher_Suites +"$dir/curl-impersonate" \ + --ciphers TLS_AES_128_GCM_SHA256,TLS_AES_256_GCM_SHA384,TLS_CHACHA20_POLY1305_SHA256,ECDHE-ECDSA-AES128-GCM-SHA256,ECDHE-RSA-AES128-GCM-SHA256,ECDHE-ECDSA-AES256-GCM-SHA384,ECDHE-RSA-AES256-GCM-SHA384,ECDHE-ECDSA-CHACHA20-POLY1305,ECDHE-RSA-CHACHA20-POLY1305,ECDHE-RSA-AES128-SHA,ECDHE-RSA-AES256-SHA,AES128-GCM-SHA256,AES256-GCM-SHA384,AES128-SHA,AES256-SHA \ + -H 'sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="99", "Microsoft Edge";v="99"' \ + -H 'sec-ch-ua-mobile: ?0' \ + -H 'sec-ch-ua-platform: "Windows"' \ + -H 'Upgrade-Insecure-Requests: 1' \ + -H 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36 Edg/99.0.1150.30' \ + -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9' \ + -H 'Sec-Fetch-Site: none' \ + -H 'Sec-Fetch-Mode: navigate' \ + -H 'Sec-Fetch-User: ?1' \ + -H 'Sec-Fetch-Dest: document' \ + -H 'Accept-Encoding: gzip, deflate, br' \ + -H 'Accept-Language: en-US,en;q=0.9' \ + --http2 --false-start --compressed \ + --tlsv1.2 --no-npn --alps \ + --cert-compression brotli \ + "$@" diff --git a/chrome/patches/curl-impersonate.patch b/chrome/patches/curl-impersonate.patch index 4ad43e8..144623b 100644 --- a/chrome/patches/curl-impersonate.patch +++ b/chrome/patches/curl-impersonate.patch @@ -85,7 +85,7 @@ index 2dbfb26b5..e0bf86169 100644 * NAME curl_easy_getinfo() * diff --git a/lib/easy.c b/lib/easy.c -index 20293a710..5f2a3e166 100644 +index 20293a710..a61a220e3 100644 --- a/lib/easy.c +++ b/lib/easy.c @@ -80,6 +80,7 @@ @@ -96,7 +96,7 @@ index 20293a710..5f2a3e166 100644 /* The last 3 #include files should be in this order */ #include "curl_printf.h" -@@ -282,6 +283,291 @@ void curl_global_cleanup(void) +@@ -282,6 +283,371 @@ void curl_global_cleanup(void) init_flags = 0; } @@ -174,6 +174,46 @@ index 20293a710..5f2a3e166 100644 + } + }, + { ++ .target = "chrome99", ++ .httpversion = CURL_HTTP_VERSION_2_0, ++ .ssl_version = CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_DEFAULT, ++ .ciphers = ++ "TLS_AES_128_GCM_SHA256," ++ "TLS_AES_256_GCM_SHA384," ++ "TLS_CHACHA20_POLY1305_SHA256," ++ "ECDHE-ECDSA-AES128-GCM-SHA256," ++ "ECDHE-RSA-AES128-GCM-SHA256," ++ "ECDHE-ECDSA-AES256-GCM-SHA384," ++ "ECDHE-RSA-AES256-GCM-SHA384," ++ "ECDHE-ECDSA-CHACHA20-POLY1305," ++ "ECDHE-RSA-CHACHA20-POLY1305," ++ "ECDHE-RSA-AES128-SHA," ++ "ECDHE-RSA-AES256-SHA," ++ "AES128-GCM-SHA256," ++ "AES256-GCM-SHA384," ++ "AES128-SHA," ++ "AES256-SHA", ++ .npn = false, ++ .alpn = true, ++ .alps = true, ++ .tls_session_ticket = true, ++ .cert_compression = "brotli", ++ .http_headers = { ++ "sec-ch-ua: \" Not A;Brand\";v=\"99\", \"Chromium\";v=\"99\", \"Google Chrome\";v=\"99\"", ++ "sec-ch-ua-mobile: ?0", ++ "sec-ch-ua-platform: \"Windows\"", ++ "Upgrade-Insecure-Requests: 1", ++ "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36", ++ "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", ++ "Sec-Fetch-Site: none", ++ "Sec-Fetch-Mode: navigate", ++ "Sec-Fetch-User: ?1", ++ "Sec-Fetch-Dest: document", ++ "Accept-Encoding: gzip, deflate, br", ++ "Accept-Language: en-US,en;q=0.9" ++ } ++ }, ++ { + .target = "edge98", + .httpversion = CURL_HTTP_VERSION_2_0, + .ssl_version = CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_DEFAULT, @@ -214,6 +254,46 @@ index 20293a710..5f2a3e166 100644 + } + }, + { ++ .target = "edge99", ++ .httpversion = CURL_HTTP_VERSION_2_0, ++ .ssl_version = CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_DEFAULT, ++ .ciphers = ++ "TLS_AES_128_GCM_SHA256," ++ "TLS_AES_256_GCM_SHA384," ++ "TLS_CHACHA20_POLY1305_SHA256," ++ "ECDHE-ECDSA-AES128-GCM-SHA256," ++ "ECDHE-RSA-AES128-GCM-SHA256," ++ "ECDHE-ECDSA-AES256-GCM-SHA384," ++ "ECDHE-RSA-AES256-GCM-SHA384," ++ "ECDHE-ECDSA-CHACHA20-POLY1305," ++ "ECDHE-RSA-CHACHA20-POLY1305," ++ "ECDHE-RSA-AES128-SHA," ++ "ECDHE-RSA-AES256-SHA," ++ "AES128-GCM-SHA256," ++ "AES256-GCM-SHA384," ++ "AES128-SHA," ++ "AES256-SHA", ++ .npn = false, ++ .alpn = true, ++ .alps = true, ++ .tls_session_ticket = true, ++ .cert_compression = "brotli", ++ .http_headers = { ++ "sec-ch-ua: \" Not A;Brand\";v=\"99\", \"Chromium\";v=\"99\", \"Microsoft Edge\";v=\"99\"", ++ "sec-ch-ua-mobile: ?0", ++ "sec-ch-ua-platform: \"Windows\"", ++ "Upgrade-Insecure-Requests: 1", ++ "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36 Edg/99.0.1150.30", ++ "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", ++ "Sec-Fetch-Site: none", ++ "Sec-Fetch-Mode: navigate", ++ "Sec-Fetch-User: ?1", ++ "Sec-Fetch-Dest: document", ++ "Accept-Encoding: gzip, deflate, br", ++ "Accept-Language: en-US,en;q=0.9" ++ } ++ }, ++ { + .target = "safari15_3", + .httpversion = CURL_HTTP_VERSION_2_0, + .ssl_version = CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_DEFAULT, @@ -388,7 +468,7 @@ index 20293a710..5f2a3e166 100644 /* * curl_easy_init() is the external interface to alloc, setup and init an * easy handle that is returned. If anything goes wrong, NULL is returned. -@@ -290,6 +576,7 @@ struct Curl_easy *curl_easy_init(void) +@@ -290,6 +656,7 @@ struct Curl_easy *curl_easy_init(void) { CURLcode result; struct Curl_easy *data; @@ -396,7 +476,7 @@ index 20293a710..5f2a3e166 100644 /* Make sure we inited the global SSL stuff */ if(!initialized) { -@@ -308,6 +595,22 @@ struct Curl_easy *curl_easy_init(void) +@@ -308,6 +675,22 @@ struct Curl_easy *curl_easy_init(void) return NULL; } @@ -419,7 +499,7 @@ index 20293a710..5f2a3e166 100644 return data; } -@@ -878,6 +1181,13 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data) +@@ -878,6 +1261,13 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data) outcurl->state.referer_alloc = TRUE; } diff --git a/tests/signatures.yaml b/tests/signatures.yaml index 1f13b04..af6a545 100644 --- a/tests/signatures.yaml +++ b/tests/signatures.yaml @@ -103,6 +103,102 @@ signature: - 'accept-encoding: gzip, deflate, br' - 'accept-language: en-US,en;q=0.9' --- +name: chrome_99.0.4844.51_win10 +browser: + name: chrome + version: 99.0.4844.51 + os: win10 + mode: regular +signature: + tls_client_hello: + record_version: 'TLS_VERSION_1_0' + handshake_version: 'TLS_VERSION_1_2' + session_id_length: 32 + ciphersuites: [ + 'GREASE', + 0x1301, 0x1302, 0x1303, 0xc02b, 0xc02f, 0xc02c, 0xc030, + 0xcca9, 0xcca8, 0xc013, 0xc014, 0x009c, 0x009d, 0x002f, + 0x0035 + ] + comp_methods: [0x00] + extensions: + - type: GREASE + length: 0 + - type: server_name + - type: extended_master_secret + length: 0 + - type: renegotiation_info + length: 1 + - type: supported_groups + length: 10 + supported_groups: [ + 'GREASE', + 0x001d, 0x0017, 0x0018 + ] + - type: ec_point_formats + length: 2 + ec_point_formats: [0] + - type: session_ticket + length: 0 + - type: application_layer_protocol_negotiation + length: 14 + alpn_list: ['h2', 'http/1.1'] + - type: status_request + length: 5 + status_request_type: 0x01 + - type: signature_algorithms + length: 18 + sig_hash_algs: [ + 0x0403, 0x0804, 0x0401, 0x0503, + 0x0805, 0x0501, 0x0806, 0x0601 + ] + - type: signed_certificate_timestamp + length: 0 + - type: keyshare + length: 43 + key_shares: + - group: GREASE + length: 1 + - group: 29 + length: 32 + - type: psk_key_exchange_modes + length: 2 + psk_ke_mode: 1 + - type: supported_versions + length: 7 + supported_versions: [ + 'GREASE', 'TLS_VERSION_1_3', 'TLS_VERSION_1_2' + ] + - type: compress_certificate + length: 3 + algorithms: [0x02] + - type: application_settings + length: 5 + alps_alpn_list: ['h2'] + - type: GREASE + length: 1 + data: !!binary AA== + - type: padding + http2: + pseudo_headers: + - ':method' + - ':authority' + - ':scheme' + - ':path' + headers: + - 'sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="99", "Google Chrome";v="99"' + - 'sec-ch-ua-mobile: ?0' + - 'sec-ch-ua-platform: "Windows"' + - 'upgrade-insecure-requests: 1' + - 'user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36' + - 'accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9' + - 'sec-fetch-site: none' + - 'sec-fetch-mode: navigate' + - 'sec-fetch-user: ?1' + - 'sec-fetch-dest: document' + - 'accept-encoding: gzip, deflate, br' + - 'accept-language: en-US,en;q=0.9' +--- name: edge_98.0.1108.62_win10 browser: name: edge @@ -199,6 +295,102 @@ signature: - 'accept-encoding: gzip, deflate, br' - 'accept-language: en-US,en;q=0.9' --- +name: edge_99.0.1150.30_win10 +browser: + name: edge + version: 99.0.1150.30 + os: win10 + mode: regular +signature: + tls_client_hello: + record_version: 'TLS_VERSION_1_0' + handshake_version: 'TLS_VERSION_1_2' + session_id_length: 32 + ciphersuites: [ + 'GREASE', + 0x1301, 0x1302, 0x1303, 0xc02b, 0xc02f, 0xc02c, 0xc030, + 0xcca9, 0xcca8, 0xc013, 0xc014, 0x009c, 0x009d, 0x002f, + 0x0035 + ] + comp_methods: [0x00] + extensions: + - type: GREASE + length: 0 + - type: server_name + - type: extended_master_secret + length: 0 + - type: renegotiation_info + length: 1 + - type: supported_groups + length: 10 + supported_groups: [ + 'GREASE', + 0x001d, 0x0017, 0x0018 + ] + - type: ec_point_formats + length: 2 + ec_point_formats: [0] + - type: session_ticket + length: 0 + - type: application_layer_protocol_negotiation + length: 14 + alpn_list: ['h2', 'http/1.1'] + - type: status_request + length: 5 + status_request_type: 0x01 + - type: signature_algorithms + length: 18 + sig_hash_algs: [ + 0x0403, 0x0804, 0x0401, 0x0503, + 0x0805, 0x0501, 0x0806, 0x0601 + ] + - type: signed_certificate_timestamp + length: 0 + - type: keyshare + length: 43 + key_shares: + - group: GREASE + length: 1 + - group: 29 + length: 32 + - type: psk_key_exchange_modes + length: 2 + psk_ke_mode: 1 + - type: supported_versions + length: 7 + supported_versions: [ + 'GREASE', 'TLS_VERSION_1_3', 'TLS_VERSION_1_2' + ] + - type: compress_certificate + length: 3 + algorithms: [0x02] + - type: application_settings + length: 5 + alps_alpn_list: ['h2'] + - type: GREASE + length: 1 + data: !!binary AA== + - type: padding + http2: + pseudo_headers: + - ':method' + - ':authority' + - ':scheme' + - ':path' + headers: + - 'sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="99", "Microsoft Edge";v="99"' + - 'sec-ch-ua-mobile: ?0' + - 'sec-ch-ua-platform: "Windows"' + - 'upgrade-insecure-requests: 1' + - 'user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36 Edg/99.0.1150.30' + - 'accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9' + - 'sec-fetch-site: none' + - 'sec-fetch-mode: navigate' + - 'sec-fetch-user: ?1' + - 'sec-fetch-dest: document' + - 'accept-encoding: gzip, deflate, br' + - 'accept-language: en-US,en;q=0.9' +--- name: firefox_91.6.0esr_win10 browser: name: firefox diff --git a/tests/test_impersonate.py b/tests/test_impersonate.py index 323f8b8..84d19ed 100644 --- a/tests/test_impersonate.py +++ b/tests/test_impersonate.py @@ -127,7 +127,9 @@ class TestImpersonation: CURL_BINARIES_AND_SIGNATURES = [ # Test wrapper scripts ("chrome/curl_chrome98", None, "chrome_98.0.4758.102_win10"), + ("chrome/curl_chrome99", None, "chrome_99.0.4844.51_win10"), ("chrome/curl_edge98", None, "edge_98.0.1108.62_win10"), + ("chrome/curl_edge99", None, "edge_99.0.1150.30_win10"), ("chrome/curl_safari15_3", None, "safari_15.3_macos11.6.4"), ("firefox/curl_ff91esr", None, "firefox_91.6.0esr_win10"), ("firefox/curl_ff95", None, "firefox_95.0.2_win10"), @@ -143,6 +145,14 @@ class TestImpersonation: }, "chrome_98.0.4758.102_win10" ), + ( + "./minicurl", + { + "LD_PRELOAD": "./chrome/libcurl-impersonate.so", + "CURL_IMPERSONATE": "chrome99" + }, + "chrome_99.0.4844.51_win10" + ), ( "./minicurl", { @@ -151,6 +161,14 @@ class TestImpersonation: }, "edge_98.0.1108.62_win10" ), + ( + "./minicurl", + { + "LD_PRELOAD": "./chrome/libcurl-impersonate.so", + "CURL_IMPERSONATE": "edge99" + }, + "edge_99.0.1150.30_win10" + ), ( "./minicurl", {