Pentesting gRPC-Web

Reading time: 11 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をサポートする

プロトコルの簡単な復習と攻撃対象

  • Transport: gRPC‑Web はプロキシ経由(Envoy/APISIX/grpcwebproxy/etc.)でブラウザ互換の gRPC バリアントを HTTP/1.1 或いは HTTP/2 上で話します。Only unary and server‑streaming calls are supported.
  • よく見る Content-Types:
  • application/grpc-web (binary framing)
  • application/grpc-web-text (base64-encoded framing for HTTP/1.1 streaming)
  • Framing: 各メッセージは 5 バイトの gRPC ヘッダ(1 バイトの flags + 4 バイトの length)でプレフィックスされます。In gRPC‑Web、trailers (grpc-status, grpc-message, …) はボディ内の特殊フレームとして送られます:最初のバイトは MSB がセット(0x80)され、その後に長さと HTTP/1.1 スタイルのヘッダブロックが続きます。
  • Common request headers: x-grpc-web: 1, x-user-agent: grpc-web-javascript/…, grpc-timeout, grpc-encoding。Responses は grpc-status/grpc-message を trailers/body フレーム経由で公開し、ブラウザ向けには Access-Control-Expose-Headers で公開されていることが多いです。
  • セキュリティ関連のミドルウェアが存在することが多い:
  • Envoy grpc_web filter and gRPC‑JSON transcoder (HTTP<->gRPC bridge)
  • Nginx/APISIX gRPC‑Web plugins
  • プロキシ上の CORS ポリシー

攻撃者にとっての意味:

  • リクエストは手作業で作れる(バイナリまたは base64 テキスト)、あるいはツールに生成/エンコードさせることもできます。
  • プロキシの CORS ミスは cross‑site で認証済みの gRPC‑Web 呼び出しを許してしまう可能性があります(従来の CORS 問題と類似)。
  • JSON transcoding ブリッジは、ルーティングや認証が誤設定されていると gRPC メソッドを認証不要の HTTP エンドポイントとして意図せず公開することがあります。

Testing gRPC‑Web from the CLI

Easiest: buf curl (speaks gRPC‑Web natively)

  • リフレクションでメソッドを一覧表示(有効な場合):
bash
# list methods (uses reflection)
buf curl --protocol grpcweb https://host.tld --list-methods
  • JSON入力でメソッドを呼び出し、gRPC‑Web framing と headers を自動処理する:
bash
buf curl --protocol grpcweb \
-H 'Origin: https://example.com' \
-d '{"field":"value"}' \
https://host.tld/pkg.svc.v1.Service/Method
  • reflection が無効になっている場合は、--schema オプションで schema/descriptor set を提供するか、ローカルの .proto ファイルを指定してください。詳細は buf help curl を参照してください。

Raw with curl (手動ヘッダ + フレーム化されたボディ)

バイナリモード (application/grpc-web) では、フレーム化されたペイロード(5-byte プレフィックス + protobuf メッセージ)を送信します。テキストモードでは、フレーム化されたペイロードを base64 エンコードしてください。

bash
# Build a protobuf message, then gRPC-frame it (1 flag byte + 4 length + msg)
# Example using protoscope to compose/edit the message and base64 for grpc-web-text
protoscope -s msg.txt | python3 grpc-coder.py --encode --type grpc-web-text | \
tee body.b64

curl -i https://host.tld/pkg.svc.v1.Service/Method \
-H 'Content-Type: application/grpc-web-text' \
-H 'X-Grpc-Web: 1' \
-H 'X-User-Agent: grpc-web-javascript/0.1' \
--data-binary @body.b64

ヒント: HTTP/1.1 の中間機器がバイナリストリーミングを壊す場合、application/grpc-web-text で base64/text モードを強制する。

CORS の挙動を確認する(preflight + response)

  • プリフライト:
bash
curl -i -X OPTIONS https://host.tld/pkg.svc.v1.Service/Method \
-H 'Origin: https://evil.tld' \
-H 'Access-Control-Request-Method: POST' \
-H 'Access-Control-Request-Headers: content-type,x-grpc-web,x-user-agent,grpc-timeout'
  • 脆弱な設定では任意の Origin を反映し Access-Control-Allow-Credentials: true を返すことが多く、クロスサイトで認証済みの呼び出しを許可します。 また、Access-Control-Expose-Headers に grpc-status、grpc-message が含まれているか確認してください(多くのデプロイでクライアントライブラリ向けにこれらを公開しています)。

For generic techniques to abuse CORS, check CORS - Misconfigurations & Bypass.

gRPC‑Web ペイロードの操作

gRPC‑Web はブラウザ互換性のために Content-Type: application/grpc-web-text として base64 でラップされた gRPC フレームストリームを使用します。フレームをデコード/修正/再エンコードして、フィールドを改ざんしたりフラグを反転させたり、ペイロードを注入したりできます。

ラウンドトリップを高速化するには、gprc-coder ツール(およびその Burp extension)を使用してください。

gGRPC Coder Tool による手動操作

  1. ペイロードをデコードする:
bash
echo "AAAAABYSC0FtaW4gTmFzaXJpGDY6BVhlbm9u" | python3 grpc-coder.py --decode --type grpc-web-text | protoscope > out.txt
  1. デコードされたペイロードの内容を編集する
nano out.txt
2: {"Amin Nasiri Xenon GRPC"}
3: 54
7: {"<script>alert(origin)</script>"}
  1. 新しい payload をエンコードする
bash
protoscope -s out.txt | python3 grpc-coder.py --encode --type grpc-web-text
  1. Burp interceptorで出力を使用する:
AAAAADoSFkFtaW4gTmFzaXJpIFhlbm9uIEdSUEMYNjoePHNjcmlwdD5hbGVydChvcmlnaW4pPC9zY3JpcHQ+

