Race Conditions Lab 3
Skills
- Multi-endpoint race conditions
Certificaciones
- eWPT
- eWPTXv2
- OSWE
- BSCP
Descripción
Este laboratorio
tiene una race condition
en el flujo de compra
, lo que nos permite comprar artículos a un precio no intencionado
. Para resolver
el laboratorio
, tenemos que comprar
una chaqueta Lightweight L33t de cuero
. Podemos iniciar sesión
con las credenciales wiener:peter
Resolución
Al acceder
a la web
vemos esto
Si hacemos click sobre My account
nos podemos loguear con las credenciales wiener:peter
Después de iniciar sesión
vemos que tenemos 100 dólares
en la cuenta
Podemos añadir
un artículo
a la cesta
pulsando sobre View details > add to cart
. Si posteriormente pulsamos sobre la cesta podemos ver
el artículo añadido
Al comprar
la Gift Card
su código
para que podamos canjearlo
Si nos dirigimos a My account
vemos que podemos canjear
la Gift Card
Si en el apartado de Gift cards
canjeamos el código obtendremos 10 dólares
Las race condition
son un tipo común de vulnerabilidad
estrechamente relacionada con los fallos de lógica de negocio
. Ocurren cuando los sitios web
procesan solicitudes
de forma concurrente sin los mecanismos de protección
adecuados. Esto puede hacer que múltiples hilos
distintos interactúen con los mismos datos
al mismo tiempo, lo que resulta en una colisión
que provoca un comportamiento
no deseado en la aplicación
. Un ataque
de race condition
utiliza solicitudes
enviadas con una sincronización
precisa para causar colisiones
intencionadas y explotar
este comportamiento
no deseado con fines maliciosos
El período de tiempo
durante el cual una colisión
es posible se conoce como race window
. Esto podría ser la fracción de segundo
entre dos interacciones
con la base de datos
, por ejemplo
Al igual que otros fallos de lógica
, el impacto
de una race condition
depende en gran medida de la aplicación
y de la funcionalidad específica
en la que ocurra
En la práctica
, una sola solicitud
puede iniciar una secuencia
de múltiples pasos
, haciendo que la aplicación
pase por múltiples estados ocultos
a los que entra
y luego sale
antes de que se complete el procesamiento
de la solicitud
. Nos referimos a estos como subestados
Si identificamos
una o más solicitudes HTTP
que causan una interacción
con los mismos datos
, podemos abusar
de estos subestados
para exponer
variaciones sensibles al tiempo
, este tipo de fallos lógicos
son comunes
en los flujos de trabajo
que requieren múltiples pasos
. Esto permite explotaciones
de race condition
que van mucho más allá de simplemente exceder
algún tipo de límite
Por ejemplo, podemos estar familiarizados con los flujos de trabajo defectuosos
de la autenticación multifactor (MFA)
que nos permiten realizar
la primera parte
del inicio de sesión
utilizando credenciales conocidas
, y luego navegar directamente
a la aplicación
forzando la navegación, evitando
por completo la MFA
El siguiente pseudocódigo
demuestra cómo un sitio web
podría ser vulnerable
a una variación de condición de carrera
de este ataque
1
2
3
4
5
6
session['userid'] = user.userid
if user.mfa_enabled:
session['enforce_mfa'] = True
# generate and send MFA code to user
# redirect browser to MFA code entry form
Como podemos ver, esto es en realidad una secuencia de múltiples pasos
dentro del intervalo de una sola solicitud
. Lo más importante es que la aplicación
pasa por un subestado
en el que el usuario
tiene temporalmente una sesión iniciada válida
, pero la MFA
aún no se está aplicando
. Un atacante
podría explotar
esto enviando una solicitud
de inicio de sesión
junto con una solicitud
a un endpoint
que contenga información importante
, al estar autenticados podemos obtener información sensible
bypasseando el MFA
Como estas vulnerabilidades
son bastante específicas de cada aplicación
, es importante primero comprender
la metodología general
que debemos aplicar para identificarlas
de manera eficiente
Predecir colisiones potenciales
- Probar cada endpoint
no es práctico
. Después de mapear
el sitio objetivo
, podemos reducir
la cantidad de endpoints
que necesitamos probar haciéndonos las siguientes preguntas
¿Es este endpoint crítico para la seguridad?
- Muchosendpoints
no afectanfuncionalidades críticas
, por lo que no vale la penaprobarlos
¿Existe potencial de colisión?
- Para unacolisión exitosa
, generalmente se requierendos o más solicitudes
que desencadenenoperaciones
en el mismoregistro
Por ejemplo, consideremos las siguientes variaciones
de una implementación
de restablecimiento de contraseña
. Con el primer ejemplo
, solicitar un restablecimiento de contraseña
en paralelo
para dos usuarios diferentes
es poco probable
que cause una colisión
, ya que son cambios en dos registros
diferentes. Sin embargo, la segunda implementación
permite editar
el mismo registro
con solicitudes para dos usuarios
diferentes
Buscar pistas
- Para reconocer pistas
, primero debemos medir
cómo se comporta el endpoint
bajo condiciones normales
. Podemos hacer esto desde el Repeater
agrupando todas las solicitudes
y utilizando la opción Send group in sequence (separate connections)
, en este tipo de solicitud el Repeater
establece una conexión
con el objetivo, envía la solicitud
desde la primera pestaña
, y luego cierra la conexión
y repite
este proceso
para todas
las demás pestañas
en el orden
en que están dispuestas
en el grupo
. Enviar las solicitudes a través de separate connections
facilita testear vulnerabilidades
que requieren de múltiples pasos
En el caso de Send group in sequence (single connection)
el Repeater
establece una conexión
con el objetivo
, envía las solicitudes
de todas las pestañas
en el grupo
y luego cierra
la conexión
Enviar solicitudes a través de una única conexión
te permite probar posibles vectores de desincronización
del lado del cliente
. También reduce el jitter
que puede ocurrir al establecer conexiones TCP
. Esto es útil para ataques basados en tiempo
que dependen de poder comparar respuestas
con diferencias muy pequeñas
en los tiempos de respuesta
Para enviar
una secuencia
de solicitudes
, el grupo
debe cumplir
con los siguientes criterios
No debe haber ninguna
pestaña
demensaje WebSocket
en el grupoNo debe haber ninguna
pestaña vacía
en el grupo
Existen algunos criterios adicionales
para enviar
a través de una única conexión
Todas las
pestañas
deben tener el mismoobjetivo
Todas las
pestañas
deben usar la mismaversión de HTTP
, es decir, deben usar todasHTTP/1
o todasHTTP/2
En el caso de las solicitudes en paralelo
, el Repeater
envía las solicitudes
de todas las pestañas del grupo
a la vez. Esto resulta útil para identificar
y explotar
las race conditions
El Repeater
sincroniza las solicitudes en parelelo
para garantizar que todas lleguen completas
y simultáneamente
. Utiliza diferentes técnicas de sincronización
según la versión HTTP
utilizada
Al enviar por
HTTP/1
, elRepeater
utiliza la técnica delast-byte sync
. En este caso, se envían variassolicitudes
a través deconexiones simultáneas
, pero se retiene elúltimo byte
de cadasolicitud del grupo
. Tras un breveretraso
, estosúltimos bytes
se envíansimultáneamente
por cadaconexión
Al enviar mediante
HTTP/2+
, elRepeater
envía elgrupo
mediante unsingle-packet attack
. En este caso, se envíanmúltiples solicitudes
mediante unsolo paquete TCP
Cuando seleccionamos
una pestaña
que contiene una respuesta
a una solicitud en pararelo
, un indicador
en la esquina inferior derecha
muestra el orden
en que se recibió
esa respuesta
dentro del grupo
(por ejemplo, 1/3
, 2/3
)
Debemos tener en cuenta que no se pueden enviar solicitudes en paralelo
usando macros
. Esto se hace para evitar
que las macros
interfieran con la sincronización de solicitudes
Para enviar un grupo de solicitudes
en paralelo
, el grupo
debe cumplir dos criterios
Todas las
solicitudes del grupo
deben utilizar los mismosprotocolos de host
,puerto
ycapa de transporte
No se debe habilitar
HTTP/1 keep-alive
para elproyecto
Una vez aclarado esto, el siguiente paso es enviar el mismo grupo de solicitudes a la vez utilizando el single-packet attack
o last-byte sync
si la web no soporta HTTP/2
para minimizar la network jitter
. Podemos hacer esto desde el Repeater
seleccionando la opción Send group in pararell (single-packet attack)
. Alternativamente, podemos usar la extensión Turbo Intruder
Cualquier cosa puede ser una pista
. Solo debemos buscar alguna forma de desviación
de lo que observamos durante el benchmarking
. Esto incluye un cambio en una o más respuestas
, pero no debemos olvidar los efectos de segundo orden
, como diferentes contenidos de correo electrónico
o un cambio visible en el comportamiento de la aplicación después del ataque
Prueba el concepto
- Debemos tratar de entender lo que está ocurriendo
, eliminar las solicitudes superfluas
y asegurarnos de que podemos replicar los efectos
después de eliminarlas
Las advanced race conditions
pueden causar comportamientos inusuales y únicos
, por lo que la forma para obtener el máximo impacto
no siempre es obvia de inmediato. Puede ayudar, pensar que cada race condition
es como una debilidad estructural
,en lugar de una vulnerabilidad aislada
Quizá la forma más intuitiva
de race conditions
son aquellas que implican enviar solicitudes
a múltiples endpoints
al mismo tiempo
, a este tipo de race condition
se llama multi-endpoint race condition
. Por ejemplo, estamos comprando
en una tienda online
, añadimos un artículo
al carrito
y posteriormente pagamos ese artículo
, pero antes de que la página de confirmación del pedido
se cargue por completo, rápidamente añadimos otro artículo al carrito
y forzamos la navegación
a la página de confirmación
. En este escenario, podríamos encontrarnos con una race condition
donde el sistema
no ha terminado
de procesar
el primer pago
antes de que intentemos añadir
el segundo artículo
. Podemos aprovechar esto
, por ejemplo, para obtener más productos a un precio menor del estipulado
Una variación de esta vulnerabilidad
puede ocurrir cuando la validación de pago
y la confirmación del pedido
se realizan durante el procesamiento de una única petición
. El diagrama de estado
para el estado del pedido
podría ser similar a este, en este caso, podemos añadir más artículos
a nuestro carrito
durante la race window
, es decir, el momento entre que se valida
el pago
y cuando el pedido
se confirma
Al probar las multi-endpoint race conditions
, podríamos encontrar problemas al intentar alinear
las race window
para cada solicitud
, incluso si las enviamos todas al mismo tiempo
utilizando un single-packet attack
Este problema común
es causado principalmente por los siguientes dos factores
Retrasos introducidos por la arquitectura de red
- Por ejemplo, puede haber un retraso cada vez que elfront-end
establece una nuevaconexión
con elback-end
. Elprotocolo
utilizado también puede tener un gran impactoRetrasos introducidos por el procesamiento específico del endpoint
- Lostiempos de procesamiento
de losendpoints
varían , a veces de manera significativa, dependiendo de lasoperaciones
que desencadenan
Afortunadamente, existen posibles soluciones alternativas
para ambos problemas
Connection warming
- El delay
en las conexiones del back-end
normalmente no interfieren
con los race condition attacks
porque generalmente retrasan las solicitudes
de manera equivalente
, por lo que las solicitudes
permanecen sincronizadas
Es esencial
poder distinguir
este tipo de delays
de aquellos causados por factores específicos
del endpoint
. Una forma de hacerlo es "calentando"
la conexión
con una o más solicitudes
sin importancia
para ver si esto reduce
los tiempos de procesamiento
de las solicitudes
. Desde Repeater
, podemos intentar agregar
una solicitud GET
para la pestaña de login
de nuestro grupo
y luego usar la opción Send group in sequence (single connection)
Si la primera solicitud
aún tiene un tiempo de procesamiento
más largo
, pero el resto de las solicitudes ahora se procesan dentro de corto período de tiempo
, podemos ignorar
el retraso
aparente y continuar testeando
de manera normal
Si aún vemos tiempos de respuesta inconsistentes
en un endpoint
, incluso usando un single-packet attack
, esto es una indicación de que el delay
en la respuesta
del back-end
está interfiriendo con nuestro ataque
. Podemos ser capaces de sortear esto utilizando la extensión Turbo Intruder
para enviar algunas solicitudes de "calentamiento"
de conexión
antes de seguir con las solicitudes principales de nuestro ataque
Abusing rate or resource limits
- Si el connection warming
no funciona, existen varias soluciones a este problema. Podemos usar el Turbo Intruder
para provocar un delay
en el front-end
, sin embargo, como esto implica dividir
las solicitudes
del ataque
en varios paquetes TCP
no podremos usar la técnica del single-packet attack
. Como resultado, es poco probable que el ataque
funcione correctamente en los objetivos
que tengan un delay altamente variable (jitter)
, sin importar el delay
que le configuremos al front-end
En su lugar, podemos solucionar
este problema
si nos aprovechamos de una característica de seguridad común
Lo primero que debemos saber es que es el rate limit
y el resource limit
Rate limit
- Es unmecanismo
deseguridad
querestringe
lacantidad
desolicitudes
que uncliente
puedeenviar
a unservidor
en unperíodo
detiempo
determinado. Si seexcede
estelímite
, el servidor puederetrasar
orechazar
lassolicitudes adicionales
Resource limit
- Son lasrestricciones
queimpone
unservidor
paraevitar
que se leagoten
losrecursos
(como memoria, CPU o conexiones) cuandose reciben demasiadas solicitudes
Los servidores web
a menudo retrasan
el procesamiento de solicitudes
si se envían demasiadas demasiado rápido
. Al enviar una gran cantidad
de solicitudes
para activar
intencionalmente el rate limit
o el resource limit
, podemos ser capaces de causar la cantidad de delay
necesario en el back-end
. Esto hace que el single-packet attack
sea viable incluso cuando se requiere que se ejecute
con delay
Una vez sabemos esto vamos a capturar varias peticiones
y mandarlas
al Repeater
, la primera
va ser la de añadir el artículo Lightweight "l33t" Leather Jacket a la cesta
y la segunda
va a ser la de Place order
Pinchamos
sobre los tres puntos
y creamos
un grupo
pulsando en Create tab group
El orden
de las peticiones
tiene que ser este. Primero
tenemos que añadir
el artículo Gift Card
a la cesta
, lo cual lo tenemos que hacer desde fuera del grupo
, podemos hacerlo desde el Repeater
o manualmente
desde la web
. Posteriormente
tenemos que comprarlo
y mientras que se procesa la orden de compra
debemos añadir
el artículo Lightweight "l33t" Leather Jacket
a la cesta
para que no se nos cobre este último artículo
Vamos a enviar todas las peticiones en grupo
usando la opción Send group in sequence (single connection)
, usamos esta opción porque la posible race condition
se va a dar en una misma sesión
debido a que estamos logueados
. Esto se hace para saber si hay algún delay entre las peticiones
En la parte inferior derecha
podemos ver el delay
de las peticiones
. Vemos que hay bastante diferencia
entre los delays
de las diferentes peticiones
Para solucionar
este problema
vamos emplear una la técnica connection warming
, así que para ello vamos a añadir
al grupo una petición al directorio raíz /
de la web
. Es importante
que esta petición
este al principio
del grupo
Testeamos
la race condicion
nuevamente con Send group in sequence (single connection)
En este caso, la diferencia de delay
es menor
que en el caso anterior
Añadimos
la Gift Card
a la cesta
, ya sea desde el Repeater pero fuera del grupo
o de forma manual desde la web
Una vez hecho esto, seleccionamos la opción Send group in parallel (single-packet attack)
y efectuamos un single-packet attack
. Aunque las condiciones
sean aparentemente idóneas
puede ser que tengamos que ejecutar
el ataque
varias veces para que funcione
Si renderizamos
la respuesta
vemos que la orden de compra
se ha llevado a cabo con éxito
Aunque funciona correctamente de esta forma, he obtenido mayor porcentaje de éxito
si añado
otra Gift Card
en la race condition
. Es decir, Añadimos
una Gift Card
a la cesta
, ya sea desde el Repeater pero fuera del grupo
o de forma manual desde la web
y posteriormente añadimos otra
mediante la race condition