volvervolver
Automatizando despliegue de proxys con Python

COMPARTIR

Automatizando despliegue de proxys con Python

Durante la ejecución de una auditoría, o en otros casos como al consumir un servicio, el cual queremos evitar el bloqueo por IP, o en el caso de la ejecución de un web crawling/spider, debemos buscar la manera de cambiar nuestra IP real cada cierta cantidad de requests o tiempo. Hay distintas maneras de realizar esta tarea dentro de dos categorías bien marcadas, el camino del uso de infraestructura gratuita (como son los proxies públicos o tor) y la otra utilizar un servicio privado de un proxy rotativo o el uso del conocido servicio de Amazon.

En este caso vamos a ver en detalle cómo sacar provecho de las listas de proxies públicos, pero también vamos a mencionar los otros puntos que mencionamos anteriormente.

Desarrollaremos un código en Python que nos va a facilitar la automatización de:
   Extracción y digest de listas públicas de proxies
   Desarrollo de código para filtrar proxies en base a criterios de latencia y otros.
   Comprobación automática de cada proxy
   Configuración automática de un balanceador de carga con la lista de proxies verificada
   Generación del archivo de configuración de proxychains (alternativo)

Fuente y digest de la información

Antes de comenzar con el desarrollo del primer borrador del código, necesitamos encontrar una fuente de información para nuestro propósito. Cabe destacar, que si realizamos esta etapa lo más simplificada posible, luego vamos a poder añadir nuevas fuentes de manera más sencilla y alargar la vida útil del código y la paciencia del desarrollador.

