curl-impersonate: una compilación especial de curl que puede imitar a los principales navegadores
(github.com/lwthiker)- curl-impersonate es una compilación modificada de curl para realizar handshakes TLS y HTTP que parecen hechos por Chrome, Edge, Safari y Firefox, y puede usarse como herramienta CLI o como biblioteca de reemplazo de
libcurl - El Client Hello y la configuración de HTTP/2 de los clientes y bibliotecas HTTP comunes difieren mucho de los navegadores reales, por lo que algunos servicios web identifican al cliente por el handshake TLS/HTTP y entregan contenido diferente
- La implementación usa NSS para Firefox y BoringSSL para la familia Chrome, con cambios en extensiones TLS, opciones SSL y configuración HTTP/2, además de aplicar flags no predeterminados como
--ciphers,--curvesy headers - Los objetivos compatibles incluyen Chrome 99~116, Chrome 99 para Android, Edge 99 y 101, Firefox 91 ESR~117, y Safari 15.3 y 15.5, y cada objetivo tiene su propio wrapper script y nombre de target
- En la línea de comandos se ejecuta como
curl_chrome116, y para integración por biblioteca puede usarsecurl_easy_impersonate()o aplicarse a apps existentes que usanlibcurlmedianteLD_PRELOADyCURL_IMPERSONATEen Linux
El problema que resuelve curl-impersonate
- curl-impersonate es un proyecto que compila curl de forma especial para que pueda imitar a los cuatro navegadores principales: Chrome, Edge, Safari y Firefox
- Puede realizar handshakes TLS y HTTP idénticos a los de los navegadores reales
- Tiene dos formas de uso
- Una herramienta de línea de comandos parecida a curl normal
- Una biblioteca que puede integrarse en lugar de
libcurl
Por qué hace falta
- Cuando un cliente HTTP se conecta a un sitio web con TLS, primero realiza un handshake TLS
- El primer mensaje del handshake TLS es Client Hello, y el Client Hello que generan la mayoría de clientes y bibliotecas HTTP difiere mucho del de los navegadores reales
- Si el servidor usa HTTP/2, además del handshake TLS también se realiza un handshake HTTP/2, donde se intercambian varias configuraciones
- La configuración de HTTP/2 de la mayoría de clientes y bibliotecas HTTP también difiere de la de los navegadores reales
- Algunos servicios web aprovechan estas diferencias para identificar al cliente que se conecta y servir contenido distinto según el cliente
- Este método se conoce como TLS fingerprinting y HTTP/2 fingerprinting
- El README señala que el uso extendido de estas técnicas ha hecho que la web sea menos abierta, menos privada y más restrictiva para ciertos clientes web
Cómo funciona
curlestá bastante parcheado para que se vea como un navegador- Los principales cambios son los siguientes
- La versión de Firefox compila curl con NSS, la biblioteca TLS que usa Firefox, en lugar de OpenSSL
- La versión de Chrome se compila con BoringSSL, la biblioteca TLS de Google
- Se cambia la forma en que curl configura varias extensiones TLS y opciones SSL
- Se añade soporte para nuevas extensiones TLS
- Se cambia la configuración usada en conexiones HTTP/2
- Se ejecuta curl con flags no predeterminados como
--ciphers,--curvesy algunos headers-H
- Como resultado, desde la perspectiva de la red, curl se ve igual que un navegador real
- La explicación técnica completa está en part a y part b
Navegadores compatibles y nombres de target
- La lista de navegadores compatibles también está disponible en
browsers.json - Targets compatibles de la familia Chrome
- Chrome 99, 100, 101, 104, 107, 110, 116 en Windows 10
- Chrome 99 en Android 12
- Edge 99 y 101 en Windows 10
- Safari 15.3 en MacOS Big Sur
- Safari 15.5 en MacOS Monterey
- Targets compatibles de Firefox
- Firefox 91 ESR, 95, 98, 100, 102, 109 y 117 en Windows 10
- Cada target compatible tiene un nombre de target y un wrapper script
- Ejemplo: el target
chrome116se ejecuta con el wrapper scriptcurl_chrome116 - Ejemplo: el target
ff117se ejecuta con el wrapper scriptcurl_ff117
- Ejemplo: el target
Uso básico
- Para cada navegador compatible hay un wrapper script que ejecuta
curl-impersonatecon los headers y flags necesarios - Ejemplo de ejecución
curl_chrome116 https://www.wikipedia.org - Si agregas flags de línea de comandos, se pasan a curl
- Algunos flags pueden cambiar la firma TLS de curl y hacer que se detecte
- El wrapper script usa un conjunto predeterminado de headers HTTP
- Si quieres cambiar los headers, puedes modificar el wrapper script según tu objetivo
- Más opciones están incluidas en el uso avanzado de
libcurl-impersonatecomo biblioteca
Instalación y forma de distribución
- Por razones técnicas,
curl-impersonatetiene dos versiones- Versión chrome: se usa para imitar Chrome, Edge y Safari
- Versión firefox: se usa para imitar Firefox
- Los binarios precompilados para Linux y macOS Intel se ofrecen en GitHub releases
- Antes de usar los binarios precompilados, hay que instalar NSS y los certificados 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:
- El sistema también necesita zlib
- zlib casi siempre está presente, pero puede faltar en algunos sistemas mínimos
- Los binarios precompilados para Linux están construidos para sistemas Ubuntu
- Si aparece un error de verificación de certificados en otra distribución, puede ser necesario indicar a curl dónde están los certificados CA
curl_chrome116 https://www.wikipedia.org --cacert /etc/ssl/certs/ca-bundle.crt - Para compilar desde código fuente, consulta INSTALL.md
Docker y paquetes
- Hay imágenes Docker basadas en Alpine Linux y Debian disponibles en Docker Hub
- Las imágenes Docker incluyen los binarios y todos los wrapper scripts
- Ejemplo
# Versión 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 # Versión 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 - Los usuarios de Archlinux pueden usar paquetes de AUR
- Paquetes precompilados: curl-impersonate-bin, libcurl-impersonate-bin
- Paquetes para compilar desde código fuente: curl-impersonate-chrome, curl-impersonate-firefox
- Hay una fórmula no oficial de Homebrew para Mac, solo para Chrome
brew tap shakacode/brew brew install curl-impersonate
Uso avanzado de libcurl-impersonate
libcurl-impersonate.soes una libcurl compilada con los mismos cambios quecurl-impersonatede línea de comandos- Tiene una función API adicional
CURLcode curl_easy_impersonate(struct Curl_easy *data, const char * target, int default_headers); - Si se llama con un nombre de target como
chrome116, configura internamente las opciones y headers que antes establecía el wrapper script - Si
default_headerses 0, no configura la lista integrada de headers HTTP- En ese caso, el usuario debe proporcionar los headers directamente con la opción normal de libcurl
CURLOPT_HTTPHEADER
- En ese caso, el usuario debe proporcionar los headers directamente con la opción normal de libcurl
curl_easy_impersonate()configura varias opciones de libcurlCURLOPT_HTTP_VERSIONCURLOPT_SSLVERSION,CURLOPT_SSL_CIPHER_LIST,CURLOPT_SSL_EC_CURVES,CURLOPT_SSL_ENABLE_NPN,CURLOPT_SSL_ENABLE_ALPNCURLOPT_HTTPBASEHEADER, una opción no estándar del proyectoCURLOPT_HTTP2_PSEUDO_HEADERS_ORDER,CURLOPT_HTTP2_NO_SERVER_PUSH, opciones HTTP/2 no estándar del proyectoCURLOPT_SSL_ENABLE_ALPS,CURLOPT_SSL_SIG_HASH_ALGS,CURLOPT_SSL_CERT_COMPRESSION,CURLOPT_SSL_ENABLE_TICKET, opciones TLS no estándar del proyectoCURLOPT_SSL_PERMUTE_EXTENSIONS, una opción TLS no estándar del proyecto
- Si después llamas a
curl_easy_setopt()con alguna de las opciones anteriores, sobrescribes el valor configurado porcurl_easy_impersonate()
Aplicarlo a apps existentes con libcurl
- Si la aplicación ya usa
libcurl, en Linux se puede reemplazar la biblioteca existente en tiempo de ejecución conLD_PRELOAD - Configurando la variable de entorno
CURL_IMPERSONATEse aplica la suplantación automáticamenteLD_PRELOAD=/path/to/libcurl-impersonate.so CURL_IMPERSONATE=chrome116 my_app CURL_IMPERSONATEtiene dos efectos- Cuando se crea un nuevo handle de curl con
curl_easy_init(), se llama automáticamente acurl_easy_impersonate() - Después de
curl_easy_reset(), también se llama automáticamente acurl_easy_impersonate()
- Cuando se crea un nuevo handle de curl con
- Si necesitas un control fino sobre los headers HTTP, puedes desactivar la lista integrada de headers con
CURL_IMPERSONATE_HEADERS=noy configurarlos tú mismoLD_PRELOAD=/path/to/libcurl-impersonate.so CURL_IMPERSONATE=chrome116 CURL_IMPERSONATE_HEADERS=no my_app - El método con
LD_PRELOADno funciona con curl mismo- Porque la herramienta curl sobrescribe la configuración TLS
- Para curl hay que usar el wrapper script
Estructura del repositorio y contribuciones
- El repositorio tiene dos carpetas principales
- El directorio de Firefox, por ejemplo, incluye los siguientes archivos
- Dockerfile: se usa para compilar
curl-impersonatecon todas las dependencias - curl_ff91esr, curl_ff95, curl_ff98: wrapper scripts para ejecutarlo con los flags correctos
- curl-impersonate.patch: el parche principal que hace que curl use las mismas extensiones TLS que Firefox y permite compilación estática con libnghttp2 y libnss
- Dockerfile: se usa para compilar
- tests/signatures es una base de datos YAML de firmas conocidas de navegadores que se pueden imitar
- Los parches reales de curl se mantienen en un repositorio separado derivado de upstream curl
- Los cambios de Firefox están en la rama impersonate-firefox
- Los cambios de Chrome están en la rama impersonate-chrome
1 comentarios
Opiniones en Hacker News
Hay un fork con bastantes mejoras respecto del original y que se mantiene activamente: https://github.com/lexiforest/curl-impersonate
También hay bindings para usuarios de Python: https://github.com/lexiforest/curl_cffi
Paradójicamente, esa solicitud le impondría menos carga al servidor que un navegador certificado; uno se pregunta si esta es la distopía sobre la que nos advertían en los 90. Me pregunto quién aquí se animaría a nombrar a una empresa que, mientras se posiciona como buena contribuidora de la comunidad open source/hacker, creó esta situación.
Ojalá Ladybird gane impulso en el futuro. Actualmente usa cURL oficial para networking, pero ese enfoque puede tener obstáculos.
Por ejemplo, entiendo que cURL todavía tiene algunas limitaciones y no puede manejar WebSocket sobre h2. En cambio, si surge un motor de navegador en crecimiento, el tráfico normal también tendría la misma huella digital que cURL básico, y esa vía de fingerprinting podría desaparecer.
También es un buen banco de pruebas para ver qué funcionalidades le faltan a cURL tomando como referencia flujos de trabajo reales de un navegador.
En los últimos meses aumentó mucho el nivel de fingerprinting y de “abuso” de comportamientos definidos por la implementación, probablemente como intento de matar otros motores de navegador. A los incumbentes no les gusta en absoluto la competencia.
La otra parte intenta presentarlo como “DDoS de bots de IA”, pero me pregunto cuánto de eso fue creado por ellos mismos.
Me gusta este curl, pero me preocupa que, cuando algún componente asume el papel de hacer trucos para “ponerse al día”, se acumule una carga de “compatibilidad” difícil de mantener.
Lo ideal sería poder decir simplemente: “Hola, soy curl, déjame entrar”.
Claro que el problema está en los servidores exigentes con el código de vestimenta, y ese problema a su vez existe por los estafadores que entran disfrazados, así que es un ciclo tipo el huevo y la gallina.
[0] https://cybershow.uk/episodes.php?id=39
Además, el hecho de que se haya rediseñado en C++, que demostrablemente no es seguro, implica un gran riesgo de seguridad.
¿Habrán configurado también
IP_TTLpara que coincida con el valor TTL de la plataforma que intentan suplantar?Si no, también se puede hacer cierto fingerprinting en la capa IP. Si el valor TTL en la capa IP es menor que 64, queda claro que no se está ejecutando en Windows moderno, o que es un Windows moderno con el TTL predeterminado modificado. Esto se debe a que el TTL predeterminado de los paquetes en Windows moderno empieza en 128, mientras que en la mayoría de las otras plataformas empieza en 64.
Como las demás plataformas también se comunican por Internet sin problemas, un paquete IP proveniente de Windows moderno siempre se verá del lado remoto con un TTL de 64 o más, probablemente un poco por encima de 64. Dicho esto, el fingerprinting en la capa IP es difícil, pero no imposible.
https://en.wikipedia.org/wiki/TCP/IP_stack_fingerprinting
Un momento: si el handshake TLS se ve diferente, ¿no se podría filtrar a nivel de nginx el tráfico que dice ser un navegador web pero en realidad es un script de Python/PHP?
Por ejemplo, cuando usa un user agent de Chrome pero no es un navegador real. Como la mayor parte del tráfico de bots maliciosos entraría ahí, sería bueno poder bloquearlo sin más.
El funcionamiento está detallado en https://github.com/FoxIO-LLC/ja4/blob/main/technical_details..., y también ofrecen un módulo para Nginx: https://github.com/FoxIO-LLC/ja4-nginx-module
Si no estás sufriendo un ataque real en este momento, no deberías usar una lista de permitidos de huellas TLS.
Es una herramienta genial, pero no debería importar si el cliente es un navegador o no. Es triste que en la realidad se necesiten herramientas así.
Agregué una extensión de user agent en Chrome, lo cambié a IE y volví a intentar; funcionó, y todas las funciones del sitio también andaban bien. Por eso me dio tristeza y también me molestó. Probablemente esa agencia gubernamental hizo el sitio hace 25 años y no lo actualizó desde entonces.
Este tipo de gatekeeping también me parece triste. Según entiendo, los navegadores personalizados o user agents hechos por uno mismo nunca funcionarán en sitios tipo Cloudflare hasta que consigan suficiente influencia, dinero, cantidad de usuarios o algo similar para convencerlos.
Esta herramienta es bastante buena para trabajos de red team si se combina con pequeños scripts bash y GNU parallel.
Me resultó útil para mapear endpoints HTTPS dentro de rangos de direcciones definidos en el alcance, que por varias razones solo respondían a navegadores adecuados o solo respondían si la configuración de SNI era correcta. También se pueden usar tal cual opciones normales de curl, como
-H, para falsificar headers.Publicación de Show HN de aquel entonces: https://news.ycombinator.com/item?id=30378562
Cada vez que algo así aparece aquí, siempre tengo sentimientos encontrados. Por un lado, me gusta que indique que todavía queda algo de rebeldía e independencia entre la gente.
Por otro lado, como ocurre con otros proyectos en los que “la libertad es inestable”, si atrae atención no deseada, la situación podría empeorar para quienes dependen de esto. Crear navegadores es difícil, y los actores dominantes existentes siguen haciéndolo más difícil.
No lo veo como un problema de rebeldía. Que el software se vuelva identificable por huella digital erosiona la privacidad y la diversidad del software.
Extraño un poco aquellos tiempos simples en los que, si a un sitio web le parecían bien los bots, los permitía, y si no, bloqueaba el user agent.
Si solo son 3 parches y un wrapper de shell, Daniel podría animarse a programarlo. Personalmente, creo que esto debería entrar sí o sí en el curl mainline.