Como evitar ataques de repetición en tus proyectos de IoT con OTP (Arduino)

Los ataques de repetición son un habitual en los dispositivos de IoT y muchas grandes empresas los han sufrido. Se producen cuando alguien intenta securizar las comunicaciones entre dispositivos pero no tiene muy claro como se hace.

Realmente un ataque de repetición es un ataque de inyección de comandos pero con algunas limitaciones. Vamos a plantear un escenario muy sencillo. Una casa con una bombilla inteligente conectada por WiFi (o de cualquier otra manera la capa física de la conexión da igual). Esta bombilla recibe comandos para encenderse y apagarse. Ahora conectamos un dispositivo “malvado” a esta red (o no lo era cuando lo conectamos pero un atacante se hace con el control). Este dispositivo podría enviar comandos de encendido y apagado a la bombilla. Lo que sería el equivalente a un niño jugando con el interruptor. Esto sería un ataque de inyección de comandos.

Para solucionarlo el fabricante piensa que puede cifrar los comandos con un cifrado superseguro e irrompible, cada bombilla tendrá una clave única así que aunque el atacante haga ingeniería inversa no le va servir de nada. Ahora el fabricante anuncia que su dispositivo es seguro y comprador se siente protegido.

Pero la realidad es que no basta con cifrar la comunicación. La lámpara recibe comandos de encendido y apagado cifrados. Podríamos decir que es lo mismo, un conjunto de bytes enciende la lámpara y otro la apaga, solo que esta vez ese conjunto es diferente para cada lámpara del mundo. La clave de este ataque es que si siempre se cifra el mismo comando con la misma clave el conjunto de bytes siempre es el mismo por lo que al atacante le basta con capturarlo para poder reenviarlo tantas veces como quiera.

¿Y si añade una parte del mensaje que sea aleatoria? Tampoco sirve, aunque ahora cada mensaje sea un grupo de bytes diferente, se puede reutilizar el mismo mensaje varias veces ya que el dispositivo no puede verificar su validez.

Lo mismo ocurre si el mensaje va firmado digitalmente. Nada impide al atacante copiar ese mensaje y reenviarlo.

El truco esta en usar una parte del mensaje que sea predecible y no repetible. Predecible para que el receptor del mensaje pueda saber que es correcto y no repetible para descartar los ya utilizados.

Para ello vamos a usar passwords de un solo uso (OTP) para saber más sobre el tema se puede ver en este articulo. En el articulo se emplea un contador o un timestamp dependiendo de que tipo de OTP se use, lo ideal seria usar TOTP. En nuestro caso eso da igual. No hay que olvidar que aquí estamos hablando de proyectos IoT lo cual limita técnicamente las soluciones que podemos adoptar.

Antes de ver posibles soluciones vamos a empezar explicando el concepto de “ventana de tiempo del ataque”, se podría definir como “tiempo durante el cual somos vulnerables al ataque”. En nuestro caso es el tiempo durante el que un mensaje capturado y reenviado por un atacante es considerado válido por nuestro dispositivo. Cuanto más pequeña sea esta ventana más seguros estaremos.

Volviendo a nuestro OTP tenemos: una función que lo calcula (OTP), un contador o timestamp (c) y un secreto compartido entre ambos dispositivos (k) y un comando o mensaje a enviar (msg). En lugar de calcular un token OTP con el contador uniremos el mensaje y el contador y calcularemos un OTP de ambos.

Token = OTP(msg+c, k)

Truco, si el mensaje es demasiado grande para procesarlo ya sea por memoria o por tiempo se puede usar cualquier función que lo resuma (una función hash o algo menos costoso), aunque hay que tener cuidado de que dos comandos distintos generen dos resúmenes diferentes.

Ahora enviamos el mensaje y el token para que el cliente pueda validarlo.

Si un tercero interceptara nuestro comando este solo le seria valido durante un breve periodo de tiempo.

Si queremos añadir un extra de seguridad podemos hacer que nuestro sistema no acepte dos veces el mismo comando durante un periodo de tiempo igualo mayor a la ventana de ataque.

En el esquema de debajo se puede ver como es el proceso, para calcular c se usa el timestamp (t) actual dividido por la ventana de tiempo (vt).

Un detalle a tener en cuanta es que nunca se ha hablado de cifrar la comunicación, este sistema es seguro aunque los mensajes se distribuyan de forma abierta.