Prey es una herramienta que permite el rastreo de computadores y dispositivos móviles, pensado para encontrar tu portátil, tablet o teléfono móvil cuando se te pierde o te lo roban.
Basicamente, y como todo software o herramienta de rastreo, lo que hace es enviar información a un servidor centralizado con la ubicación y otros datos que te pueden ayudar a identificar dónde está tu dispositivo. Lo que me llamó la atención fue querer conocer cómo envia la información y cómo funciona la "api" de comunicación, por lo que me lo descargué y comencé a analizar el código.
La versión analizada es la 0.5.9 (md5: 1ff6cb6bb0de36415fde3382e72a8a6d), pero imagino que la información que voy a exponer afecta a todas las versiones anteriores.
El principal problema es que el protocolo que se pensó para la interacción entre los usuarios y el servidor centralizado es demasiado básico y no cuenta con los controles de seguridad necesarios.
Primero, para entender un poco como funciona de manera simple, los clientes (usuarios) interactuan con el servidor control.preyproject.com, habilitado bajo los protocolos HTTP y HTTPS. Se comunica bajo el User-Agent=Prey Configurator/Version y se envían los parámetros requeridos mediante POST. Las peticiones se envian a distintos archivos xml bajo el subdominio de control; por ejemplo users.xml, devices.xml, prey-last-response.xml o "device_key".xml. Este último, se remplaza device_key por la llave o identificador del dispositivo.
Segundo, existen parámetros de autenticación que se envian en las cabeceras de la petición http. Corresponden al mecanismo de autenticación HTTP mediante la cabecera Authorization. Aquí está el primer problema y debilidad de la herramienta: Se envían cifrados en Base64.
Todos sabemos que base64 es un algorítmo de doble vía, que permite cifrar y descifrar sin mayores esfuerzos, por lo que no se recomienda utilizarlo como medida de seguridad para claves o tokens.
Existen distintos tipos de autentificación http, el que implementa Prey es el más inseguro y el menos recomendado, su nombres es "Basic". Los datos enviados mediante el mecanismo básico de autenticación puede ser fácilmente interceptado y descifrado, permitiendo conocer la ApiKey y que, capturando los datos enviados por POST, ya tenemos toda la información para hacer consultas sobre el o los dispositivos de nuestra víctima.
Por ejemplo, esta es una petición enviada al servidor de control de Prey, usando un ApiKey aleatorio:
Si desciframos la segunda linea, despues de "Basic", obtenemos lo siguiente: syrjbqk7z6w:x. El primer elemento, antes de los dos puntos (:) corresponde al usuario y el segundo a la clave.
Algunos pueden pensar que si el tráfico va por SSL no deberíamos poder leerlo, sin embargo, aquí existe otro problema mas.
El segúndo problema es que las peticiones que hace Prey a su servidor "seguro" son de forma insegura, aceptando certificados inválidos, permitiendo a un atacante realizar ataques Man-in-the-Middle al protocolo HTTPS y conocer el contenido de la petición sin ningun problema. Por ejemplo, esta es una de las llamadas que hace la herramienta usando cURL:
command = '/usr/bin/curl -A "' + USER_AGENT + '" -i -s -k --connect-timeout 5 ' + CONTROL_PANEL_URL_SSL + '/' + path + data
El parámetro "-k" de cURL significa: aceptar certificados inválidos. La línea corresponde a la número 479 del archivo platform/linux/prey-config.py.
El impacto de estas vulnerabilidades o debilidades es que por ejemplo si tienes Prey instalado en tu celular o en tu notebook y te conectas a una red publica (con o sin clave) como la de un café, centro comercial, bar o lo que sea, toda la información que Prey envía sobre tu ubicación puede ser intersectado por un tercero. Además, esa persona podría quedarse con tus tokens y consultar la ubicación y los datos de los dispositivos registrados cuando quiera.
La tercera vulnerabilidad, afecta al proceso de registro de un nuevo usuario o dispositivo. Para realizar este proceso se envia una petición a users.xml pasando mediante POST las variables name, email, password y password_confirmation. No cuenta con ningún tipo de control de seguridad, lo que permite registrar tantos usuarios como queramos, pudiendo saturar el servidor si se realizan miles de peticiones de forma simultanea. Esta información fue obtenida del archivo platform/linux/prey-config.py, función create_user.
PRE0
Por ejemplo, en la siguiente Prueba de Concepto (PoC) crearé 10 nuevos usuarios y el sistema me devolverá sus respectivas llaves. Usando cURL de la siguiente forma:
for num in $(seq 1 10); do curl -A "Prey Configurator/222 (Linux)" https://control.preyproject.com/users.xml -d "user[name]=user_$num&user[email]=correodeprueba$num@gmail.com&user[password]=123456&user[password_confirmation]=123456"; done
Obtenemos:
Con esto hemos creado los usuarios user_1, user_2, user_3, user_4, user_5, user_6, user_7, user_8, user_9 y user_10 con los correos respectivos correodeprueba1@gmail.com, correodepruebaN@gmail.com. El servidor devolvió los siguientes tokens:
- hjxdp3k46u2j
- v6lijlbx3tc8
- qow7eih39ymb
- cvrealg9vu09
- t5nd017drwmi
- irsiauu5msc2
- t8u9jrtvmxbh
- 31gqe0h3fiy2
- glua8bsl8wtg
- 295y3at88e0w
Los cuales cumplen el mismo patrón: Largo 13 caracteres, numeros y letras en minusculas. Ahora podemos generar tokens aleatorios segun este patron e ir probando. Con esto ya tenemos nuestra cuarta vulnerabilidad que debido a la fatla de controles de seguridad es posible realizar fuerza bruta y obtener las ApiKey de los usuarios. Si hacemos una petición a devices.xml entregando mediante la cabecera de autentifiación básica un token aleatorio el servidor nos devolverá el código 401 Unauthorized, de lo contrario nos devolverá 200 OK. De esta forma podemos enviar tantas peticiones queramos hasta obtener el codigo 200. Como podemos ver en la función verify_keys() del archivo core/pull, si el servidor devuelve 200 OK o 404 Not Found, significa que la ApiKey es válida, de lo contrario nos dice que es incorrecta:
PRE1
Por lo tanto, lo único que debemos hacer es un script que genere strings alfa-numéricos en minúsculas de largo 13 y que haga las peticiones correspondientes hasta dar con un token valido.
Con el siguiente script hacemos la prueba de concepto:

