Hola hacketones! Bienvenidos a un nuevo CTF de la ruta completa de Web Fundamentals, en este capítulo veremos: TryHackMe Race Conditions
Introducción
Supongamos que nos encargan probar la seguridad de una aplicación web de compras en línea. Surgen muchas preguntas. ¿Podemos reutilizar una tarjeta de regalo de $10 para pagar un artículo de $100? ¿Podemos aplicar el mismo descuento a nuestro carrito de compras varias veces? ¡La respuesta es quizás ! Si el sistema es susceptible a una vulnerabilidad de condición de carrera, podemos hacer todo esto y más.
Esta sala presenta la vulnerabilidad de las condiciones de carrera. Una condición de carrera es una situación en programas informáticos donde la sincronización de los eventos influye en el comportamiento y el resultado del programa. Suele ocurrir cuando varios subprocesos acceden y modifican una variable. Debido a la falta de mecanismos de bloqueo adecuados y de sincronización entre los diferentes subprocesos, un atacante podría abusar del sistema y aplicar un descuento varias veces o realizar transacciones monetarias que superen su saldo.
Objetivos de aprendizaje
Después de completar esta sala, aprenderá lo siguiente:
- Vulnerabilidad de las condiciones de carrera
- Uso de Burp Suite Repeater para aprovechar las condiciones de carrera
En el camino también aprenderás sobre:
- Subprocesos y multiproceso
- Diagramas de estados
Multi-hilo
En esta tarea, proporcionaremos una descripción general rápida de los siguientes términos:
- Programa
- Proceso
- Hilo
- Multihilo
Programas
Un programa es un conjunto de instrucciones para realizar una tarea específica. Es necesario ejecutarlo para lograr lo deseado. Si no se ejecuta, no hará nada y seguirá siendo un conjunto de instrucciones estáticas.
Piensa en ello como una receta; acabas de descargar una nueva receta de café que incluye diversas hierbas, como cardamomo y canela. Estas son las instrucciones:
1.Combine brewed coffee, cardamom, cinnamon, and cloves (if using) in a saucepan.
2.Heat the mixture over low heat for 5 minutes, stirring occasionally. Do not boil.
3.Strain the coffee into your mug.
4.Add milk if desired, and sweeten to taste with honey or sugar.
¡Si alguien no sigue las instrucciones anteriores, no se servirá café!
Compare esto con nuestro servidor mínimo de Flask (Python) «¡Hola, mundo!». El código a continuación indica que la aplicación escuchará en el puerto 8080 y responderá con una página HTML de saludo mínima que contiene «¡Hola, mundo!». Sin embargo, debemos ejecutar estas instrucciones (programa) antes de esperar recibir páginas de saludo.
Tenga en cuenta que el código de Flask que aparece a continuación se muestra solo con fines demostrativos. No proporcionamos un entorno para ejecutarlo, ya que está fuera del alcance de esta sala.

Procesos
Una tarde, decides probar una nueva receta de café que descargaste de internet. Empiezas a revisarla paso a paso. Estás en proceso de prepararla. Mientras sigues las instrucciones, podrías ser interrumpido por una llamada urgente. O podrías estar trabajando en otra tarea mientras esperas a que se caliente el agua. Las interrupciones y las esperas suelen ser inevitables. Seguir las instrucciones de la receta para preparar café es similar a ejecutar las instrucciones de un programa.
Un proceso es un programa en ejecución. En la literatura, es posible encontrar el término » trabajo» . Ambos términos se refieren a lo mismo, aunque el término «proceso» ha sustituido al término «trabajo». A diferencia de un programa, que es estático, un proceso es una entidad dinámica. Contiene varios aspectos clave, en particular:
- Programa : El código ejecutable relacionado con el proceso.
- Memoria : Almacenamiento temporal de datos
- Estado : Un proceso suele alternar entre diferentes estados. Tras estar en el estado Nuevo (recién creado), pasa al estado Listo (listo para ejecutarse una vez que la CPU le haya asignado tiempo). Una vez que la CPU le asigna tiempo, pasa al estado En ejecución. Además, puede estar en estado Esperando, pendiente de E/S o de la finalización de un evento. Al salir, pasa al estado Terminado.

Si ejecuta el código Flask anterior, se creará un proceso que escuchará las conexiones entrantes en el puerto 8080. En otras palabras, pasará la mayor parte del tiempo en estado de espera. Al recibir una GET /solicitud HTTP, pasará al estado de listo, esperando su turno para ejecutarse según la programación de la CPU . Una vez en estado de ejecución, envía la página HTML al cliente y regresa al estado de espera.
Desde la perspectiva del servidor, la aplicación atiende a los clientes secuencialmente; es decir, las solicitudes de los clientes se procesan una a una. (Tenga en cuenta que Flask es multiproceso por defecto desde la versión 1.0. Usamos el argumento –without-threadspara forzar su ejecución en un solo subproceso).
Tenga en cuenta que el comando Flask que se muestra a continuación es sólo para fines demostrativos.

Threads
¡Terminemos con otra analogía del café! Consideremos el caso de una máquina de espresso comercial en una cafetería. Digamos que tiene dos portafiltros. Al comenzar la jornada laboral, el barista enciende la máquina y, cada vez que un cliente pide un espresso, se usa un portafiltro para prepararle un espresso. ¿Otro cliente pide un espresso? ¡No hay problema, el segundo portafiltro al rescate! La máquina de espresso caliente es el proceso; a cada nuevo pedido se le asigna un portafiltro; esa es la analogía del hilo.
Un hilo es una unidad ligera de ejecución. Comparte varias partes de memoria e instrucciones con el proceso.
En muchos casos, necesitamos replicar el mismo proceso repetidamente. Imaginemos un servidor web que ofrece la misma página (o una página personalizada) a miles de usuarios. Podemos adoptar uno de dos enfoques principales:
- Serie: Un proceso se está ejecutando; atiende a un usuario tras otro secuencialmente. Los nuevos usuarios se ponen en cola.
- Paralelo: Un proceso se ejecuta y crea un hilo para atender a cada nuevo usuario. Los nuevos usuarios solo se ponen en cola cuando se alcanza el número máximo de hilos en ejecución.
La aplicación anterior puede ejecutarse con cuatro subprocesos usando Gunicorn. Gunicorn, también llamado «Unicornio Verde», es un servidor HTTP WSGI de Python . WSGI significa Interfaz de Puerta de Enlace de Servidor Web (Web Server Gateway Interface), que conecta servidores web con aplicaciones web de Python. En particular, Gunicorn puede generar múltiples procesos de trabajo para gestionar las solicitudes entrantes simultáneamente. Al ejecutar gunicorncon esta –workers=4opción, especificamos que queremos cuatro procesos de trabajo listos para atender las solicitudes de los clientes; además, –threads=2indica que cada proceso de trabajo puede generar dos subprocesos.
Tenga en cuenta que el comando Gunicorn que se muestra a continuación es solo para fines demostrativos. No proporcionamos un entorno para ejecutarlo, ya que está fuera del alcance de esta sala.

