# Condição de Corrida
\
Use [**Trickest**](https://trickest.com/?utm\_campaign=hacktrics\&utm\_medium=banner\&utm\_source=hacktricks) para construir e **automatizar fluxos de trabalho** com as ferramentas comunitárias **mais avançadas** do mundo.\
Obtenha Acesso Hoje:
{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}
Aprenda a hackear AWS do zero ao herói comhtARTE (HackTricks AWS Red Team Expert)!
Outras formas de apoiar o HackTricks:
* Se você quer ver sua **empresa anunciada no HackTricks** ou **baixar o HackTricks em PDF**, confira os [**PLANOS DE ASSINATURA**](https://github.com/sponsors/carlospolop)!
* Adquira o [**material oficial PEASS & HackTricks**](https://peass.creator-spring.com)
* Descubra [**A Família PEASS**](https://opensea.io/collection/the-peass-family), nossa coleção de [**NFTs**](https://opensea.io/collection/the-peass-family) exclusivos
* **Junte-se ao grupo** 💬 [**Discord**](https://discord.gg/hRep4RUj7f) ou ao grupo [**telegram**](https://t.me/peass) ou **siga-me** no **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/carlospolopm)**.**
* **Compartilhe suas técnicas de hacking enviando PRs para os repositórios do GitHub** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud).
## Explorando RC
O principal problema ao abusar de RCs é que você precisa que as solicitações sejam processadas em paralelo com uma diferença de tempo muito curta (geralmente >1ms). Na seção a seguir, diferentes soluções são propostas para tornar isso possível.
### Ataque de pacote único (HTTP/2) / Sincronização do último byte (HTTP/1.1)
HTTP2 permite enviar **2 solicitações em uma única conexão TCP** (enquanto no HTTP/1.1 elas têm que ser sequenciais).\
O uso de um único pacote TCP **elimina completamente o efeito da variação de rede**, então isso claramente tem potencial para ataques de condição de corrida também. No entanto, **duas solicitações não são suficientes para um ataque de corrida confiável** devido à **variação do lado do servidor** - variações no tempo de processamento de solicitações da aplicação causadas por variáveis incontroláveis como a contenção de CPU.
Mas, usando a técnica de '**sincronização do último byte**' do HTTP/1.1, é possível pré-enviar a maior parte dos dados retendo um pequeno fragmento de cada solicitação e depois 'completar' **20-30 solicitações com um único pacote TCP**.
Para **pré-enviar a maior parte de cada solicitação**:
* Se a solicitação não tem corpo, envie todos os cabeçalhos, mas não defina a flag END\_STREAM. Retenha um quadro de dados vazio com a flag END\_STREAM definida.
* Se a solicitação tem um corpo, envie os cabeçalhos e todos os dados do corpo exceto o último byte e a flag END\_STREAM. Retenha um quadro de dados contendo o último byte.
Em seguida, **prepare-se para enviar os quadros finais**:
* Espere por 100ms para garantir que os quadros iniciais foram enviados.
* Garanta que TCP\_NODELAY está desativado - é crucial que o algoritmo de Nagle agrupe os quadros finais.
* Envie um pacote ping para aquecer a conexão local. Se você não fizer isso, a pilha de rede do SO colocará o primeiro quadro final em um pacote separado.
Finalmente, envie os quadros retidos. Você deve ser capaz de verificar que eles chegaram em um único pacote usando o Wireshark.
{% hint style="info" %}
Note que **não funciona para arquivos estáticos** em certos servidores, mas arquivos estáticos são irrelevantes para ataques de RC.
{% endhint %}
Usando essa técnica, você pode fazer com que 20-30 solicitações cheguem ao servidor simultaneamente - independentemente da variação de rede:
**Adaptando-se à arquitetura alvo**
Vale ressaltar que muitas aplicações estão por trás de um servidor frontal, e estes podem decidir encaminhar algumas solicitações por conexões existentes para o back-end, e criar novas conexões para outras.
Como resultado, é importante não atribuir inconsistências no tempo das solicitações ao comportamento da aplicação, como mecanismos de bloqueio que permitem apenas um único thread acessar um recurso por vez. Além disso, o roteamento de solicitações front-end é frequentemente feito com base em cada conexão, então você pode ser capaz de uniformizar o tempo das solicitações realizando um aquecimento de conexão do lado do servidor - **enviando algumas solicitações inconsequentes pela sua conexão antes de realizar o ataque** (isso é apenas enviar várias solicitações antes de começar o ataque real).
#### Mecanismos de bloqueio baseados em sessão
Alguns frameworks tentam prevenir a corrupção acidental de dados usando alguma forma de **bloqueio de solicitação**. Por exemplo, o módulo de **manipulador de sessão nativo do PHP** processa apenas **uma solicitação por sessão por vez**.
É extremamente importante identificar esse tipo de comportamento, pois ele pode mascarar vulnerabilidades trivialmente exploráveis. Se você notar que todas as suas solicitações estão sendo processadas sequencialmente, tente enviar cada uma delas usando um token de sessão diferente.
#### **Abusando de limites de taxa ou recursos**
Se o aquecimento de conexão não fizer diferença, existem várias soluções para esse problema.
Usando o Turbo Intruder, você pode introduzir um curto atraso do lado do cliente. No entanto, como isso envolve dividir suas solicitações de ataque reais em vários pacotes TCP, você não poderá usar a técnica de ataque de pacote único. Como resultado, em alvos com alta variação de rede, o ataque é improvável de funcionar de forma confiável, independentemente do atraso que você definir.
Em vez disso, você pode ser capaz de resolver esse problema abusando de um recurso de segurança comum.
Servidores web frequentemente **atrasam o processamento de solicitações se muitas forem enviadas rapidamente**. Ao enviar um grande número de solicitações fictícias para acionar intencionalmente o limite de taxa ou recursos, você pode ser capaz de causar um atraso adequado do lado do servidor. Isso torna o ataque de pacote único viável mesmo quando a execução atrasada é necessária.
{% hint style="warning" %}
Para mais informações sobre essa técnica, confira o relatório original em [https://portswigger.net/research/smashing-the-state-machine](https://portswigger.net/research/smashing-the-state-machine)
{% endhint %}
#### Exemplos de Ataque
* **Tubo Intruder - Ataque de pacote único HTTP2 (1 endpoint)**: Você pode enviar a solicitação para o **Turbo Intruder** (`Extensões` -> `Turbo Intruder` -> `Enviar para Turbo Intruder`), você pode alterar na solicitação o valor que deseja forçar bruta para **`%s`** como em `csrf=Bn9VQB8OyefIs3ShR2fPESR0FzzulI1d&username=carlos&password=%s` e depois selecionar o **`examples/race-single-packer-attack.py`** no menu suspenso:
Se você for **enviar valores diferentes**, você poderia modificar o código com este que usa uma lista de palavras da área de transferência:
```python
passwords = wordlists.clipboard
for password in passwords:
engine.queue(target.req, password, gate='race1')
```
{% hint style="warning" %}
Se a web não suportar HTTP2 (apenas HTTP1.1) use `Engine.THREADED` ou `Engine.BURP` em vez de `Engine.BURP2`.
{% endhint %}
* **Tubo Intruder - Ataque de pacote único HTTP2 (Vários endpoints)**: Caso precise enviar uma solicitação para 1 endpoint e depois várias para outros endpoints para acionar o RCE, você pode alterar o script `race-single-packet-attack.py` com algo como:
```python
def queueRequests(target, wordlists):
engine = RequestEngine(endpoint=target.endpoint,
concurrentConnections=1,
engine=Engine.BURP2
)
# Hardcode the second request for the RC
confirmationReq = '''POST /confirm?token[]= HTTP/2
Host: 0a9c00370490e77e837419c4005900d0.web-security-academy.net
Cookie: phpsessionid=MpDEOYRvaNT1OAm0OtAsmLZ91iDfISLU
Content-Length: 0
'''
# For each attempt (20 in total) send 50 confirmation requests.
for attempt in range(20):
currentAttempt = str(attempt)
username = 'aUser' + currentAttempt
# queue a single registration request
engine.queue(target.req, username, gate=currentAttempt)
# queue 50 confirmation requests - note that this will probably sent in two separate packets
for i in range(50):
engine.queue(confirmationReq, gate=currentAttempt)
# send all the queued requests for this attempt
engine.openGate(currentAttempt)
```
* Também está disponível no **Repeater** através da nova opção '**Enviar grupo em paralelo**' no Burp Suite.
* Para **limit-overrun**, você poderia simplesmente adicionar **o mesmo pedido 50 vezes** no grupo.
* Para **aquecimento de conexão**, você poderia **adicionar** no **início** do **grupo** alguns **pedidos** para alguma parte não estática do servidor web.
* Para **atrasar** o processo **entre** o processamento **de um pedido e outro** em 2 etapas de subestados, você poderia **adicionar pedidos extras entre** ambos os pedidos.
* Para um RC **multi-endpoint**, você poderia começar enviando o **pedido** que **vai para o estado oculto** e depois **50 pedidos** logo após ele que **exploram o estado oculto**.
### BF Bruto
Antes da pesquisa anterior, estes eram alguns payloads usados que apenas tentavam enviar os pacotes o mais rápido possível para causar um RC.
* **Repeater:** Verifique os exemplos da seção anterior.
* **Intruder**: Envie o **pedido** para o **Intruder**, defina o **número de threads** para **30** dentro do menu **Opções e,** selecione como payload **Null payloads** e gere **30.**
* **Turbo Intruder**
```python
def queueRequests(target, wordlists):
engine = RequestEngine(endpoint=target.endpoint,
concurrentConnections=5,
requestsPerConnection=1,
pipeline=False
)
a = ['Session=','Session=','Session=']
for i in range(len(a)):
engine.queue(target.req,a[i], gate='race1')
# open TCP connections and send partial requests
engine.start(timeout=10)
engine.openGate('race1')
engine.complete(timeout=60)
def handleResponse(req, interesting):
table.add(req)
```
* **Python - asyncio**
```python
import asyncio
import httpx
async def use_code(client):
resp = await client.post(f'http://victim.com', cookies={"session": "asdasdasd"}, data={"code": "123123123"})
return resp.text
async def main():
async with httpx.AsyncClient() as client:
tasks = []
for _ in range(20): #20 times
tasks.append(asyncio.ensure_future(use_code(client)))
# Get responses
results = await asyncio.gather(*tasks, return_exceptions=True)
# Print results
for r in results:
print(r)
# Async2sync sleep
await asyncio.sleep(0.5)
print(results)
asyncio.run(main())
```
## **Metodologia RC**
### Excedente de limite / TOCTOU
Este é o tipo mais básico de condição de corrida onde **vulnerabilidades** que **aparecem** em locais que **limitam o número de vezes que você pode realizar uma ação**. Como usar o mesmo código de desconto várias vezes em uma loja online. Um exemplo muito fácil pode ser encontrado neste [**relatório**](https://medium.com/@pravinponnusamy/race-condition-vulnerability-found-in-bug-bounty-program-573260454c43) ou neste [**bug**](https://hackerone.com/reports/759247)**.**
Existem muitas variações desse tipo de ataque, incluindo:
* Resgatar um cartão-presente várias vezes
* Avaliar um produto várias vezes
* Sacar ou transferir dinheiro em excesso ao saldo da sua conta
* Reutilizar uma única solução CAPTCHA
* Bypassar um limite de taxa anti-força bruta
### **Subestados ocultos**
Outros RC mais complicados explorarão **subestados no estado da máquina** que podem permitir que um atacante **abuse** de estados aos quais ele **nunca deveria ter acesso**, mas existe uma **pequena janela** para o atacante acessá-lo.
1. **Prever subestados ocultos e interessantes**
O primeiro passo é identificar todos os endpoints que escrevem nele ou leem dados dele e, em seguida, usam esses dados para algo importante. Por exemplo, usuários podem ser armazenados em uma tabela de banco de dados que é modificada por registro, edições de perfil, iniciação de redefinição de senha e conclusão de redefinição de senha.
Podemos usar três perguntas-chave para descartar endpoints que provavelmente não causarão colisões. Para cada objeto e os endpoints associados, pergunte:
* **Como o estado é armazenado?**
Dados armazenados em uma estrutura de dados persistente do lado do servidor são ideais para exploração. Alguns endpoints armazenam seu estado inteiramente do lado do cliente, como redefinições de senha que funcionam enviando um JWT por e-mail - esses podem ser ignorados com segurança.
Aplicações geralmente armazenam algum estado na sessão do usuário. Esses geralmente são um tanto protegidos contra subestados - mais sobre isso mais tarde.
* **Estamos editando ou acrescentando?**
Operações que editam dados existentes (como alterar o e-mail principal de uma conta) têm um grande potencial de colisão, enquanto ações que simplesmente acrescentam a dados existentes (como adicionar um endereço de e-mail adicional) são improváveis de serem vulneráveis a algo além de ataques de excedente de limite.
* **Em que a operação é baseada?**
A maioria dos endpoints opera em um registro específico, que é procurado usando uma 'chave', como um nome de usuário, token de redefinição de senha ou nome de arquivo. Para um ataque bem-sucedido, precisamos de duas operações que usem a mesma chave. Por exemplo, imagine duas implementações plausíveis de redefinição de senha:
2. **Procurar por pistas**
Neste ponto, é hora de **lançar alguns ataques RC** sobre os endpoints potencialmente interessantes para tentar encontrar resultados inesperados em comparação com os regulares. **Qualquer desvio da resposta esperada**, como uma mudança em uma ou mais respostas, ou um efeito secundário como conteúdos de e-mail diferentes ou uma mudança visível na sua sessão, pode ser uma pista indicando que algo está errado.
3. **Provar o conceito**
O passo final é **provar o conceito e transformá-lo em um ataque viável**.
Quando você envia um lote de solicitações, pode descobrir que um par de solicitações iniciais desencadeia um estado final vulnerável, mas solicitações posteriores sobrescrevem/invalidam isso e o estado final é inexplorável. Neste cenário, você vai querer eliminar todas as solicitações desnecessárias - duas devem ser suficientes para explorar a maioria das vulnerabilidades. No entanto, reduzir para duas solicitações tornará o ataque mais sensível ao tempo, então você pode precisar tentar o ataque várias vezes ou automatizá-lo.
### Ataques Sensíveis ao Tempo
Às vezes você pode não encontrar condições de corrida, mas as **técnicas para entregar solicitações com tempo preciso** ainda podem revelar a presença de outras vulnerabilidades.
Um exemplo é quando **timestamps de alta resolução são usados em vez de strings aleatórias criptograficamente** seguras para gerar tokens de segurança.
Considere um **token de redefinição de senha que é randomizado apenas usando um timestamp**. Neste caso, pode ser possível **acionar duas redefinições de senha para dois usuários diferentes**, que usam o **mesmo token**. Tudo o que você precisa fazer é cronometrar as solicitações para que elas gerem o mesmo timestamp.
{% hint style="warning" %}
Para confirmar, por exemplo, a situação anterior, você poderia simplesmente pedir **2 tokens de redefinição de senha ao mesmo tempo** (usando ataque de pacote único) e verificar se eles são **iguais**.
{% endhint %}
Confira o [**exemplo neste laboratório**](https://portswigger.net/web-security/race-conditions/lab-race-conditions-exploiting-time-sensitive-vulnerabilities).
## Estudos de caso de subestados ocultos
### Pagar & adicionar um item
[**Confira este laboratório**](https://portswigger.net/web-security/logic-flaws/examples/lab-logic-flaws-insufficient-workflow-validation) para ver como **pagar** em uma loja e **adicionar um item extra** que você **não precisará pagar**.
### Confirmar outros e-mails
A ideia é **verificar um endereço de e-mail e alterá-lo para um diferente ao mesmo tempo** para descobrir se a plataforma verifica o novo alterado.
### Mudar e-mail para 2 endereços de e-mail baseados em Cookie
De acordo com [**este relato**](https://portswigger.net/research/smashing-the-state-machine) o Gitlab era vulnerável a uma tomada de controle dessa maneira porque poderia **enviar** o **token de verificação de e-mail de um e-mail para o outro e-mail**.
Você também pode conferir [**este laboratório**](https://portswigger.net/web-security/race-conditions/lab-race-conditions-single-endpoint) para aprender sobre isso.
### Estados ocultos do banco de dados / Bypass de confirmação
Se **2 escritas diferentes** são usadas para **adicionar** **informações** dentro de um **banco de dados**, existe uma pequena porção de tempo onde **apenas os primeiros dados foram escritos** no banco de dados. Por exemplo, ao criar um usuário, o **nome de usuário** e **senha** podem ser **escritos** e **depois o token** para confirmar a conta recém-criada é escrito. Isso significa que por um pequeno tempo o **token para confirmar uma conta é nulo**.
Portanto, **registrar uma conta e enviar várias solicitações com um token vazio** (`token=` ou `token[]=` ou qualquer outra variação) para confirmar a conta imediatamente poderia permitir **confirmar uma conta** onde você não controla o e-mail.
Confira [**este laboratório**](https://portswigger.net/web-security/race-conditions/lab-race-conditions-partial-construction) para verificar um exemplo.
### Bypass de 2FA
O seguinte pseudo-código demonstra como um site poderia ser vulnerável a uma variação de ataque de corrida dessa forma:
```python
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 você pode ver, isso é de fato uma **sequência de múltiplos passos dentro do intervalo de uma única requisição**. Mais importante, ela passa por um subestado no qual o **usuário temporariamente possui uma sessão válida de login**, **mas a MFA ainda não está sendo aplicada**. Um atacante poderia potencialmente explorar isso enviando uma requisição de login junto com uma requisição para um endpoint sensível e autenticado.
### Persistência eterna OAuth2
Existem vários [**provedores OAuth**](https://en.wikipedia.org/wiki/List_of_OAuth_providers). Esses serviços permitem que você crie uma aplicação e autentique usuários que o provedor registrou. Para fazer isso, o **cliente** precisará **permitir que sua aplicação** acesse alguns dos seus dados dentro do **provedor OAuth**.\
Até aqui, apenas um login comum com google/linkedin/github... onde você é apresentado com uma página dizendo: "_Aplicação \ quer acessar suas informações, você deseja permitir?_"
#### Condição de Corrida em `authorization_code`
O **problema** aparece quando você **aceita** e automaticamente envia um **`authorization_code`** para a aplicação maliciosa. Então, essa **aplicação abusa de uma Condição de Corrida no provedor de serviço OAuth para gerar mais de um AT/RT** (_Token de Autenticação/Token de Atualização_) a partir do **`authorization_code`** para sua conta. Basicamente, ela abusará do fato de você ter aceitado a aplicação para acessar seus dados para **criar várias contas**. Então, se você **parar de permitir que a aplicação acesse seus dados, um par de AT/RT será deletado, mas os outros ainda serão válidos**.
#### Condição de Corrida em `Refresh Token`
Uma vez que você tenha **obtido um RT válido**, você poderia tentar **abusar dele para gerar vários AT/RT** e **mesmo que o usuário cancele as permissões** para a aplicação maliciosa acessar seus dados, **vários RTs ainda serão válidos.**
## **RC em WebSockets**
Em [**WS_RaceCondition_PoC**](https://github.com/redrays-io/WS_RaceCondition_PoC) você pode encontrar um PoC em Java para enviar mensagens websocket em **paralelo** para abusar de **Condições de Corrida também em Web Sockets**.
## Referências
* [https://hackerone.com/reports/759247](https://hackerone.com/reports/759247)
* [https://pandaonair.com/2020/06/11/race-conditions-exploring-the-possibilities.html](https://pandaonair.com/2020/06/11/race-conditions-exploring-the-possibilities.html)
* [https://hackerone.com/reports/55140](https://hackerone.com/reports/55140)
* [https://portswigger.net/research/smashing-the-state-machine](https://portswigger.net/research/smashing-the-state-machine)
* [https://portswigger.net/web-security/race-conditions](https://portswigger.net/web-security/race-conditions)
Aprenda hacking no AWS do zero ao herói comhtARTE (HackTricks AWS Red Team Expert)!
Outras formas de apoiar o HackTricks:
* Se você quer ver sua **empresa anunciada no HackTricks** ou **baixar o HackTricks em PDF**, confira os [**PLANOS DE ASSINATURA**](https://github.com/sponsors/carlospolop)!
* Adquira o [**material oficial PEASS & HackTricks**](https://peass.creator-spring.com)
* Descubra [**A Família PEASS**](https://opensea.io/collection/the-peass-family), nossa coleção de [**NFTs**](https://opensea.io/collection/the-peass-family) exclusivos
* **Junte-se ao grupo** 💬 [**Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo do telegram**](https://t.me/peass) ou **siga-me** no **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/carlospolopm)**.**
* **Compartilhe suas dicas de hacking enviando PRs para os repositórios** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) no github.
\
Use [**Trickest**](https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks) para construir e **automatizar fluxos de trabalho** com facilidade, alimentados pelas **ferramentas comunitárias mais avançadas**.\
Obtenha Acesso Hoje:
{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}