gRPC‑Web Coder Burp Suite Extension を使ったマニュアル

より簡単な方法として、gRPC‑Web Pentest Suite に含まれている gRPC‑Web Coder Burp Suite Extension を使うことができます。インストールと使用方法はリポジトリの説明を参照してください。

gRPC‑Web JavaScript ファイルの解析

gRPC‑Web を使用する Web アプリは少なくとも1つの生成済みの JS/TS バンドルを配布します。これらをリバースして、サービス、メソッド、メッセージの構造を抽出します。

  • バンドルの解析には gRPC-Scan を試してみてください。
  • /./ のようなメソッドパス、メッセージのフィールド番号/型、認証ヘッダを追加するカスタムインターセプターを探します。
  1. JavaScript の gRPC‑Web ファイルをダウンロードする
  2. grpc-scan.py でスキャンする:
bash
python3 grpc-scan.py --file main.js
  1. 出力を解析し、新しい endpoints と新しい services をテストする:
Output:
Found Endpoints:
/grpc.gateway.testing.EchoService/Echo
/grpc.gateway.testing.EchoService/EchoAbort
/grpc.gateway.testing.EchoService/NoOp
/grpc.gateway.testing.EchoService/ServerStreamingEcho
/grpc.gateway.testing.EchoService/ServerStreamingEchoAbort

Found Messages:

grpc.gateway.testing.EchoRequest:
+------------+--------------------+--------------+
| Field Name |     Field Type     | Field Number |
+============+====================+==============+
| Message    | Proto3StringField  | 1            |
+------------+--------------------+--------------+
| Name       | Proto3StringField  | 2            |
+------------+--------------------+--------------+
| Age        | Proto3IntField     | 3            |
+------------+--------------------+--------------+
| IsAdmin    | Proto3BooleanField | 4            |
+------------+--------------------+--------------+
| Weight     | Proto3FloatField   | 5            |
+------------+--------------------+--------------+
| Test       | Proto3StringField  | 6            |
+------------+--------------------+--------------+
| Test2      | Proto3StringField  | 7            |
+------------+--------------------+--------------+
| Test3      | Proto3StringField  | 16           |
+------------+--------------------+--------------+
| Test4      | Proto3StringField  | 20           |
+------------+--------------------+--------------+

grpc.gateway.testing.EchoResponse:
+--------------+--------------------+--------------+
|  Field Name  |     Field Type     | Field Number |
+==============+====================+==============+
| Message      | Proto3StringField  | 1            |
+--------------+--------------------+--------------+
| Name         | Proto3StringField  | 2            |
+--------------+--------------------+--------------+
| Age          | Proto3IntField     | 3            |
+--------------+--------------------+--------------+
| IsAdmin      | Proto3BooleanField | 4            |
+--------------+--------------------+--------------+
| Weight       | Proto3FloatField   | 5            |
+--------------+--------------------+--------------+
| Test         | Proto3StringField  | 6            |
+--------------+--------------------+--------------+
| Test2        | Proto3StringField  | 7            |
+--------------+--------------------+--------------+
| Test3        | Proto3StringField  | 16           |
+--------------+--------------------+--------------+
| Test4        | Proto3StringField  | 20           |
+--------------+--------------------+--------------+
| MessageCount | Proto3IntField     | 8            |
+--------------+--------------------+--------------+

grpc.gateway.testing.ServerStreamingEchoRequest:
+-----------------+-------------------+--------------+
|   Field Name    |    Field Type     | Field Number |
+=================+===================+==============+
| Message         | Proto3StringField | 1            |
+-----------------+-------------------+--------------+
| MessageCount    | Proto3IntField    | 2            |
+-----------------+-------------------+--------------+
| MessageInterval | Proto3IntField    | 3            |
+-----------------+-------------------+--------------+

grpc.gateway.testing.ServerStreamingEchoResponse:
+------------+-------------------+--------------+
| Field Name |    Field Type     | Field Number |
+============+===================+==============+
| Message    | Proto3StringField | 1            |
+------------+-------------------+--------------+

grpc.gateway.testing.ClientStreamingEchoRequest:
+------------+-------------------+--------------+
| Field Name |    Field Type     | Field Number |
+============+===================+==============+
| Message    | Proto3StringField | 1            |
+------------+-------------------+--------------+

grpc.gateway.testing.ClientStreamingEchoResponse:
+--------------+----------------+--------------+
|  Field Name  |   Field Type   | Field Number |
+==============+================+==============+
| MessageCount | Proto3IntField | 1            |
+--------------+----------------+--------------+

ブリッジとJSONトランスコーディングの注意点

多くのデプロイでは、gRPC サーバーの前に Envoy(または同等の)プロキシを配置します:

  • grpc_web フィルタは HTTP/1.1 の POST を HTTP/2 gRPC に変換します。
  • gRPC‑JSON Transcoder は .proto オプション (google.api.http) があると gRPC メソッドを HTTP JSON エンドポイントとして公開します。

pentesting の観点から:

  • transcoder が有効な場合、application/json で /./ に対して直接 HTTP JSON コールを試してみてください(auth/route の不一致はよくあります):
bash
curl -i https://host.tld/pkg.svc.v1.Service/Method \
-H 'Content-Type: application/json' \
-d '{"field":"value"}'
  • 未知の methods/parameters が拒否されるか、通過されるかを確認する。いくつかの設定では一致しないパスを upstream に転送し、時として auth や request validation をバイパスしてしまうことがある。
  • プロキシによって追加される x-envoy-original-path や関連ヘッダを観察する。これらを信頼する upstreams は、プロキシがそれらをサニタイズしない場合に悪用され得る。

参考

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をサポートする