Vale la pena señalar lo siguiente:
- Es imposible ejecutar más de una copia de este proceso ya que está vinculado al puerto TCP 8080. Un puerto TCP o UDP solo puede estar vinculado a un proceso.
- El proceso se puede configurar con cualquier número de subprocesos y las solicitudes HTTP que lleguen al puerto 8080 se enviarán a los diferentes subprocesos.
Responda las preguntas a continuación
Descargaste un manual de instrucciones sobre cómo hacer una grulla de origami. ¿Cómo se vería este manual en términos informáticos?
- Program
¿Cuál es el nombre del estado en el que un proceso está esperando un evento de E/S?
Waiting
Condiciones de carrera
Analogía del mundo real
Imagine la siguiente situación. Llama a un restaurante para reservar una mesa para una comida de negocios crucial. Conoce el restaurante y su distribución. Una mesa en particular, la número 17, es su opción preferida, ya que tiene una vista agradable y está relativamente aislada. Llama para reservar la mesa 17; el anfitrión confirma que está libre, ya que no tiene la etiqueta «Reservado». Al mismo tiempo, otro cliente habla con otro anfitrión y reserva la misma mesa.
¿Quién reservó la mesa? Eso es una condición de carrera.
¿Por qué ocurrió esto? Esta desafortunada situación se produjo porque más de un anfitrión aceptaba reservas; además, el anfitrión tardó unos minutos en obtener la etiqueta «Reservado» y colocarla en la mesa después de actualizar el libro de reservas diario. Hay al menos un minuto de margen para que otro cliente reserve una mesa.
De manera similar, cuando un hilo verifica un valor para realizar una acción, otro hilo podría cambiar ese valor antes de que se realice la acción.
Ejemplo A
Consideremos este escenario:
- Una cuenta bancaria tiene $100.
- Dos hilos intentan retirar dinero al mismo tiempo.
- El hilo 1 verifica el saldo (ve $100) y retira $45.
- Antes de que el Hilo 1 actualice el saldo , el Hilo 2 también verifica el saldo (ve incorrectamente $100) y retira $35.
No podemos estar 100% seguros de qué hilo actualizará primero el saldo restante; sin embargo, supongamos que es el Hilo 1. Este hilo establecerá el saldo restante en $55. Posteriormente, el Hilo 2 podría establecerlo en $65 si no se gestiona adecuadamente. (El Hilo 2 calculó que $65 debían permanecer en la cuenta después del retiro, ya que el saldo era de $100 cuando lo revisó). En otras palabras, el usuario realizó dos retiros, pero el saldo de la cuenta se dedujo solo en el segundo, ¡por orden del Hilo 2!
Ejemplo B
Consideremos otro escenario:
- Una cuenta bancaria tiene $75.
- Dos hilos intentan retirar dinero al mismo tiempo.
- El hilo 1 verifica el saldo (ve $75) y retira $50.
- Antes de que el Hilo 1 actualice el saldo , el Hilo 2 verifica el saldo (ve incorrectamente $75) y retira $50.
El hilo 2 procederá con el retiro, aunque dicha transacción debería haber sido rechazada.
Los ejemplos A y B demuestran una vulnerabilidad de tiempo de verificación a tiempo de uso (TOCTOU).
Código de ejemplo
Considere el siguiente código Python con dos subprocesos que simulan la finalización de una tarea en incrementos del 10%.

Estos dos hilos comienzan juntos; solo imprimen un valor en pantalla. Por lo tanto, se esperaría que terminaran simultáneamente, o al menos que el resultado fuera consistente. Sin embargo, en el programa anterior, no se garantiza qué hilo terminará primero ni a qué hora. A continuación se muestra el resultado de la primera ejecución:

A continuación se muestra una segunda salida de ejecución:

Ejecutar este programa varias veces producirá resultados diferentes. En el primer intento, el hilo 2 alcanzó el 100 primero; sin embargo, en el segundo, el hilo 2 llegó al 100 en segundo lugar. No tenemos control sobre el resultado. Si la seguridad de nuestra aplicación depende de que un hilo finalice antes que el otro, necesitamos implementar mecanismos para garantizar una protección adecuada. Considere los dos ejemplos siguientes para comprender mejor la gravedad de los errores cuando dejamos las cosas al azar.
En AttackBox, puedes guardar el código Python anterior y ejecutarlo varias veces para observar el resultado. Por ejemplo, si lo guardaste como race.py, puedes ejecutar el script con el python race.pycomando.
Causas
Como vimos en el programa anterior, dos hilos modificaban la misma variable. Cada vez que se le asignaba tiempo de CPU, se apresuraba a incrementarlo xen 1. En consecuencia, estos dos hilos competían por incrementar la misma variable. Este programa muestra un ejemplo sencillo en un solo host.
En general, una causa común de las condiciones de carrera reside en los recursos compartidos. Por ejemplo, cuando varios subprocesos acceden y modifican simultáneamente los mismos datos compartidos. Ejemplos de datos compartidos son un registro de base de datos y una estructura de datos en memoria. Existen muchas causas sutiles, pero mencionaremos tres comunes:
- Ejecución paralela : Los servidores web pueden ejecutar múltiples solicitudes en paralelo para gestionar las interacciones simultáneas de los usuarios. Si estas solicitudes acceden y modifican recursos compartidos o estados de la aplicación sin una sincronización adecuada, pueden generar condiciones de carrera y comportamientos inesperados.
- Operaciones de base de datos : Las operaciones concurrentes de base de datos, como las secuencias de lectura-modificación-escritura, pueden generar condiciones de competencia. Por ejemplo, si dos usuarios intentan actualizar el mismo registro simultáneamente, podrían generar datos incoherentes o conflictos. La solución radica en implementar mecanismos de bloqueo adecuados y el aislamiento de transacciones.
- Bibliotecas y servicios de terceros : Hoy en día, las aplicaciones web suelen integrarse con bibliotecas, API y otros servicios de terceros. Si estos componentes externos no están diseñados para gestionar correctamente el acceso concurrente, pueden producirse condiciones de carrera cuando varias solicitudes u operaciones interactúan con ellos simultáneamente.
Responda las preguntas a continuación
¿El script de Python presentado garantiza qué hilo alcanzará el 100 % primero? (Sí/No)
Nay
En la segunda ejecución del script de Python, ¿cuál es el nombre del hilo que alcanzó el 100% primero?
Thread-1
Arquitectura de aplicaciones web
Visitemos la arquitectura de la aplicación web para explicar cómo son posibles las condiciones de carrera.
Modelo cliente-servidor
Las aplicaciones web siguen un modelo cliente-servidor:
- Cliente : El cliente es el programa o aplicación que inicia la solicitud de un servicio. Por ejemplo, cuando navegamos por una página web, nuestro navegador solicita la página (archivo) a un servidor web.
- Servidor : El servidor es el programa o sistema que proporciona estos servicios en respuesta a las solicitudes entrantes. Por ejemplo, el servidor web responde a una solicitud HTTP GET entrante y envía una página (o archivo) HTML al navegador web solicitante (cliente).
En términos generales, el modelo cliente-servidor se ejecuta en una red. El cliente envía su solicitud a través de la red y el servidor la recibe y la procesa antes de devolver el recurso requerido.
Aplicación web típica
Una aplicación web sigue una arquitectura multicapa. Esta arquitectura separa la lógica de la aplicación en diferentes capas o niveles. El diseño más común utiliza tres niveles:
- Capa de presentación : En las aplicaciones web, esta capa consiste en el navegador web del lado del cliente. El navegador web procesa el código HTML, CSS y JavaScript.
- Capa de aplicación : Esta capa contiene la lógica de negocio y la funcionalidad de la aplicación web. Recibe las solicitudes de los clientes, las procesa e interactúa con la capa de datos. Se implementa mediante lenguajes de programación del lado del servidor como Node.js y PHP , entre muchos otros.
- Nivel de datos : Este nivel se encarga de almacenar y manipular los datos de la aplicación. Las operaciones típicas de la base de datos incluyen la creación, actualización, eliminación y búsqueda de registros existentes. Esto suele lograrse mediante un sistema de gestión de bases de datos (SGBD); algunos ejemplos son MySQL y PostgreSQL.
Estados
Veamos algunos ejemplos de lógica de negocios antes de profundizar. Consideraremos los siguientes ejemplos:
- Validación y realización de transferencias de dinero
- Validar códigos de cupón y aplicar descuentos
Validación y realización de transferencias de dinero
Considere el ejemplo de transferir dinero a un amigo o a su otra cuenta. El programa se desarrollará de la siguiente manera:
- El usuario hace clic en el botón “Confirmar transferencia”
- La aplicación consulta la base de datos para confirmar que el saldo de la cuenta puede cubrir el monto de la transferencia.
- La base de datos responde a la consulta
- Si el monto está dentro de los límites de la cuenta, la aplicación realiza la transacción.
- Si el monto excede los límites de la cuenta, la aplicación muestra un mensaje de error