Luego de una simple búsqueda en Google, encontramos un servicio interesante por la manera tan abierta de compartir la lista de proxies (descarga en formato json, txt, csv,. esto nos favorece, ya que vamos a estar ahorrando tiempo en no tener que parsear un HTML.

El servicio que utilizaremos será el de Genode (https://geonode.com/free-proxy-list/) imagen ilustrativa
Vamos a analizar cómo nos llega esta información si lo obtenemos con curl y lo procesamos con jq, pero primero modifiquemos un poco la URL, ya que el link que nos provee la página, va a traer 500 proxies, traigamos solo uno para examinar la respuesta y la estructura de datos recibida:
imagen ilustrativa
La respuesta es la siguiente:
imagen ilustrativa
Podremos utilizar toda esta información de las maneras más creativas, para este caso solo vamos a utilizar data[“ip”], data[“latency”] y total. El total de proxies puede ser no muy importante ahora, pero nos va a servir para recorrer las distintas páginas, hay que tener en cuenta que la url muestra los resultados por página, y el máximo de proxies a traer es de 500. Las siguientes funciones se encuentran simplificadas al máximo para entender el flujo de la información, y se han eliminado strings innecesarios que dificultan la lectura:

Función get_proxys_count(“socks5”)
imagen ilustrativa
Función parse_proxy_response(json,”socks5”,50)
imagen ilustrativa
Función get_proxy_list(“socks5”,50)
imagen ilustrativa
Estas tres funciones obtienen el json de cada página de los proxies del tipo que queramos (http, https, socks4 y socks5), luego recorre esos datos y genera un array con los proxies que tienen menos latencia que 50 (esto lo pasamos por parámetro al momento de ejecutar el script). Los datos se guardarán de la siguiente manera:
imagen ilustrativa
Testeo de los proxies

Para esta etapa, lo siguiente será tomar como input el resultado de la etapa anterior, donde ya tenemos nuestros proxies con el formato del archivo de configuración de ProxyChains. Una de las formas de testear estos proxies, es hacer una request a una página web a través del protocolo, ip y puerto que obtuvimos, y analizar la respuesta. En base a esto nuestro script identificará que proxies podemos usar desde nuestra ubicación, si uno ejecuta el script desde IP de países distintos, obtendrá resultados diversos, ya que algunos proxies solo están habilitados para ciertas zonas.

Al utilizar el módulo de request si probamos por ejemplo 2.000 proxies, esto será bastante lento si se hace de a uno por vez. Para ello vamos a utilizar multi-threading, con la librería threading de Python. Ya que la ejecución del testeo necesita retornarnos un valor positivo o negativo en caso de que el proxy sea utilizable, necesitamos declarar una nueva clase, la librería en cuestión.

Clase thread con valor de retorno
imagen ilustrativa
Ya podemos ejecutar la función que va a verificar los proxies y determinar en base al valor retornado si el mismo está vivo o no. La función es la siguiente:

Función check_proxy(“socks5 1.1.1.1 3128”,”http://ifconfig.me/ip”) imagen ilustrativa
Ahora sí, crearemos la función que ejecutará 12 workers a la vez y checkeará nuestra lista filtrada de proxies activos.

Función do_multi_thread_check(array_proxies,”http://ifconfig.me/ip”):
imagen ilustrativa
Esta función en particular recibirá como parámetro la lista de proxies filtrados por latencia y el sitio web contra el que queremos probar si estos funcionan.

La lógica de programación de esta última función será que, mientras haya proxies en el argumento proxies, creará 12 workers, cada uno extrae un proxy y elimina el valor extraído de la lista original hasta que el argumento quede vacío. Si el proxy está vivo el worker que lo verificó retorna la información, y esta es guardada en una variable nueva llamada good_ones. Al finalizar la tarea, la función retorna estos proxies que están funcionando.

Balanceador de carga

La etapa anterior nos dejó una variable con los proxies testeados y funcionales. La tarea ahora es levantar un solo puerto con un servicio que pueda distribuir la carga del tráfico que queremos “proxear”. Una buena alternativa para realizar esta tarea, es el siguiente proyecto el cual encaja justo con nuestra necesidad: https://github.com/extremecoders-re/go-dispatch-proxy

Esta herramienta es una adaptación del dispatch-proxy desarrollado en NodeJS y Golang. Este último detalle parece interesante, ya que es un lenguaje muy rápido. Para utilizar la herramienta, debemos instalar libpcap-dev:

imagen ilustrativa
Podemos compilar el proyecto o descargarnos el reléase funcional. En nuestro caso, compilaremos el código en nuestra máquina:

imagen ilustrativa
Y Listo! Ya tenemos el binario del balanceador de carga compilado, si todo fue bien, deberíamos obtener como output en el último comando un mensaje como el siguiente: imagen ilustrativa
El siguiente paso será mover el binario del balanceador de carga a la carpeta donde tenemos desarrollado el script de Python, siguiente a eso, desarrollaremos la siguiente función para levantar el binario compilado con los proxies buenos que obtuvimos en la etapa anterior:

imagen ilustrativa
Esta función armará el comando según la documentación del repositorio y lo ejecutará a través de subprocess.run.

Ejecutemos el código desarrollado con los siguientes argumentos:
imagen ilustrativa
La ejecución de nuestro script arroja el siguiente output:
imagen ilustrativa
Ya tenemos funcionando entonces un balanceador de carga con proxies públicos, cabe destacar tener especial cuidado al utilizar estos proxies, generalmente registran todo el tráfico enviado incluyendo cookies de sesión, credenciales o información sensible que puede ser comprometida. Al levantar la conexión a través del protocolo socks5, el servicio puede ser utilizado para escanear puertos.

Esté balanceador solo funciona con proxies socks5, por lo tanto, nuestro código deberá tener la validación correspondiente para no levantar proxies de otro tipo (y así perder tiempo valioso).

Para realizar un escaneo de puertos necesitaremos un scanner que tenga soporte para proxy socks5, como por ejemplo naabu (https://github.com/projectdiscovery/naabu). Solo debemos pasarle al scanner el puerto del loadbalancer que levanta por defecto en el 8080.

Generación de proxychains.conf

Analizando hasta ahora hemos realizado él parseo de los listados de proxies, lo procesamos, testeamos el estado de cada uno y levantamos un balanceador de carga con los activos, todo de forma automatizada. Podríamos agregar una funcionalidad más a nuestro script en la cual genere un archivo de configuración de proxychains. Para ello la siguiente función hará el trabajo:

Función print_proxy_chains_file(array_de_proxies_activos,1):
imagen ilustrativa
Ejecutemos nuestro script para que en vez de levantar un load balancer, imprima el archivo de configuración de proxychains, esta vez bajaremos la latencia para no testear tantos proxies y utilizar el output como un ejemplo rápido. También testearemos desde un vps las conexiones entrantes de los proxies para verificar desde donde nos llegan:

En localhost:
imagen ilustrativa
En el VPS:
imagen ilustrativa
El output en localhost, arroja el siguiente resultado:
imagen ilustrativa
Mientras que del lado del VPS obtenemos el siguiente resultado:
imagen ilustrativa
Para utilizar los proxies que obtuvimos, solo debemos copiar el output del script dentro del archivo proxychains.conf:
imagen ilustrativa
Conclusión

De esta manera podemos automatizar la tarea de verificar una lista de proxies y utilizar estos con proxychains o levantando nuestro propio balanceador de carga. Como describíamos en la introducción, hay otras maneras de realizar esta tarea, por ejemplo utilizando el proyecto de docker rotating-tor-http-proxy podremos levantar un HAProxy a través del protocolo HTTP que tiene la misma funcionalidad que el código que desarrollamos pero utilizando múltiples instancias de tor, que son renovadas cada cierto tiempo.

Además, existe otra alternativa utilizando los servicios de API Gateway de Amazon, este método es muy rápido cuando queremos realizar web fuzzing y evadir controles de bloqueo de IP. Estos últimos métodos mencionados no son compatibles con un escaneo de puertos, ya que el protocolo utilizado es HTTP y para este escenario la única manera posible es el script desarrollado en este texto.

El repositorio de GitHub donde se encuentra todo el código desarrollado de la herramienta está a continuación: https://github.com/BASE4-offensive-operations/autolb-proxies