Upgrade Header Smuggling
H2Cスモグリング
HTTP2オーバークリアテキスト (H2C)
H2C、またはhttp2オーバークリアテキストは、標準のHTTP接続を持続的なものにアップグレードすることで、一時的なHTTP接続の規範から逸脱します。このアップグレードされた接続は、平文HTTPの単一リクエストの性質とは対照的に、継続的な通信のためにhttp2バイナリプロトコルを利用します。
スモグリングの問題の核心は、リバースプロキシの使用にあります。通常、リバースプロキシはHTTPリクエストを処理し、バックエンドに転送し、その後バックエンドの応答を返します。しかし、HTTPリクエストにConnection: Upgrade
ヘッダーが存在する場合(一般的にウェブソケット接続で見られる)、リバースプロキシはクライアントとサーバー間の持続的な接続を維持し、特定のプロトコルに必要な継続的な交換を促進します。H2C接続の場合、RFCに従うためには、3つの特定のヘッダーが必要です:
脆弱性は、接続をアップグレードした後、リバースプロキシが個々のリクエストの管理を停止し、接続確立後にルーティングの仕事が完了したと仮定する場合に発生します。H2Cスムージングを悪用することで、H2C接続が正常に開始されると仮定して、リクエスト処理中に適用されるリバースプロキシルール(パスベースのルーティング、認証、WAF処理など)を回避できます。
脆弱なプロキシ
この脆弱性は、リバースプロキシがUpgrade
および時にはConnection
ヘッダーをどのように処理するかに依存します。以下のプロキシは、プロキシパス中にこれらのヘッダーを本質的に転送し、H2Cスムージングを本質的に可能にします:
HAProxy
Traefik
Nuster
逆に、これらのサービスはプロキシパス中に両方のヘッダーを本質的に転送しません。しかし、設定が不適切である場合、Upgrade
およびConnection
ヘッダーのフィルタリングされていない転送を許可することがあります:
AWS ALB/CLB
NGINX
Apache
Squid
Varnish
Kong
Envoy
Apache Traffic Server
悪用
すべてのサーバーが準拠したH2C接続アップグレードに必要なヘッダーを本質的に転送するわけではないことに注意することが重要です。そのため、AWS ALB/CLB、NGINX、Apache Traffic Serverなどのサーバーは、自然にH2C接続をブロックします。それにもかかわらず、Connection: Upgrade
の非準拠バリアントを使用してテストする価値があります。これは、Connection
ヘッダーからHTTP2-Settings
値を除外します。一部のバックエンドは標準に準拠していない可能性があります。
proxy_pass
URLに指定された特定のパス(例:http://backend:9999/socket.io
)に関係なく、確立された接続はデフォルトでhttp://backend:9999
になります。これにより、この技術を利用して、その内部エンドポイント内の任意のパスと対話できます。したがって、proxy_pass
URLにパスを指定してもアクセスは制限されません。
ツールh2csmuggler by BishopFoxおよびh2csmuggler by assetnoteは、H2C接続を確立することにより、プロキシによって課せられた保護を回避する試みを支援し、プロキシによって保護されたリソースへのアクセスを可能にします。
この脆弱性に関する追加情報、特にNGINXに関しては、この詳細なリソースを参照してください。
Websocketスムージング
Websocketスムージングは、プロキシを介してアクセス可能なエンドポイントへのHTTP2トンネルを作成するのとは異なり、Websocketトンネルを確立して潜在的なプロキシの制限を回避し、エンドポイントとの直接通信を促進します。
シナリオ1
このシナリオでは、公開WebSocket APIとアクセスできない内部REST APIを提供するバックエンドが、内部REST APIへのアクセスを求める悪意のあるクライアントによって標的にされます。攻撃は以下のいくつかのステップで展開されます:
クライアントは、ヘッダーに不正な
Sec-WebSocket-Version
プロトコルバージョンを含むUpgradeリクエストをリバースプロキシに送信します。プロキシはSec-WebSocket-Version
ヘッダーを検証せず、Upgradeリクエストが有効であると信じてバックエンドに転送します。バックエンドは、
Sec-WebSocket-Version
ヘッダーに不正なプロトコルバージョンを示すステータスコード426
で応答します。リバースプロキシはバックエンドの応答ステータスを見落とし、WebSocket通信の準備が整ったと仮定し、応答をクライアントに中継します。その結果、リバースプロキシはクライアントとバックエンドの間にWebSocket接続が確立されたと誤解しますが、実際にはバックエンドはUpgradeリクエストを拒否しました。それにもかかわらず、プロキシはクライアントとバックエンドの間にオープンなTCPまたはTLS接続を維持し、この接続を介してクライアントがプライベートREST APIに無制限にアクセスできるようにします。
影響を受けるリバースプロキシには、問題に対処しなかったVarnishや、アップグレードメカニズムが変更されたEnvoyプロキシバージョン1.8.0以前が含まれます。他のプロキシも脆弱である可能性があります。
![](https://book.hacktricks.xyz/~gitbook/image?url=https%3A%2F%2Fgithub.com%2F0ang3el%2Fwebsocket-smuggle%2Fraw%2Fmaster%2Fimg%2F2-4.png&width=768&dpr=4&quality=100&sign=f1f723d7&sv=1)
シナリオ2
このシナリオでは、公開WebSocket APIとヘルスチェック用の公開REST API、さらにアクセスできない内部REST APIを持つバックエンドが関与します。攻撃はより複雑で、以下のステップが含まれます:
クライアントは、ヘルスチェックAPIをトリガーするためにPOSTリクエストを送信し、追加のHTTPヘッダー
Upgrade: websocket
を含めます。リバースプロキシとして機能するNGINXは、Upgrade
ヘッダーのみに基づいてこれを標準のUpgradeリクエストとして解釈し、リクエストの他の側面を無視してバックエンドに転送します。バックエンドはヘルスチェックAPIを実行し、攻撃者が制御する外部リソースにアクセスし、ステータスコード
101
を持つHTTP応答を返します。この応答はバックエンドによって受信され、NGINXに転送されると、プロキシはステータスコードのみを検証するため、WebSocket接続が確立されたと誤解します。
![](https://book.hacktricks.xyz/~gitbook/image?url=https%3A%2F%2Fgithub.com%2F0ang3el%2Fwebsocket-smuggle%2Fraw%2Fmaster%2Fimg%2F3-4.png&width=768&dpr=4&quality=100&sign=4fb431ba&sv=1)
警告: この技術の複雑さは、ステータスコード101を返すことができるエンドポイントと対話する能力を必要とするため、増加します。
最終的に、NGINXはクライアントとバックエンドの間にWebSocket接続が存在すると誤解します。実際には、そのような接続は存在せず、ヘルスチェックREST APIがターゲットでした。それにもかかわらず、リバースプロキシは接続をオープンに保ち、クライアントがそれを介してプライベートREST APIにアクセスできるようにします。
![](https://book.hacktricks.xyz/~gitbook/image?url=https%3A%2F%2Fgithub.com%2F0ang3el%2Fwebsocket-smuggle%2Fraw%2Fmaster%2Fimg%2F3-5.png&width=768&dpr=4&quality=100&sign=9eee65d3&sv=1)
ほとんどのリバースプロキシはこのシナリオに脆弱ですが、悪用は通常低Severityの問題と見なされる外部SSRF脆弱性の存在に依存します。
ラボ
両方のシナリオをテストするためのラボを確認してください:https://github.com/0ang3el/websocket-smuggle.git
参考文献
Last updated