En un escenario ideal, el código anterior conduce a dos estados del programa:
- Cantidad no enviada
- Cantidad enviada
Validar códigos de cupón y aplicar descuentos
Consideremos el ejemplo de aplicar un cupón de descuento. El usuario accede a su carrito de compras y añade un cupón para obtener un descuento. Los pasos podrían ser similares a los siguientes:
- El usuario introduce un código de cupón
- La aplicación consulta la base de datos para determinar si el código de cupón es válido y si existen restricciones.
- La base de datos responde con validez y restricciones
- El descuento se aplica si el código es válido y no hay restricciones para aplicarlo a este usuario.
- Se muestra un mensaje de error si el código no es válido o existen restricciones para aplicarlo a este usuario.
El código anterior conduce a algunos estados del programa:
- Cupón no aplicado
- Cupón aplicado
¿Dos Estados? Piénsalo de nuevo
Continuemos nuestro análisis de la aplicación de un cupón de descuento. Idealmente, esperamos dos estados: Cupón no aplicado y Cupón aplicado . Sin embargo, esto es demasiado simplista para representar escenarios complejos. Podemos añadir un estado intermedio: Comprobando la aplicabilidad del cupón .

Dependiendo del desarrollo de la aplicación, podemos esperar más estados. Por ejemplo, » Comprobar la aplicabilidad del cupón» podría implicar dos estados: » Comprobar la validez del cupón» y «Comprobar las restricciones del cupón» . Un cupón podría ser válido, pero las restricciones existentes impiden su aplicación. De igual forma, «Cupón aplicado» podría dividirse en dos estados, uno de los cuales es «Recalculando el total» .

¿Por qué es esto importante para las condiciones de carrera?
En el diagrama de estados anterior, podemos ver que pasamos por varios estados antes de que el cupón se marque como aplicado. Dibujemos los estados en un eje de tiempo, como se muestra a continuación.

Existe un intervalo de tiempo entre el momento en que intentamos añadir un cupón y el momento en que se marca como aplicado y no se puede volver a aplicar. Mientras el cupón no esté marcado como aplicado, lo más probable es que ningún control impida que se acepte repetidamente. Es posible que podamos aplicarlo varias veces durante este intervalo.
Esta situación es similar al considerar los estados del programa que realiza una transferencia de dinero. Si bien idealmente serían dos estados, considerando la lógica de negocio, podemos actualizar fácilmente el diagrama para incluir tres. Esto se debe a que prevemos dedicar tiempo a revisar el saldo y los límites de la cuenta; aunque este tiempo puede ser breve, no es nulo. Si profundizamos, podemos descubrir más estados ocultos.

