# 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 facilidade, utilizando as ferramentas comunitárias mais avançadas do mundo.\ Acesse hoje mesmo: {% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥 * Você trabalha em uma **empresa de cibersegurança**? Gostaria de ver sua **empresa anunciada no HackTricks**? Ou gostaria de ter acesso à **última versão do PEASS ou baixar o HackTricks em PDF**? Confira os [**PLANOS DE ASSINATURA**](https://github.com/sponsors/carlospolop)! * Descubra [**The PEASS Family**](https://opensea.io/collection/the-peass-family), nossa coleção exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family) * Adquira o [**swag oficial do PEASS & HackTricks**](https://peass.creator-spring.com) * **Junte-se ao** [**💬**](https://emojipedia.org/speech-balloon/) [**grupo Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo Telegram**](https://t.me/peass) ou **siga-me** no **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks\_live)**.** * **Compartilhe suas técnicas de hacking enviando PRs para o** [**repositório hacktricks**](https://github.com/carlospolop/hacktricks) **e para o** [**repositório hacktricks-cloud**](https://github.com/carlospolop/hacktricks-cloud).
## Explorando a Condição de Corrida O principal problema de abusar da Condição de Corrida é 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, são propostas diferentes soluções para tornar isso possível.
### Ataque de pacote único (HTTP/2) / Sincronização do último byte (HTTP/1.1) O HTTP2 permite enviar **2 solicitações em uma única conexão TCP** (enquanto no HTTP/1.1 elas devem ser sequenciais).\ O uso de um único pacote TCP elimina completamente o efeito da variação de rede, portanto, 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 da solicitação do aplicativo causadas por variáveis incontroláveis, como contenção da 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, em seguida, '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 tiver corpo, envie todos os cabeçalhos, mas não defina o sinalizador END\_STREAM. Retenha um quadro de dados vazio com o sinalizador END\_STREAM definido. * Se a solicitação tiver um corpo, envie os cabeçalhos e todos os dados do corpo, exceto o último byte. Retenha um quadro de dados contendo o último byte. Em seguida, **prepare-se para enviar os quadros finais**: * Aguarde 100ms para garantir que os quadros iniciais tenham sido enviados. * Verifique se o TCP\_NODELAY está desativado - é crucial que o algoritmo de Nagle agrupe os quadros finais. * Envie um pacote de ping para aquecer a conexão local. Se você não fizer isso, a pilha de rede do sistema operacional colocará o primeiro quadro final em um pacote separado. Por fim, envie os quadros retidos. Você deve ser capaz de verificar se eles chegaram em um único pacote usando o Wireshark. {% hint style="info" %} Observe que isso **não funciona para arquivos estáticos** em determinados servidores, mas como os arquivos estáticos não são relevantes para ataques de condição de corrida. Mas arquivos estáticos são irrelevantes para ataques de CC. {% 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 à arquitetura do alvo** Vale ressaltar que muitos aplicativos estão atrás de um servidor de front-end, e esses servidores podem decidir encaminhar algumas solicitações por meio de conexões existentes para o back-end e criar novas conexões para outras. Portanto, é importante não atribuir o tempo inconsistente de solicitação ao comportamento do aplicativo, como mecanismos de bloqueio que permitem apenas que uma única thread acesse um recurso de cada vez. Além disso, o roteamento de solicitações de front-end geralmente é feito com base em conexões individuais, portanto, você pode suavizar o tempo de solicitação realizando o aquecimento da conexão do lado do servidor - **enviando algumas solicitações inconsequentes pela sua conexão antes de realizar o ataque** (isso significa enviar várias solicitações antes de iniciar o ataque real)). #### Mecanismos de bloqueio baseados em sessão Alguns frameworks tentam evitar a corrupção acidental de dados usando algum tipo 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 de cada vez**. É extremamente importante identificar esse tipo de comportamento, pois ele pode mascarar vulnerabilidades facilmente exploráveis. Se você perceber que todas as suas solicitações estão sendo processadas sequencialmente, tente enviá-las usando um token de sessão diferente para cada uma delas. #### **Abusando dos limites de taxa ou recursos** Se o aquecimento da conexão não faz diferença, existem várias soluções para esse problema. Usando o Turbo Intruder, você pode introduzir um pequeno atraso no 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 um único pacote. Como resultado, em alvos com alta variação de latência, o ataque provavelmente não funcionará de forma confiável, independentemente do atraso definido.
Em vez disso, você pode 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 falsas para acionar intencionalmente o limite de taxa ou recurso, você pode causar um atraso adequado no lado do servidor. Isso torna o ataque de um único pacote viável mesmo quando a execução atrasada é necessária.
{% hint style="warning" %} Para obter mais informações sobre essa técnica, consulte 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 um único pacote HTTP2 (1 ponto de extremidade)**: Você pode enviar a solicitação para o **Turbo Intruder** (`Extensions` -> `Turbo Intruder` -> `Send to Turbo Intruder`), você pode alterar na solicitação o valor que deseja forçar por **`%s`** como em `csrf=Bn9VQB8OyefIs3ShR2fPESR0FzzulI1d&username=carlos&password=%s` e, em seguida, selecione o **`examples/race-single-packer-attack.py`** no menu suspenso:
Se você for **enviar valores diferentes**, você pode 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 o site 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 você 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` para 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ê pode simplesmente adicionar a **mesma solicitação 50 vezes** no grupo. * Para **aquecimento de conexão**, você pode **adicionar** no **início** do **grupo** algumas **solicitações** para alguma parte não estática do servidor web. * Para **atrasar** o processo **entre** o processamento **de uma solicitação e outra** em etapas de 2 subestados, você pode **adicionar solicitações extras entre** ambas as solicitações. * Para um RC de **vários endpoints**, você pode começar enviando a **solicitação** que **vai para o estado oculto** e, em seguida, **50 solicitações** logo após isso que **exploram o estado oculto**.
### Raw BF Antes da pesquisa anterior, esses 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 a **solicitação** para o **Intruder**, defina o **número de threads** para **30** dentro do menu **Opções** e selecione como payload **Cargas úteis nulas** 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** A biblioteca `asyncio` do Python fornece suporte para programação assíncrona, permitindo que você escreva código concorrente e escalável de forma mais eficiente. Com `asyncio`, você pode lidar com tarefas assíncronas, como chamadas de rede, de forma mais eficiente, evitando bloqueios desnecessários. A programação assíncrona é particularmente útil ao lidar com condições de corrida em aplicativos da web. Uma condição de corrida ocorre quando duas ou mais operações concorrentes tentam acessar ou modificar um recurso compartilhado ao mesmo tempo, resultando em comportamento imprevisível ou incorreto. Ao usar `asyncio`, você pode evitar condições de corrida implementando mecanismos de exclusão mútua, como semáforos ou bloqueios, para garantir que apenas uma tarefa possa acessar o recurso compartilhado de cada vez. Isso ajuda a evitar inconsistências de dados e garantir a integridade do sistema. Além disso, `asyncio` também oferece suporte a corrotinas, que são funções assíncronas que podem ser pausadas e retomadas posteriormente. Isso permite que você escreva código assíncrono de forma mais legível e organizada, facilitando o gerenciamento de tarefas concorrentes. Em resumo, a biblioteca `asyncio` do Python é uma ferramenta poderosa para lidar com condições de corrida em aplicativos da web, permitindo que você escreva código assíncrono eficiente e escalável. ```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 de RC** ### Limite de estouro / TOCTOU Este é o tipo mais básico de condição de corrida, onde **vulnerabilidades** que **aparecem** em lugares que **limitam o número de vezes que você pode executar 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 além do saldo da sua conta * Reutilizar uma solução CAPTCHA única * Bypass de um limite de taxa anti-brute-force ### **Subestados ocultos** Outra condição de corrida mais complicada explorará **subestados no estado da máquina** que poderiam permitir que um invasor **abusasse** de estados aos quais ele **nunca deveria ter acesso**, mas há uma **pequena janela** para o invasor acessá-lo. 1. **Prever subestados ocultos e interessantes potenciais** O primeiro passo é identificar todos os pontos finais que gravam nele ou lêem dados dele e, em seguida, usam esses dados para algo importante. Por exemplo, os usuários podem ser armazenados em uma tabela de banco de dados que é modificada pelo registro, edição de perfil, iniciação de redefinição de senha e conclusão da redefinição de senha. Podemos usar três perguntas-chave para descartar pontos finais que provavelmente não causarão colisões. Para cada objeto e os pontos finais 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 pontos finais armazenam seu estado inteiramente no lado do cliente, como redefinições de senha que funcionam enviando um JWT por e-mail - esses podem ser ignorados com segurança. As aplicações costumam armazenar algum estado na sessão do usuário. Esses estados geralmente são um tanto protegidos contra subestados - mais sobre isso depois. * **Estamos editando ou anexando?** Operações que editam dados existentes (como alterar o endereço de e-mail principal de uma conta) têm grande potencial de colisão, enquanto ações que simplesmente anexam a dados existentes (como adicionar um endereço de e-mail adicional) provavelmente não serão vulneráveis a nada além de ataques de limite de estouro. * **Em que a operação é baseada?** A maioria dos pontos finais 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. **Investigar pistas** Neste ponto, é hora de **lançar alguns ataques de RC** nos pontos finais 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 de segunda ordem, como conteúdos de e-mail diferentes ou uma mudança visível em sua sessão, pode ser uma pista indicando que algo está errado. 3. **Provar o conceito** A etapa 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 aciona um estado final vulnerável, mas solicitações posteriores sobrescrevem/invalidam esse estado e o estado final não pode ser explorado. Nesse cenário, você desejará 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, portanto, talvez seja necessário 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 enviar solicitações com tempo preciso** ainda podem revelar a presença de outras vulnerabilidades. Um exemplo disso é quando **carimbos de data/hora 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 é apenas randomizado usando um carimbo de data/hora**. Nesse 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 carimbo de data/hora. {% hint style="warning" %} Para confirmar, por exemplo, a situação anterior, você pode simplesmente solicitar **2 tokens de redefinição de senha ao mesmo tempo** (usando um ataque de pacote único) e verificar se eles são **iguais**. {% endhint %} Verifique 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 e adicionar um item [**Verifique 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 endereço alterado. ### Alterar o e-mail para 2 endereços de e-mail baseados em cookie De acordo com [**este artigo**](https://portswigger.net/research/smashing-the-state-machine), o Gitlab estava vulnerável a uma invasão 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 verificar [**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 gravações diferentes** são usadas para **adicionar** **informações** dentro de um **banco de dados**, há uma pequena parte do tempo em que **apenas os primeiros dados foram gravados** no banco de dados. Por exemplo, ao criar um usuário, o **nome de usuário** e a **senha** podem ser **gravados** e, em seguida, o token para confirmar a conta recém-criada é gravado. Isso significa que por um curto período de 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 pode permitir **confirmar uma conta** em que você não controla o e-mail. Verifique [**este laboratório**](https://portswigger.net/web-security/race-conditions/lab-race-conditions-partial-construction) para ver um exemplo. ### Bypassar 2FA O seguinte pseudo-código demonstra como um site pode ser vulnerável a uma variação de corrida desse ataque: ```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 vários passos dentro de uma única solicitação**. Mais importante ainda, ela passa por um subestado em que o **usuário temporariamente possui uma sessão válida logada**, **mas a MFA ainda não está sendo aplicada**. Um atacante poderia potencialmente explorar isso enviando uma solicitação de login juntamente com uma solicitação a um endpoint autenticado sensível. ### Persistência eterna do OAuth2 Existem vários [**provedores de OAuth**](https://en.wikipedia.org/wiki/List\_of\_OAuth\_providers). Esses serviços permitirão que você crie um aplicativo e autentique usuários registrados pelo provedor. Para fazer isso, o **cliente** precisará **permitir que seu aplicativo** acesse alguns de seus dados dentro do **provedor de OAuth**.\ Então, até aqui, apenas um login comum com google/linkdin/github... onde você é solicitado com uma página dizendo: "_O aplicativo \ deseja acessar suas informações, você deseja permitir?_" #### Condição de corrida em `authorization_code` O **problema** ocorre quando você **aceita** e automaticamente envia um **`authorization_code`** para o aplicativo malicioso. Em seguida, esse **aplicativo abusa de uma Condição de Corrida no provedor de serviços de OAuth para gerar mais de um AT/RT** (_Authentication Token/Refresh Token_) a partir do **`authorization_code`** para sua conta. Basicamente, ele abusará do fato de você ter aceitado o aplicativo para acessar seus dados e **criará várias contas**. Então, se você **parar de permitir que o aplicativo acesse seus dados, um par de AT/RT será excluído, mas os outros ainda serão válidos**. #### Condição de corrida em `Refresh Token` Depois de **obter um RT válido**, você pode tentar **abusar dele para gerar vários AT/RT** e, mesmo se o usuário cancelar as permissões para o aplicativo malicioso acessar seus dados, **vários RTs ainda serão válidos**. ## **CC em WebSockets** No [**WS\_RaceCondition\_PoC**](https://github.com/redrays-io/WS\_RaceCondition\_PoC), você pode encontrar um PoC em Java para enviar mensagens de websocket em **paralelo** para abusar das **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)
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥 * Você trabalha em uma **empresa de segurança cibernética**? Você quer ver sua **empresa anunciada no HackTricks**? ou você quer ter acesso à **última versão do PEASS ou baixar o HackTricks em PDF**? Verifique os [**PLANOS DE ASSINATURA**](https://github.com/sponsors/carlospolop)! * Descubra [**The PEASS Family**](https://opensea.io/collection/the-peass-family), nossa coleção exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family) * Adquira o [**swag oficial do PEASS & HackTricks**](https://peass.creator-spring.com) * **Junte-se ao** [**💬**](https://emojipedia.org/speech-balloon/) [**grupo Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo telegram**](https://t.me/peass) ou **siga-me** no **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks\_live)**.** * **Compartilhe seus truques de hacking enviando PRs para o** [**repositório hacktricks**](https://github.com/carlospolop/hacktricks) **e para o** [**repositório hacktricks-cloud**](https://github.com/carlospolop/hacktricks-cloud).
\ Use [**Trickest**](https://trickest.com/?utm\_campaign=hacktrics\&utm\_medium=banner\&utm\_source=hacktricks) para criar e **automatizar fluxos de trabalho** com facilidade, usando as ferramentas comunitárias mais avançadas do mundo.\ Acesse hoje mesmo: {% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}