¿Qué son las Race conditions ?
Las race conditions, o condiciones de carrera, representan una vulnerabilidad que surge cuando el comportamiento de un sistema depende del orden o la sincronización de múltiples operaciones concurrentes. Esto ocurre cuando el servidor procesa peticiones simultáneamente sin implementar los mecanismos de protección adecuados (safeguards), lo que puede derivar en inconsistencias, errores inesperados o incluso fallos críticos en la seguridad del sistema.
Todo esto se sucede cuando hay ausencia de mecanismos adecuados de control y estas operaciones pueden interferir entre sí, provocando comportamientos inesperados, errores o incluso fallos críticos en la seguridad y estabilidad del sistema.
Este tipo de vulnerabilidad es especialmente común en entornos multihilo o sistemas distribuidos, donde múltiples procesos acceden simultáneamente a recursos compartidos sin las garantías necesarias de consistencia y control.Vamos a poner un ejemplo para que se entienda mejor.
En una aplicación bancaria, si dos usuarios intentan transferir fondos desde la misma cuenta al mismo tiempo y no existe una sincronización adecuada, el saldo final podría quedar desactualizado o ser incorrecto. Esta vulnerabilidad puede ser aprovechada por atacantes para obtener beneficios ilícitos o comprometer la integridad del sistema.
Otro concepto que es importante conocer es el de la Race Window.
La Race Window es el breve espacio de tiempo en el que pueden ocurrir colisiones o interferencias entre operaciones concurrentes. Durante este periodo, que puede durar sólo fracciones de segundo, múltiples interacciones, como consultas o modificaciones a una base de datos, pueden ejecutarse sin la sincronización adecuada. Esto abre la puerta a condiciones de carrera y posibles problemas de seguridad.
El ataque puede que no funcione o sea exitoso en el primer intento, ya que sincronizar múltiples solicitudes dentro de la race window es un proceso complejo. Por ello, es necesario intentarlo varias veces hasta lograr que las solicitudes se ejecuten en el momento preciso para explotar la vulnerabilidad.
Explotación en HTTP/1 y HTTP/2
Las aplicaciones web que utilizan los protocolos HTTP/1 y HTTP/2 pueden ser particularmente vulnerables a las condiciones de carrera.
En HTTP/1, las solicitudes se manejan de forma secuencial. A primera vista, ésto podría parecer una ventaja en términos de seguridad, ya que cada solicitud se procesa en orden y no hay concurrencia directa. Sin embargo, un atacante puede aprovechar esta vulnerabilidad enviando varias solicitudes en un corto período de tiempo.
El problema radica en que, aunque las solicitudes se ejecutan una tras otra, el servidor podría no actualizar su estado lo suficientemente rápido entre una solicitud y otra. Esto abre la puerta a ataques que aprovechan estos estados intermedios, lo que puede llevar a comportamientos inesperados o a la filtración de información sensible. En escenarios vulnerables, un atacante podría modificar datos en una solicitud y, antes de que el servidor refleje completamente el cambio, enviar otra solicitud que aproveche el estado inconsistente.
El HTTP/2, que introdujo, la multiplexión de solicitudes, una mejora clave para el rendimiento. Esta característica permite que múltiples solicitudes y respuestas viajen simultáneamente por una sola conexión TCP, eliminando el bloqueo de cabecera de línea (head-of-line blocking) y reduciendo la latencia. No obstante, esta mejora en eficiencia también amplía la superficie de ataque.
Al permitir una mayor concurrencia, HTTP/2 facilita que los atacantes diseñen escenarios en los que varias solicitudes se procesen simultáneamente. Esto aumenta las posibilidades de explotar condiciones de carrera, ya que el servidor puede verse obligado a manejar estados inconsistentes cuando procesa múltiples solicitudes en paralelo. Un atacante podría, por ejemplo, aprovecharse de esta simultaneidad para modificar datos críticos antes de que otra solicitud los valide o los utilice en una operación sensible.
Tipos Comunes de Ataques Basados en Condiciones de Carrera
▪️ Explotación de Límites (Limit Overrun)
El limit overrun ocurre cuando un atacante fuerza un sistema a procesar más solicitudes, datos o recursos de los que está diseñado para manejar. Por ejemplo, si una aplicación permite que cada usuario canjee un cupón sólo una vez, un atacante podría explotar esta lógica enviando múltiples solicitudes simultáneamente, logrando utilizar el cupón varias veces antes de que la base de datos actualice la información.▪️ Evasión de Secuencias de Autenticación (Hidden Multi-Step Sequences)
En sistemas que requieren varios pasos consecutivos, como la autenticación multifactor, los atacantes pueden aprovechar fallos en el proceso entre un paso y otro. Por ejemplo, en un sistema que envía un código de verificación al móvil, un atacante podría explotar el tiempo en que el sistema aún no ha validado la información para intentar saltarse parte del procedimiento de seguridad.▪️ Condiciones de Carrera en Múltiples Puntos de Acceso (Multi-Endpoint Race Conditions)
Cuando diferentes puntos finales (endpoints) interactúan con los mismos recursos compartidos sin sincronización adecuada, los atacantes pueden manipular datos o eludir restricciones. Un ejemplo común es cuando APIs distintas permiten modificar el mismo recurso sin control centralizado.
Un ejemplo de ésto podría ser el añadir productos a la cesta después de consultar el saldo disponible en la cuenta.
▪️ Condiciones de Carrera en un único Punto de Acceso (Single-Endpoint Race Conditions)
Estas ocurren cuando múltiples solicitudes se envían simultáneamente a un mismo punto de acceso, como una página web o un endpoint de API. Se produce por ejemplo en un mecanismo de restablecimiento de contraseña donde se envían dos solicitudes paralelas con diferentes usuarios, lo que podría permitir a un atacante obtener un token de restablecimiento válido para una cuenta ajena. Otro ejemplo, cuando dos solicitudes simultáneas para modificar un recurso compartido pueden sobrescribir los cambios del otro proceso.
▪️ Ataques Basados en Condiciones Temporales (Time-of-Check to Time-of-Use - TOCTOU)
Los ataques TOCTOU (Time of Check to Time of Use) explotan la ventana temporal entre la verificación y el uso de un recurso. Vamos a poner un ejemplo para que se entienda mejor, imaginemos una aplicación verifica permisos antes de abrir un archivo, un atacante podría reemplazar ese archivo antes de que se complete la operación.
Mitigaciones y Buenas Prácticas para Prevenir Condiciones de Carrera (Race Conditions)
Para mitigar o prevenir esta vulnerabilidad se debe tener en cuenta lo siguiente:
▪️ Control de Acceso a Recursos Compartidos:
En lugar de permitir que varios procesos modifiquen datos al mismo tiempo, se debe implementar mecanismos que con un único proceso puedan acceder al recurso en un momento dado.
Un ejemplo de ello es poner una fila de espera para que cada proceso espere su turno antes de modificar los datos.
▪️ Zonas Protegidas del Código (Regiones Críticas):
Se identifican partes del código donde sólo un proceso a la vez puede modificar información. Si otro proceso intenta acceder a esa parte del código mientras ya está en uso, debe esperar hasta que el primero termine.
▪️ Sistemas de Confirmación de Cambios (Memoria Transaccional):
En lugar de modificar los datos directamente, los cambios se realizan de manera provisional y sólo se aplican si no hubo interferencia con otro proceso al mismo tiempo. Si hay conflicto, los cambios se revierten y se intenta nuevamente.
▪️ Uso de Variables con Protección Especial:
Existen variables diseñadas para garantizar que, cuando se modifican, no haya interrupciones de otros procesos.
Es como un interruptor eléctrico: cuando un proceso lo cambia, no puede ser cambiado por otro hasta que el primero haya terminado. Esto evita que dos procesos intenten modificar la misma información al mismo tiempo.
▪️ Control en Bases de Datos:
Para sistemas que manejan información almacenada, es clave usar niveles de seguridad en las transacciones para evitar que dos procesos alteren datos al mismo tiempo de forma incorrecta.
Se pueden aplicar reglas como "esperar antes de escribir si alguien más está leyendo" para evitar conflictos.
La clave aquí está que para evitar condiciones de carrera es importante organizar bien el acceso a los datos compartidos, asegurando que cada proceso espere su turno o tenga su propia copia de la información cuando sea posible.
Referencias:
Todas las imágenes se han obtenido de:
https://portswigger.net/web-security/race-conditions