Sin embargo, incluso si la aplicación web es vulnerable, aún tenemos un desafío que superar: la sincronización. Incluso en aplicaciones vulnerables, esta «ventana de oportunidad» es relativamente corta; por lo tanto, para explotarla es necesario que nuestras solicitudes lleguen al servidor simultáneamente. En la práctica, nuestro objetivo es que nuestras solicitudes repetidas lleguen al servidor con solo milisegundos de diferencia.
¿Cómo podemos conseguir que nuestras solicitudes duplicadas lleguen al servidor en este breve periodo de tiempo? Necesitamos una herramienta como Burp Suite .
Responda las preguntas a continuación
¿Cuántos estados tenía el diagrama de estados original de “validación y realización de transferencias de dinero”?
2
¿Cuántos estados tenía el diagrama estatal actualizado de “validación y realización de transferencias de dinero”?
3
¿Cuántos estados tenía el diagrama final de estados de “validación de códigos de cupón y aplicación de descuentos”?
5
Explotación de las condiciones de carrera
Haga clic en el botón «Iniciar máquina» a la derecha para iniciar la máquina virtual conectada . Haga clic en el botón «Iniciar AttackBox» en la parte superior para iniciar AttackBox. En AttackBox, busque http://10.65.135.74:8080.
Estas son las credenciales para dos usuarios:
- Usuario1:07799991337
- Contraseña:pass1234
Y
- Usuario2:07113371111
- Contraseña:pass1234
Esta aplicación web pertenece a un operador móvil y permite la transferencia de saldo telefónico. En esta demostración, comprobaremos si el sistema es susceptible a una vulnerabilidad de condición de carrera e intentaremos explotarla transfiriendo más saldo del que tenemos en nuestra cuenta.
Primero, debemos explorar y estudiar cómo la aplicación web de destino recibe las solicitudes HTTP y cómo responde a ellas. Con Burp Suite Proxy , haga clic en «Abrir navegador» en la pestaña «Interceptar» . (Si recibe un mensaje de error sobre la activación del entorno aislado del navegador, debe cambiar la configuración manualmente. En este caso, haga clic en «Configuración» en la esquina superior derecha de la ventana de Burp Suite, haga clic en el navegador de Burp en » Herramientas » y marque la opción «Permitir que el navegador de Burp se ejecute sin un entorno aislado «). Con el navegador incluido, podemos explorar el sitio de destino y estudiar cómo procesa nuestras solicitudes HTTP, en particular las solicitudes HTTP y las respuestas relacionadas. La pestaña » Historial HTTP» registra cada solicitud HTTP y su respectiva respuesta.POST
Inicia sesión en cualquiera de las cuentas y haz clic en el botón «Pagar y recargar» . Para realizar una transferencia de crédito, haz clic en el botón «Transferir» e introduce el número de móvil de la otra cuenta junto con el importe que deseas transferir. Puedes intentar transferir una cantidad que supere tu saldo actual y una pequeña cantidad, como $1, para ver cómo responde el sistema en cada caso.
Burp Suite : Repetidor
En la imagen de abajo podemos ver:
- Una POSTsolicitud
- Los detalles muestran el número de teléfono de destino y un monto de transferencia de $1.5
- En la respuesta, podemos inferir que la transacción es exitosa.

Ahora que hemos visto cómo reacciona el sistema a solicitudes válidas e inválidas, veamos si podemos aprovechar una condición de carrera. Haga clic derecho en la POSTsolicitud que desea duplicar y seleccione «Enviar al repetidor» .

En la pestaña Repetidor , como se muestra en las capturas de pantalla numeradas a continuación:
- Haga clic en el +icono junto a la pestaña de solicitud recibida y seleccione Crear grupo de pestañas
- Asigne un nombre al grupo e incluya la pestaña de la solicitud que acaba de enviar al importador antes de hacer clic en Crear
- Haga clic derecho en la pestaña de solicitud y elija Duplicar pestaña (si esta opción no está disponible en su versión, puede presionar CTRL + R varias veces)
- Como punto de partida, lo duplicaremos 20 veces.
- Al lado del botón Enviar, la flecha que apunta hacia abajo traerá un menú para decidir cómo desea enviar las solicitudes duplicadas.


