viernes, octubre 02, 2015

Cómo saltarse Cloudflare para scrappear una web

Buscando como ganar algo de dinero acepté un trabajo que consistía en hacer un plugin para scrappear los videos de una pagina web y ponerlos en un WordPress. La verdad es que el uso de este plugin puede ser para hacer cosas buenas y también para hacer cosas malas, pero en mi caso consistía solo en hacer el trabajo, así que no me pareció mala idea y lo acepté. El caso es que durante el proceso de scrappear las páginas del sitio me encontré con un problema. En un error mío empece a enviar peticiones a la pagina de forma masiva y sin control, lo que provocó lo que a ojos del sitio era un Ataque de Denegación de Servicio de todo la vida, y en respuesta esa pagina puso su protección de "I'm under attack" que tiene contratada con Cloudflare. En ese momento pensé, vaya me quede sin el dinero y empece a indagar en el tema.

Figura 1: Cómo saltarse Cloudflare para scrappear una web

El protector de Cloudflare frente ataques de Denegación de Servicio lo que parece que intenta es hacerte esperar durante cinco segundos antes de poder entrar en la pagina web. Así, cuando vas a una página protegida por Cloudflare lo que ves en el navegador es simplemente una pantalla en blanco con la frase "Espere 5 segundos". Sin embargo, lo que sucede por debajo es un poco más complejo, ya que en realidad hay una serie de peticiones y respuestas con un algoritmo que intenta detectar cuando es un bot o cuando es un usuario navegando. Ésta es la pantalla que se puede observar al intentar entrar.

Figura 2: Pantalla de protección de Cloudflare para evitar los ataques DDoS

Al ver esto lo primero que pensé fue en buscar por Internet qué podía hacer y si había algún programa capaz de saltarse de forma automatizada esas peticiones, pero para mi sorpresa sólo había un código en Python hecho por un tal Anorov y yo ese código no podía usarlo en mi aplicación, ya que usaba librerías externas, así que lo que decidí fue crear mi propio código en PHP para saltarme la protección.

Para ello decidí comenzar con el proceso desde cero y analizar qué estaba pasando durante esos cinco segundos. Quité todas las cookies de mi navegador y empecé a analizar los paquetes que recibía por la red con Wireshark y como podéis ver, el intercambio es algo más complejo .

Figura 3: Intercambio de paquetes entre cliente y servidor de Cloudflare

Estos son los paquetes que recibía. Hasta aquí ningún problema, ahora los analizaremos con mas detalle para explicar qué es lo que hay que automatizar con el objeto de saltarse la protección y poder seguir scrappeando.

Figura 4: Cookie __cfdui enviada por Cloudflare

Como podeis ver en la respuesta que aparece en la Figura 4,  el servidor te envía una cookie con Set Cookie:__cfdui. Esto nos lo guardaremos para más adelante ya que deberemos gestionar esta cookie en el resto de peticiones que vayamos a automatizar al tener que pasarnos por un navegador. Nos hará falta ese valor.

Lo importante es que dentro de lo que envía el servidor de Cloudflare hay un código Javascript que complica todo el proceso ya que obliga al navegador a hacer operaciones. Estas operaciones en el pasado ya han sido analizadas en el pasado, como explicaba David Barroso en su artículo sobre Cloudflare: Héroe o Villano, pero lo van cambiando y actualizando con el tiempo.

Figura 5: Código ofuscado enviado por Cloudflare para detectar al navegador

Este código lo que hace es enviarnos números en formato ofuscado JavaScript con la forma de !![]+[]. Para transcribir este código dentro de un PHP a números tenemos que ejecutarlo y para ello nos hacen falta librerías de ejecución de JavaScript en PHP. Es necesario hacer el cálculo de resultado de esta fichero porque luego debe ir en la respuesta que le enviaremos a Cloudflare para autenticarnos como “no bots”.

Yo lo que hice - como no tenia mucha idea inicialmente de esta codificación y lo único que sabía es que daba un número, fue empezar a ejecutar código JavaScript en otro sitio y descubrir qué quería decir cada uno de estos símbolos. Al final después de un buen rato descubri la forma en la que funcionaba - sí, lo hice a pico y pala y seguro que hay formas mucho mas eficientes de hacerlo pero yo lo hice así. Para ello me hice este código.

Figura 6: Código para interpretar desde PHP las operaciones ofuscadas en JavaScript
Lo que hace este código para calcular el resultado de la operación es, si tenemos:
var t,r,a,f, dUFLoHl={"StGGclxDbFtT":+((!+[]+!![]+!![]+!![]+[])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]))};\n
Primero separa los paréntesis. Es decir, primero (!+[]+!![]+!![]+!![]+[]) y después (!+[]+!![]+!![]+!![]+!![]+!![]+!![]). Luego hay que interpretar los números, donde los !+[] y !![] valen 1 y los [] valen 0, pero si el [] esta después de un !![] (1) y en el siguiente paréntesis hay un !+[] delante valdrá 10, tienen que cumplirse estas dos condiciones si no, valdrá 0. Por lo tanto en este ejemplo el numero valdrá ((40)+(7)) = 47.

