curl-impersonate : un build spécial de curl capable d’usurper l’identité des principaux navigateurs
(github.com/lwthiker)- curl-impersonate est un build modifié de curl conçu pour effectuer des handshakes TLS et HTTP qui ressemblent à ceux de Chrome, Edge, Safari et Firefox, et peut être utilisé comme outil en ligne de commande ou comme bibliothèque de remplacement de
libcurl - Les Client Hello et paramètres HTTP/2 des clients et bibliothèques HTTP classiques diffèrent fortement de ceux des vrais navigateurs, si bien que certains services web identifient les clients via le handshake TLS/HTTP et servent un contenu différent
- L’implémentation repose sur NSS pour Firefox et BoringSSL pour les navigateurs de type Chrome, avec des modifications des extensions TLS, des options SSL, des paramètres HTTP/2, ainsi que l’usage de drapeaux non par défaut comme
--ciphers,--curveset certains en-têtes - Les cibles prises en charge sont Chrome 99 à 116, Chrome 99 sur Android, Edge 99 et 101, Firefox 91 ESR à 117, Safari 15.3 et 15.5, avec pour chacune un wrapper script et un nom de cible
- En ligne de commande, on exécute
curl_chrome116, et pour l’intégration en bibliothèque, on peut utilisercurl_easy_impersonate()ou, sous Linux,LD_PRELOADetCURL_IMPERSONATEpour l’appliquer à des applications existantes utilisantlibcurl
Le problème que résout curl-impersonate
- curl-impersonate est un projet qui propose un build spécial de curl capable d’imiter les quatre grands navigateurs : Chrome, Edge, Safari et Firefox
- Il peut effectuer les handshakes TLS et HTTP à l’identique de ceux des vrais navigateurs
- Il s’utilise de deux façons
- comme outil en ligne de commande comparable à curl classique
- comme bibliothèque pouvant être intégrée à la place de
libcurl
Pourquoi c’est nécessaire
- Lorsqu’un client HTTP se connecte à un site TLS, il commence par effectuer un handshake TLS
- Le premier message du handshake TLS est le Client Hello, et celui produit par la plupart des clients et bibliothèques HTTP diffère fortement de celui des vrais navigateurs
- Si le serveur utilise HTTP/2, un handshake HTTP/2 a aussi lieu en plus du handshake TLS, avec échange de plusieurs paramètres
- Les paramètres HTTP/2 de la plupart des clients et bibliothèques HTTP diffèrent eux aussi de ceux des vrais navigateurs
- Certains services web exploitent ces différences pour identifier le client qui se connecte et fournir un contenu différent selon le client
- Cette méthode est appelée TLS fingerprinting et HTTP/2 fingerprinting
- Le README indique que l’usage généralisé de ces techniques a rendu le web moins ouvert, moins respectueux de la vie privée et plus restrictif envers certains clients web
Fonctionnement
curlest fortement patché pour ressembler à un navigateur- Principales modifications
- La version Firefox compile curl avec NSS, la bibliothèque TLS utilisée par Firefox, au lieu d’OpenSSL
- La version Chrome est compilée avec BoringSSL, la bibliothèque TLS de Google
- La manière dont curl configure plusieurs extensions TLS et options SSL est modifiée
- La prise en charge de nouvelles extensions TLS est ajoutée
- Les paramètres utilisés pour les connexions HTTP/2 sont modifiés
- curl est exécuté avec des drapeaux non par défaut comme
--ciphers,--curveset certains en-têtes-H
- Résultat : du point de vue réseau, curl apparaît exactement comme un vrai navigateur
- La description technique complète se trouve dans part a et part b
Navigateurs pris en charge et noms de cible
- La liste des navigateurs pris en charge est également disponible dans
browsers.json - Cibles prises en charge de type Chrome
- Chrome 99, 100, 101, 104, 107, 110, 116 sur Windows 10
- Chrome 99 sur Android 12
- Edge 99, 101 sur Windows 10
- Safari 15.3 sur MacOS Big Sur
- Safari 15.5 sur MacOS Monterey
- Cibles prises en charge pour Firefox
- Firefox 91 ESR, 95, 98, 100, 102, 109, 117 sur Windows 10
- Chaque cible prise en charge dispose d’un nom de cible et d’un wrapper script
- Exemple : la cible
chrome116s’exécute via le wrapper scriptcurl_chrome116 - Exemple : la cible
ff117s’exécute via le wrapper scriptcurl_ff117
- Exemple : la cible
Utilisation de base
- Pour chaque navigateur pris en charge, un wrapper script permet d’exécuter
curl-impersonateavec les en-têtes et drapeaux nécessaires - Exemple d’exécution
curl_chrome116 https://www.wikipedia.org - Les drapeaux supplémentaires en ligne de commande sont transmis à curl
- Certains drapeaux peuvent modifier la signature TLS de curl et le rendre détectable
- Le wrapper script utilise un jeu d’en-têtes HTTP par défaut
- Pour modifier les en-têtes, il est possible d’adapter le wrapper script selon l’usage visé
- D’autres options sont disponibles dans l’utilisation avancée de
libcurl-impersonatecomme bibliothèque
Installation et mode de distribution
- Pour des raisons techniques,
curl-impersonateexiste en deux versions- version chrome : utilisée pour imiter Chrome, Edge et Safari
- version firefox : utilisée pour imiter Firefox
- Des binaires précompilés pour Linux et macOS Intel sont disponibles sur GitHub releases
- Avant d’utiliser les binaires précompilés, il faut installer NSS et les certificats CA
- Ubuntu :
sudo apt install libnss3 nss-plugin-pem ca-certificates - Red Hat/Fedora/CentOS :
yum install nss nss-pem ca-certificates - Archlinux :
pacman -S nss ca-certificates - macOS :
brew install nss ca-certificates
- Ubuntu :
- Le système a aussi besoin de zlib
- zlib est presque toujours présent, mais peut manquer sur certains systèmes minimaux
- Les binaires Linux précompilés sont construits pour Ubuntu
- Sur d’autres distributions, en cas d’erreur de validation des certificats, il peut être nécessaire d’indiquer à curl l’emplacement des certificats CA
curl_chrome116 https://www.wikipedia.org --cacert /etc/ssl/certs/ca-bundle.crt - Pour compiler depuis les sources, voir INSTALL.md
Docker et paquets
- Des images Docker basées sur Alpine Linux et Debian sont proposées sur Docker Hub
- Les images Docker incluent les binaires et tous les wrapper scripts
- Exemples
# Version Firefox, Alpine Linux docker pull lwthiker/curl-impersonate:0.6-ff docker run --rm lwthiker/curl-impersonate:0.6-ff curl_ff109 https://www.wikipedia.org # Version Chrome, Alpine Linux docker pull lwthiker/curl-impersonate:0.6-chrome docker run --rm lwthiker/curl-impersonate:0.6-chrome curl_chrome110 https://www.wikipedia.org - Les utilisateurs d’Archlinux peuvent utiliser des paquets AUR
- Paquets précompilés : curl-impersonate-bin, libcurl-impersonate-bin
- Paquets à compiler depuis les sources : curl-impersonate-chrome, curl-impersonate-firefox
- Une formule Homebrew non officielle pour Mac est disponible uniquement pour Chrome
brew tap shakacode/brew brew install curl-impersonate
Utilisation avancée de libcurl-impersonate
libcurl-impersonate.soest une version de libcurl compilée avec les mêmes modifications quecurl-impersonateen ligne de commande- Une fonction API supplémentaire est fournie
CURLcode curl_easy_impersonate(struct Curl_easy *data, const char * target, int default_headers); - En l’appelant avec un nom de cible comme
chrome116, les options et en-têtes normalement définis par le wrapper script sont configurés en interne - Si
default_headersvaut 0, la liste intégrée des en-têtes HTTP n’est pas configurée- L’utilisateur doit alors fournir lui-même les en-têtes via l’option
CURLOPT_HTTPHEADERstandard de libcurl
- L’utilisateur doit alors fournir lui-même les en-têtes via l’option
curl_easy_impersonate()configure plusieurs options libcurlCURLOPT_HTTP_VERSIONCURLOPT_SSLVERSION,CURLOPT_SSL_CIPHER_LIST,CURLOPT_SSL_EC_CURVES,CURLOPT_SSL_ENABLE_NPN,CURLOPT_SSL_ENABLE_ALPNCURLOPT_HTTPBASEHEADER, une option non standard propre au projetCURLOPT_HTTP2_PSEUDO_HEADERS_ORDER,CURLOPT_HTTP2_NO_SERVER_PUSH, des options HTTP/2 non standard propres au projetCURLOPT_SSL_ENABLE_ALPS,CURLOPT_SSL_SIG_HASH_ALGS,CURLOPT_SSL_CERT_COMPRESSION,CURLOPT_SSL_ENABLE_TICKET, des options TLS non standard propres au projetCURLOPT_SSL_PERMUTE_EXTENSIONS, une option TLS non standard propre au projet
- Si l’on appelle ensuite
curl_easy_setopt()sur l’une de ces options, la valeur définie parcurl_easy_impersonate()est écrasée
Application à des apps libcurl existantes
- Si l’application utilise déjà
libcurl, il est possible sous Linux de remplacer la bibliothèque existante à l’exécution viaLD_PRELOAD - Le comportement d’usurpation peut être appliqué automatiquement en définissant la variable d’environnement
CURL_IMPERSONATELD_PRELOAD=/path/to/libcurl-impersonate.so CURL_IMPERSONATE=chrome116 my_app CURL_IMPERSONATEa deux effetscurl_easy_impersonate()est appelée automatiquement à chaque création d’un nouveau handle curl viacurl_easy_init()curl_easy_impersonate()est aussi appelée automatiquement aprèscurl_easy_reset()
- Pour un contrôle fin des en-têtes HTTP, on peut désactiver la liste d’en-têtes intégrée avec
CURL_IMPERSONATE_HEADERS=noet les définir soi-mêmeLD_PRELOAD=/path/to/libcurl-impersonate.so CURL_IMPERSONATE=chrome116 CURL_IMPERSONATE_HEADERS=no my_app - La méthode
LD_PRELOADne fonctionne pas avec curl lui-même- parce que l’outil curl écrase les paramètres TLS
- pour curl, il faut utiliser les wrapper scripts
Structure du dépôt et contribution
- Le dépôt contient deux dossiers principaux
- Exemples de fichiers dans le répertoire Firefox
- Dockerfile : utilisé pour construire
curl-impersonateavec toutes les dépendances - curl_ff91esr, curl_ff95, curl_ff98 : wrapper scripts lançant l’outil avec les bons drapeaux
- curl-impersonate.patch : patch principal qui fait utiliser à curl les mêmes extensions TLS que Firefox, avec compilation statique contre libnghttp2 et libnss
- Dockerfile : utilisé pour construire
- tests/signatures est une base de données YAML des signatures de navigateurs connus pouvant être imitées
- Les patchs réels de curl sont maintenus dans un dépôt séparé forké depuis curl upstream
- Les modifications Firefox se trouvent dans la branche impersonate-firefox
- Les modifications Chrome se trouvent dans la branche impersonate-chrome
1 commentaires
Avis sur Hacker News
Il existe un fork activement maintenu avec pas mal d’améliorations par rapport à l’original : https://github.com/lexiforest/curl-impersonate
Il y a aussi des bindings pour les utilisateurs de Python : https://github.com/lexiforest/curl_cffi
Paradoxalement, cette requête serait moins coûteuse pour le serveur qu’un navigateur certifié ; on se demande si c’est ce genre de dystopie dont on nous avertissait dans les années 90. Je me demande qui ici saurait nommer l’entreprise qui a créé cette situation tout en se présentant comme un bon contributeur de la communauté open source/hacker
J’espère que Ladybird prendra de l’ampleur à l’avenir. Pour l’instant, il utilise le cURL officiel pour le réseau, et cette approche pourrait poser des difficultés
Par exemple, à ma connaissance, cURL a encore plusieurs limitations et ne sait pas gérer WebSocket au-dessus de h2. En revanche, si un moteur de navigateur en croissance apparaît, le trafic normal pourrait lui aussi avoir la même empreinte que cURL de base, ce qui pourrait faire disparaître cette voie de fingerprinting
C’est aussi un bon banc d’essai pour voir quelles fonctionnalités manquent à cURL au regard des workflows réels d’un navigateur
Ces derniers mois, le niveau de fingerprinting et d’« exploitation » des comportements définis par l’implémentation a énormément augmenté, probablement dans une tentative de tuer les autres moteurs de navigateur. Les acteurs établis n’aiment pas du tout la concurrence
Le camp d’en face essaie de présenter cela comme un « DDoS de bots IA », mais je me demande dans quelle mesure ils ne sont pas eux-mêmes à l’origine du problème
J’aime bien ce curl, mais je crains que, lorsqu’un composant est chargé de servir de trompe-l’œil pour « suivre le rythme », cela n’accumule une dette de « compatibilité » difficile à maintenir
Idéalement, on devrait simplement pouvoir dire : « bonjour, je suis curl, laisse-moi entrer »
Bien sûr, le problème vient des serveurs trop pointilleux sur le code vestimentaire, et ce problème existe aussi à cause des fraudeurs qui entrent déguisés ; c’est donc une boucle de type poule et œuf
[0] https://cybershow.uk/episodes.php?id=39
Et le fait qu’il ait été reconçu en C++, dont l’insécurité est démontrable, représente aussi un gros risque de sécurité
Est-ce qu’ils ont aussi défini
IP_TTLpour faire correspondre la valeur TTL à la plateforme qu’ils essaient d’usurper ?Sinon, il est possible de faire un certain fingerprinting même au niveau IP. Si la valeur TTL au niveau IP est inférieure à 64, il est clair que cela ne tourne pas sur un Windows moderne, ou alors sur un Windows moderne dont le TTL par défaut a été modifié. En effet, le TTL par défaut des paquets sur Windows moderne commence à 128, tandis que la plupart des autres plateformes commencent à 64
Comme les autres plateformes n’ont pas de problème pour communiquer sur Internet, les paquets IP provenant d’un Windows moderne apparaîtront toujours, côté distant, avec un TTL d’au moins 64, et probablement légèrement supérieur à 64. Cela dit, le fingerprinting au niveau IP est difficile, mais pas impossible
https://en.wikipedia.org/wiki/TCP/IP_stack_fingerprinting
Attendez, si le handshake TLS a une apparence différente, ne pourrait-on pas filtrer au niveau de nginx le trafic qui prétend être un navigateur web mais qui est en réalité un script Python/PHP ?
Par exemple, le cas où il utilise un user-agent Chrome sans être un vrai navigateur. Comme la majorité du trafic de bots malveillants correspond probablement à ça, ce serait bien de pouvoir simplement le bloquer
Le fonctionnement est détaillé ici : https://github.com/FoxIO-LLC/ja4/blob/main/technical_details..., et un module Nginx est également fourni : https://github.com/FoxIO-LLC/ja4-nginx-module
Si vous n’êtes pas réellement en train de subir une attaque, il ne faut pas utiliser de liste d’autorisation d’empreintes TLS
C’est un excellent outil, mais le fait qu’un client soit un navigateur ou non ne devrait pas avoir d’importance. C’est amer de constater qu’un tel outil est nécessaire dans la réalité
J’ai ajouté une extension de changement d’agent utilisateur à Chrome, je l’ai réglée sur IE et j’ai réessayé : ça a fonctionné, et toutes les fonctionnalités du site marchaient parfaitement. C’était donc à la fois amer et agaçant. L’agence gouvernementale en question a sans doute créé son site il y a 25 ans et ne l’a jamais mis à jour depuis
Ce genre de gatekeeping me laisse aussi un goût amer. D’après ce que j’ai compris, les navigateurs personnalisés faits maison ou les agents utilisateur personnalisés ne fonctionneront jamais sur les sites du type Cloudflare tant qu’ils n’auront pas assez d’influence, d’argent, d’utilisateurs, etc. pour les convaincre
Cet outil est assez efficace pour des opérations de red team lorsqu’on le combine avec de petits scripts bash et GNU parallel
Il m’a été utile pour cartographier, dans des plages d’adresses définies, des endpoints HTTPS qui ne répondent correctement qu’à de vrais navigateurs, ou seulement si la configuration SNI est correcte. Les options curl classiques comme
-Hpour maquiller les en-têtes restent utilisables telles quellesLe post Show HN de l’époque : https://news.ycombinator.com/item?id=30378562
Chaque fois que ce genre de chose apparaît ici, j’ai toujours des sentiments ambivalents. D’un côté, il est bon de voir qu’il reste encore un peu d’esprit de rébellion et d’indépendance chez les gens
De l’autre, comme pour d’autres projets où la « liberté » est traitée comme de l’instabilité, attirer une attention non désirée pourrait empirer la situation pour les personnes qui en dépendent. Écrire un navigateur est difficile, et les acteurs établis continuent de rendre la tâche encore plus difficile
Je ne vois pas ça comme une question d’esprit de rébellion. Le fait qu’un logiciel puisse être identifié par empreinte nuit à la protection de la vie privée et à la diversité logicielle
Les temps plus simples où les sites web autorisaient les bots s’ils les acceptaient, et bloquaient l’agent utilisateur s’ils ne les aimaient pas, me manquent un peu
S’il ne s’agit que de 3 patchs et d’un wrapper shell, Daniel pourrait bien se mettre à coder. Personnellement, je pense que cela devrait absolument entrer dans le curl mainline