A continuación, explotaremos la aplicación de destino enviando la solicitud duplicada. Con las opciones integradas de Burp Suite Repeater, la flecha desplegable ofrece las siguientes opciones:
- Enviar grupo en secuencia ( conexión única )
- Enviar grupo en secuencia ( conexiones separadas )
- Enviar grupo en paralelo
Envío de grupo de solicitudes en secuencia
Enviar el grupo en secuencia ofrece dos opciones:
- Enviar grupo en secuencia ( conexión única )
- Enviar grupo en secuencia ( conexiones separadas )
Enviar grupo en secuencia a través de una única conexión
Esta opción establece una única conexión con el servidor y envía todas las solicitudes en las pestañas del grupo antes de cerrar la conexión. Esto puede ser útil para detectar posibles vulnerabilidades de desincronización del lado del cliente.
Enviar grupo en secuencia a través de conexiones separadas
Como sugiere el nombre, esta opción establece una conexión TCP, envía una solicitud desde el grupo y cierra la conexión TCP antes de repetir el proceso para la solicitud posterior.
Probamos esta opción para atacar la aplicación web. La siguiente captura de pantalla muestra 21 conexiones TCP para las diferentes solicitudes POST del grupo que enviamos.
- El primer grupo (marcado con el número 1) comprende cinco solicitudes exitosas. Pudimos confirmar su éxito al revisar las respuestas respectivas. Además, observamos que cada una tardó alrededor de 3 segundos, como lo indica la duración (marcada con el número 3).
- El segundo grupo (etiquetado como 2) muestra dieciséis solicitudes denegadas. La duración fue de aproximadamente cuatro milisegundos. También es interesante comprobar la hora de inicio relativa.

La siguiente captura de pantalla muestra la conexión TCP completa para una solicitud. Podemos confirmar que la POSTsolicitud se envió en un solo paquete.

Enviar grupo de solicitudes en paralelo
Al elegir enviar las solicitudes del grupo en paralelo, el repetidor enviaría todas las solicitudes del grupo a la vez. En este caso, observamos lo siguiente, como se muestra en la captura de pantalla a continuación:
- En la columna Inicio relativo, observamos que los 21 paquetes se enviaron dentro de una ventana de 0,5 milisegundos (etiquetada como 1).
- Las 21 solicitudes se completaron correctamente y se transfirió el crédito. Cada solicitud tardó aproximadamente 3,2 segundos en completarse (marcada como 2).

Al observar atentamente la captura de pantalla anterior, observamos que cada solicitud generó 12 paquetes; sin embargo, en el intento anterior (envío secuencial), observamos que cada solicitud solo requirió 10 paquetes. ¿Por qué ocurrió esto?
Según la documentación de Envío de Solicitudes HTTP Agrupadas , al enviar en paralelo, Repeater implementa diferentes técnicas para sincronizar la llegada de las solicitudes al destino, es decir, que lleguen en un plazo breve. La técnica de sincronización depende del protocolo HTTP utilizado:
- En el caso de HTTP/2+, el repetidor intenta enviar todo el grupo en un solo paquete. En otras palabras, un solo paquete TCP transportaría múltiples solicitudes.
- En el caso de HTTP/1, el repetidor recurre a la sincronización del último byte. Este truco se logra reteniendo el último byte de cada solicitud. Solo cuando se envían todos los paquetes sin el último byte, se envía el último byte de todas las solicitudes. La captura de pantalla a continuación muestra nuestra POSTsolicitud enviada en dos paquetes.