Al final, lo que hace el código JavaScript que envía Cloudflare es aprovechar la codificación no numérica, igual que la herramienta de Hyeroglyphy lo usa para hacer ataques XSS ofuscados.

Figura 7: Codificación no numérica en JavaScript

Como hemos visto en el código JavaScript este numero que se llama dUFLoHl. StGGclxDbFtT se va sumando, restando y multiplicando por otros números hasta dar un valor final tras ejecutar todas las operaciones. En este caso el valor es: 2380330. Después, más abajo en el código que envía Cloudflare, tenemos otra parte del código que nos dará una credenciales dentro del código HTML en un formulario con type hidden.

Figura 8: Formulario con credenciales para enviar la petición

Estos valores serán necesarios para enviarlos junto a la siguiente petición que hagamos, que será ésta. Ojo, antes de enviar la petición en el código hay que esperar 5 segundos, ya que si no te esperas el servidor te deniega la entrada directamente por "sospechoso de rápido". Como podeis ver enviamos la cookie junto a la petición, y la URL a la que se lo enviamos es esta:
http://host.com/cdn-cgi/l/chk_jschl?jschl_vc=18fcb850b47d7c30a18420c5d5dbfbb5&pass=1443549964.854-Z%2F65V%2BZx%2Br&jschl_answer=2380330
Figura 9: Envío de petición con los valores calculados

Con los valores que nos han pasado jschl_vc, pass, jschl_answer, en jschl_answer lo que pondremos como valor es el número que hemos calculado antes. Ésta era la parte mas difícil luego ya la cosa es mas sencilla. Veramos lo que nos devuelve ahora. Al ver que le hemos dado una URL correcta con password correcto y todo, sólo nos devuelve un 302 Found, y un Set Cokie, cf_clearance, etcétera. Estos datos simplemente los tendremos que guardar y ya está.

Figura 10: Resultados de la petición

Puntualizo que a veces no sé porque también, a parte de enviar el cf_clearance en la segunda respuesta, también envían el valor __cfduid. Es decir realizan un reemplazo de la primera cookie por otra, lo que me generó unas cuantas comeduras de cabeza. Esta es una protección para hacer que las cookies que utilizan mueran muy rápidamente, por lo que hay que estar atentos a ver si cambian el valor de __cfduid en cada petición. Después de todo esto sólo nos falta enviar una petición con las cookies. Yo utilizaba este codigo.

Figura 11: Código final para saltarse la protección

Cabe decir que mi código no funciona el 100% de las veces. Funciona alrededor del 70-80%, ya que alguna otra medida de seguridad metida en alguna petición hace que no se ejecute correctamente, pero el poder saltar la protección de Cloudflare en el 70-80% de las veces permite que se pueda scrappear cualquier web de forma automática correctamente.

No lo hice con el objetivo de saltarme la protección de nada, sino de conseguir resolver el problema y aunque para alguno no sea gran cosa o no sea elegante, es la primera vez que consigo hacer algo de este estilo y estoy muy contento de haberlo conseguido, así que si estás trabado intentando resolver algo y no te sale, sé constante que la satisfacción de conseguirlo merece la pena el sacrificio.

Y hasta aquí el post! Un saludo maligno!

Autor: Alejandro García

11 comentarios:

  1. Gracias, como siempre. Chorrada de regalo: https://buffer-pictures.s3.amazonaws.com/ecf704408c7078fe1b822fee1c7b99f6.9801e31a3103c06fb006e4a8faf3263a.gif

    ResponderEliminar
  2. Enhorabuena Alejandro!! Gran trabajo ;D

    ResponderEliminar
  3. Felicidades por el trabajo.

    En mi caso me encontré con el mismo problema pero lo resolví de otro modo. Al final los servicios de Cloudflare o Akamai actúan como proxy y si se consigue averiguar la IP origen se puede hacer el scrapping directamente sobre ésta. La gente de Security Idiots publicaron un tutorial explicando algunos métodos para averiguar la IP origen. Aunque la mayoría de esos métodos ya están obsoletos existen otros "trucos" para dar con la IP origen.

    Saludos.

    ResponderEliminar
  4. Podías haber evaluado el código en NodeJS y te habrías ahorrado la investigación de la ofuscación y las expresiones regulares.

    ResponderEliminar
    Respuestas
    1. Muy interesante apreciación . ¿algún tuto para empezar?

      Eliminar
  5. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  6. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  7. El artículo muy bueno!!!

    ResponderEliminar
  8. grande como siempre , es mejor hacer el trabajo a mano asi se entiende lo que se hace y se aprende mejor ,exelente trabajo

    ResponderEliminar
  9. Como puedo contratarte para un servicio ?

    ResponderEliminar