Skip to content

Commit

Permalink
Impersonate Firefox 98
Browse files Browse the repository at this point in the history
Add support for impersonating Firefox 98 released a few days ago. It has
the same TLS signature as Firefox 95 so the adaptation includes changing
the user-agent only. Upgrade the NSS version used to 3.75, even though
it's not strictly necessary.
  • Loading branch information
lwthiker committed Mar 12, 2022
1 parent 0952bca commit 768e37d
Show file tree
Hide file tree
Showing 8 changed files with 168 additions and 13 deletions.
4 changes: 2 additions & 2 deletions Dockerfile.template
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,9 @@ RUN cd brotli-${BROTLI_VERSION} && \
# Needed for building libnss
RUN pip install gyp-next

ARG NSS_VERSION=nss-3.74
ARG NSS_VERSION=nss-3.75
# This tarball is already bundled with nspr, a dependency of libnss.
ARG NSS_URL=https://ftp.mozilla.org/pub/security/nss/releases/NSS_3_74_RTM/src/nss-3.74-with-nspr-4.32.tar.gz
ARG NSS_URL=https://ftp.mozilla.org/pub/security/nss/releases/NSS_3_75_RTM/src/nss-3.75-with-nspr-4.32.tar.gz

# Download and compile nss.
RUN curl -o ${NSS_VERSION}.tar.gz ${NSS_URL}
Expand Down
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ The following browsers can be impersonated.
| ![Edge](https://raw.githubusercontent.com/alrra/browser-logos/main/src/edge/edge_24x24.png "Edge") | 99 | 99.0.1150.30 | Windows 10 | `edge99` | [curl_edge99](chrome/curl_edge99) |
| ![Firefox](https://raw.githubusercontent.com/alrra/browser-logos/main/src/firefox/firefox_24x24.png "Firefox") | 91 ESR | 91.6.0esr | Windows 10 | `ff91esr` | [curl_ff91esr](firefox/curl_ff91esr) |
| ![Firefox](https://raw.githubusercontent.com/alrra/browser-logos/main/src/firefox/firefox_24x24.png "Firefox") | 95 | 95.0.2 | Windows 10 | `ff95` | [curl_ff95](firefox/curl_ff95) |
| ![Firefox](https://raw.githubusercontent.com/alrra/browser-logos/main/src/firefox/firefox_24x24.png "Firefox") | 98 | 98.0 | Windows 10 | `ff98` | [curl_ff98](firefox/curl_ff98) |
| ![Safari](https://github.com/alrra/browser-logos/blob/main/src/safari/safari_24x24.png "Safari") | 15.3 | 16612.4.9.1.8 | MacOS Big Sur | `safari15_3` | [curl_safari15_3](chrome/curl_safari15_3) |

## Basic usage
Expand Down Expand Up @@ -85,7 +86,7 @@ docker build -t curl-impersonate-ff firefox/
```
The resulting image contains:
* `/build/out/curl-impersonate` - The curl binary that can impersonate Firefox. It is compiled statically against libcurl, nss, and libnghttp2 so that it won't conflict with any existing libraries on your system. You can use it from the container or copy it out. Tested to work on Ubuntu 20.04.
* `/build/out/curl_ff91esr`, `/build/out/curl_ff95` - Wrapper scripts that launch `curl-impersonate` with all the needed flags.
* `/build/out/curl_ff91esr`, `/build/out/curl_ff95`, `...` - Wrapper scripts that launch `curl-impersonate` with all the needed flags.
* `/build/out/libcurl-impersonate.so` - libcurl compiled with impersonation support. See [libcurl-impersonate](#libcurl-impersonate) below for more details.

If you use it outside the container, install the following dependency:
Expand Down Expand Up @@ -123,7 +124,7 @@ This repository contains two main folders:

The layout is similar for both. For example, the Firefox directory contains:
* [Dockerfile](firefox/Dockerfile) - Used to build `curl-impersonate` with all dependencies.
* [curl_ff91esr](firefox/curl_ff91esr), [curl_ff95](curl_ff95) - Wrapper scripts that launch `curl-impersonate` with the correct flags.
* [curl_ff91esr](firefox/curl_ff91esr), [curl_ff95](firefox/curl_ff95), [curl_ff98](firefox/curl_ff98) - Wrapper scripts that launch `curl-impersonate` with the correct flags.
* [curl-impersonate.patch](firefox/patches/curl-impersonate.patch) - The main patch that makes curl use the same TLS extensions as Firefox. Also makes curl compile statically with libnghttp2 and libnss.
* [libnghttp2-pc.patch](firefox/patches/libnghttp2-pc.patch) - Patch to make libnghttp2 compile statically.

Expand Down
4 changes: 2 additions & 2 deletions firefox/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ RUN cd brotli-${BROTLI_VERSION} && \
# Needed for building libnss
RUN pip install gyp-next

ARG NSS_VERSION=nss-3.74
ARG NSS_VERSION=nss-3.75
# This tarball is already bundled with nspr, a dependency of libnss.
ARG NSS_URL=https://ftp.mozilla.org/pub/security/nss/releases/NSS_3_74_RTM/src/nss-3.74-with-nspr-4.32.tar.gz
ARG NSS_URL=https://ftp.mozilla.org/pub/security/nss/releases/NSS_3_75_RTM/src/nss-3.75-with-nspr-4.32.tar.gz

# Download and compile nss.
RUN curl -o ${NSS_VERSION}.tar.gz ${NSS_URL}
Expand Down
4 changes: 2 additions & 2 deletions firefox/Dockerfile.alpine
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ RUN cd brotli-${BROTLI_VERSION} && \
# Needed for building libnss
RUN pip install gyp-next

ARG NSS_VERSION=nss-3.74
ARG NSS_VERSION=nss-3.75
# This tarball is already bundled with nspr, a dependency of libnss.
ARG NSS_URL=https://ftp.mozilla.org/pub/security/nss/releases/NSS_3_74_RTM/src/nss-3.74-with-nspr-4.32.tar.gz
ARG NSS_URL=https://ftp.mozilla.org/pub/security/nss/releases/NSS_3_75_RTM/src/nss-3.75-with-nspr-4.32.tar.gz

# Download and compile nss.
RUN curl -o ${NSS_VERSION}.tar.gz ${NSS_URL}
Expand Down
22 changes: 22 additions & 0 deletions firefox/curl_ff98
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/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 the cipherlist array at
# https://github.com/curl/curl/blob/master/lib/vtls/nss.c
"$dir/curl-impersonate" \
--ciphers aes_128_gcm_sha_256,chacha20_poly1305_sha_256,aes_256_gcm_sha_384,ecdhe_ecdsa_aes_128_gcm_sha_256,ecdhe_rsa_aes_128_gcm_sha_256,ecdhe_ecdsa_chacha20_poly1305_sha_256,ecdhe_rsa_chacha20_poly1305_sha_256,ecdhe_ecdsa_aes_256_gcm_sha_384,ecdhe_rsa_aes_256_gcm_sha_384,ecdhe_ecdsa_aes_256_sha,ecdhe_ecdsa_aes_128_sha,ecdhe_rsa_aes_128_sha,ecdhe_rsa_aes_256_sha,rsa_aes_128_gcm_sha_256,rsa_aes_256_gcm_sha_384,rsa_aes_128_sha,rsa_aes_256_sha \
-H 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:98.0) Gecko/20100101 Firefox/98.0' \
-H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8' \
-H 'Accept-Language: en-US,en;q=0.5' \
-H 'Accept-Encoding: gzip, deflate, br' \
-H 'Upgrade-Insecure-Requests: 1' \
-H 'Sec-Fetch-Dest: document' \
-H 'Sec-Fetch-Mode: navigate' \
-H 'Sec-Fetch-Site: none' \
-H 'Sec-Fetch-User: ?1' \
-H 'TE: Trailers' \
--http2 --false-start --compressed \
"$@"
45 changes: 40 additions & 5 deletions firefox/patches/curl-impersonate.patch
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ index 2dbfb26b5..e0bf86169 100644
* NAME curl_easy_getinfo()
*
diff --git a/lib/easy.c b/lib/easy.c
index 20293a710..1a4d52d2f 100644
index 20293a710..b97ac204e 100644
--- a/lib/easy.c
+++ b/lib/easy.c
@@ -80,6 +80,7 @@
Expand All @@ -91,7 +91,7 @@ index 20293a710..1a4d52d2f 100644

/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -282,6 +283,162 @@ void curl_global_cleanup(void)
@@ -282,6 +283,197 @@ void curl_global_cleanup(void)
init_flags = 0;
}

Expand Down Expand Up @@ -180,6 +180,41 @@ index 20293a710..1a4d52d2f 100644
+ "Sec-Fetch-User: ?1",
+ "TE: Trailers"
+ }
+ },
+ {
+ .target = "ff98",
+ .httpversion = CURL_HTTP_VERSION_2_0,
+ .ssl_version = CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_DEFAULT,
+ .ciphers =
+ "aes_128_gcm_sha_256,"
+ "chacha20_poly1305_sha_256,"
+ "aes_256_gcm_sha_384,"
+ "ecdhe_ecdsa_aes_128_gcm_sha_256,"
+ "ecdhe_rsa_aes_128_gcm_sha_256,"
+ "ecdhe_ecdsa_chacha20_poly1305_sha_256,"
+ "ecdhe_rsa_chacha20_poly1305_sha_256,"
+ "ecdhe_ecdsa_aes_256_gcm_sha_384,"
+ "ecdhe_rsa_aes_256_gcm_sha_384,"
+ "ecdhe_ecdsa_aes_256_sha,"
+ "ecdhe_ecdsa_aes_128_sha,"
+ "ecdhe_rsa_aes_128_sha,"
+ "ecdhe_rsa_aes_256_sha,"
+ "rsa_aes_128_gcm_sha_256,"
+ "rsa_aes_256_gcm_sha_384,"
+ "rsa_aes_128_sha,"
+ "rsa_aes_256_sha",
+ .http_headers = {
+ "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:98.0) Gecko/20100101 Firefox/98.0",
+ "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
+ "Accept-Language: en-US,en;q=0.5",
+ "Accept-Encoding: gzip, deflate, br",
+ "Upgrade-Insecure-Requests: 1",
+ "Sec-Fetch-Dest: document",
+ "Sec-Fetch-Mode: navigate",
+ "Sec-Fetch-Site: none",
+ "Sec-Fetch-User: ?1",
+ "TE: Trailers"
+ }
+ }
+};
+
Expand Down Expand Up @@ -254,15 +289,15 @@ index 20293a710..1a4d52d2f 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 +447,7 @@ struct Curl_easy *curl_easy_init(void)
@@ -290,6 +482,7 @@ struct Curl_easy *curl_easy_init(void)
{
CURLcode result;
struct Curl_easy *data;
+ char *target;

/* Make sure we inited the global SSL stuff */
if(!initialized) {
@@ -308,6 +466,22 @@ struct Curl_easy *curl_easy_init(void)
@@ -308,6 +501,22 @@ struct Curl_easy *curl_easy_init(void)
return NULL;
}

Expand All @@ -285,7 +320,7 @@ index 20293a710..1a4d52d2f 100644
return data;
}

@@ -878,6 +1052,13 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data)
@@ -878,6 +1087,13 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data)
outcurl->state.referer_alloc = TRUE;
}

Expand Down
88 changes: 88 additions & 0 deletions tests/signatures.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,94 @@ signature:
- 'sec-fetch-user: ?1'
- 'te: trailers'
---
name: firefox_98.0_win10
browser:
name: firefox
version: 98.0
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: [
0x1301, 0x1303, 0x1302, 0xc02b, 0xc02f, 0xcca9, 0xcca8, 0xc02c,
0xc030, 0xc00a, 0xc009, 0xc013, 0xc014, 0x009c, 0x009d, 0x002f,
0x0035
]
comp_methods: [0x00]
extensions:
- type: server_name
- type: extended_master_secret
length: 0
- type: renegotiation_info
length: 1
- type: supported_groups
length: 14
supported_groups: [
0x1d, 0x017, 0x18, 0x19, 0x0100, 0x0101
]
- 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: delegated_credentials
length: 10
sig_hash_algs: [
0x0403, 0x0503, 0x0603, 0x0203
]
- type: keyshare
length: 107
key_shares:
- group: 29
length: 32
- group: 23
length: 65
- type: supported_versions
length: 5
supported_versions: [
'TLS_VERSION_1_3', 'TLS_VERSION_1_2'
]
- type: signature_algorithms
length: 24
sig_hash_algs: [
0x0403, 0x0503, 0x0603, 0x0804,
0x0805, 0x0806, 0x0401, 0x0501,
0x0601, 0x0203, 0x0201
]
- type: psk_key_exchange_modes
length: 2
psk_ke_mode: 1
- type: record_size_limit
length: 2
record_size_limit: 16385
- type: padding
http2:
pseudo_headers:
- ':method'
- ':path'
- ':authority'
- ':scheme'
headers:
- 'user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:98.0) Gecko/20100101 Firefox/98.0'
- 'accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8'
- 'accept-language: en-US,en;q=0.5'
- 'accept-encoding: gzip, deflate, br'
- 'upgrade-insecure-requests: 1'
- 'sec-fetch-dest: document'
- 'sec-fetch-mode: navigate'
- 'sec-fetch-site: none'
- 'sec-fetch-user: ?1'
- 'te: trailers'
---
name: safari_15.3_macos11.6.4
browser:
name: safari
Expand Down
9 changes: 9 additions & 0 deletions tests/test_impersonate.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ class TestImpersonation:
("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"),
("firefox/curl_ff98", None, "firefox_98.0_win10"),

# Test libcurl-impersonate by loading it with LD_PRELOAD to an app
# linked against the regular libcurl and setting the
Expand Down Expand Up @@ -192,6 +193,14 @@ class TestImpersonation:
"CURL_IMPERSONATE": "ff95"
},
"firefox_95.0.2_win10"
),
(
"./minicurl",
{
"LD_PRELOAD": "./firefox/libcurl-impersonate.so",
"CURL_IMPERSONATE": "ff98"
},
"firefox_98.0_win10"
)
]

Expand Down

0 comments on commit 768e37d

Please sign in to comment.