Responda las preguntas a continuación
Necesitas que cualquiera de las cuentas obtenga más de $100 de crédito para obtener la bandera. ¿Cuál es la bandera que obtuviste?
Detección y mitigación
Detección
Detectar condiciones de carrera desde la perspectiva del propietario de un negocio puede ser un desafío. Si varios usuarios canjearan la misma tarjeta de regalo varias veces, lo más probable es que pasara desapercibido a menos que se revisen activamente los registros para detectar ciertos comportamientos. Considerando que las condiciones de carrera pueden usarse para explotar vulnerabilidades aún más sutiles, es evidente que necesitamos la ayuda de expertos en pruebas de penetración y cazadores de recompensas de errores para intentar descubrir dichas vulnerabilidades e informar sobre sus hallazgos.
Los evaluadores de penetración deben comprender cómo se comporta el sistema en condiciones normales cuando se aplican controles forzados. Estos controles pueden ser: usar una vez, votar una vez, calificar una vez, limitar al saldo y limitar a uno cada 5 minutos, entre otros. El siguiente paso sería intentar eludir este límite aprovechando las condiciones de carrera. Determinar los diferentes estados del sistema puede ayudarnos a realizar estimaciones fundamentadas sobre las ventanas de tiempo en las que se puede explotar una condición de carrera. Herramientas como Burp Suite Repeater pueden ser un excelente punto de partida.
Mitigación
Enumeraremos algunas técnicas de mitigación.
- Mecanismos de sincronización : Los lenguajes de programación modernos ofrecen mecanismos de sincronización como bloqueos. Solo un hilo puede adquirir el bloqueo a la vez, lo que impide que otros accedan al recurso compartido hasta que se libere.
- Operaciones Atómicas : Las operaciones atómicas se refieren a unidades de ejecución indivisibles, un conjunto de instrucciones agrupadas y ejecutadas sin interrupción. Este enfoque garantiza que una operación pueda finalizar sin ser interrumpida por otro hilo.
- Transacciones de base de datos : Las transacciones agrupan múltiples operaciones de base de datos en una sola unidad. Por lo tanto, todas las operaciones dentro de la transacción se ejecutan correctamente o fallan como un grupo. Este enfoque garantiza la consistencia de los datos y evita las condiciones de carrera causadas por múltiples procesos que modifican la base de datos simultáneamente.
Aplicación web de desafío
En esta sala se presentaron las condiciones de carrera y diversas situaciones que provocan dichas vulnerabilidades. La complejidad del sistema y la dispersión geográfica pueden generar diversas situaciones imprevistas, incluyendo vulnerabilidades relacionadas con las condiciones de carrera. Para descubrir y explotar dichas condiciones, es fundamental observar primero cómo se comporta el sistema en condiciones normales y luego intentar averiguar cómo se comporta al explotar la sincronización. Con las herramientas disponibles actualmente, disponemos de numerosas técnicas para probar.
Desafío
Después de lo aprendido, es hora de intentar descubrir y explotar una condición de carrera sin guía.
Haga clic en el botón «Iniciar máquina» a la derecha para iniciar la máquina virtual conectada . Haga clic en el botón «Iniciar AttackBox» en la parte superior para iniciar AttackBox si aún no lo ha hecho. En AttackBox, busque http://10.66.153.10:5000.
Estas son las credenciales para los tres usuarios:
Nombre: Rasser Cond
- Nombre de usuario:4621
- Contraseña:blueApple
Nombre: Zavodni Stav
- Nombre de usuario:6282
- Contraseña:whiteHorse
Nombre: Warunki Wyscigu
- Nombre de usuario:9317
- Contraseña:greenOrange
Esta aplicación web pertenece a un banco y permite a los clientes transferir dinero en línea. Necesitas tener una cuenta con más de $1000 .
Para resolver un desafío de Race Condition (condiciones de carrera) en transferencias bancarias como el que muestras en Burp Suite, el problema suele ser que, aunque envíes las peticiones en paralelo, el servidor las procesa lo suficientemente rápido como para que el saldo se actualice correctamente entre una y otra.

Si estás enviando las peticiones y el saldo baja normalmente, puede ser por:
- Latencia de Red: Si no usas el «Single-packet attack», las peticiones llegan con milisegundos de diferencia, suficientes para que la base de datos se bloquee (locking) y procese una por una.
- Session Locking: Algunos servidores (como los basados en PHP con sesiones por defecto) bloquean la sesión del usuario hasta que termina una petición. Si esto ocurre, las peticiones se pondrán en fila (serie) obligatoriamente y el ataque fallará.
Tu Objetivo Técnico
Para superar los $1000, necesitas que el servidor acepte, por ejemplo, 50 transferencias de $50 simultáneas porque al momento de validar todas ellas, tu saldo original aún «parecía» suficiente.

Responda las preguntas a continuación
¿Qué bandera obtuviste luego de obtener un saldo de cuenta superior a $1000
THM{BANK-RED-FLAG}

Sigan entrenando, Hacketones, Nos vemos en el próximo laboratorio!!!