mcpField
A
attacking-grpc-protobuf

attacking-grpc-protobuf

github.com/trilwuセキュリティ17749 回インストール12 週間前に更新
リポジトリ

attacking-grpc-protobuf について

API セキュリティ担当者向けの gRPC・Protobuf テストスキルです。サービスとメッセージのスキーマ復元後に検査する手順を示し、認可、メタデータの信頼、内部サービスの公開に重点を置きます。

主な機能

  1. 01リフレクションやクライアント記述子からのスキーマ復元
  2. 02grpcurl によるサービスメソッドの呼び出し
  3. 03gRPC 通信の傍受とデコード
  4. 04メソッド単位の認可とメタデータ信頼の確認
  5. 05未知フィールド、型、通信セキュリティのテスト

活用シーン

  1. 01.proto ファイルがない gRPC サービスのテスト
  2. 02低権限ユーザーが呼び出せるメソッドの確認
  3. 03ゲートウェイ外に公開された内部サービスの評価
  4. 04クライアントやブラウザーアプリの gRPC 通信分析

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/trilwu/secskills --skill attacking-grpc-protobuf

インストール後、Claude Code で/attacking-grpc-protobufを入力して読み込まれたか確認します。

詳細

gRPC と Protobuf サービスへの攻撃

gRPC は、リクエストが HTTP/1.1 経由の読み取り可能なテキストであるというツールの前提を覆します。Burp にはバイナリデータか何も表示されず、スキーマがなければメソッド名すら特定できません。スキーマを復元すれば、通常の API テストとして扱えます。ただし、gRPC サービスは新たに公開された内部サービスであることが多く、その認可は前段の REST API より弱い場合があります。

使用する場面

  • トラフィックが HTTP/2 を使用し、content-type: application/grpc になっている
  • リクエストまたはレスポンスの本文が不透明なバイナリで、JSON 構造がない
  • モバイルまたはデスクトップクライアントのアプリが、protobuf 経由でバックエンドと通信している
  • コードベース内に .proto ファイル、*_pb2.py、*.pb.go、または grpc が見つかる
  • ブラウザーアプリに application/grpc-web または application/grpc-web+proto が現れる

使用しない場面

  • REST または GraphQL — testing-apis を使用してください
  • モバイルでプロキシがトラフィックをまったく確認できない — bypassing-mobile-pinning を使用してください。gRPC クライアントはシステムプロキシの設定を無視することがよくあります
  • ソースコードを利用できる — auditing-code-for-vulnerabilities を使用し、.proto ファイルを直接確認してください
  • protobuf ではないバイナリプロトコル — analyzing-binaries を使用してください

スキーマの復元

すべてはこれにかかっています。手間の少ない順に、4 つの方法があります。

1. サーバーリフレクション。 多くのサービスで有効になっており、意図せず有効なままの場合もよくあります。

grpcurl -plaintext target:50051 list
grpcurl -plaintext target:50051 list package.ServiceName
grpcurl -plaintext target:50051 describe package.ServiceName.MethodName
grpcurl -plaintext target:50051 describe package.RequestMessage

# TLS
grpcurl target:443 list
grpcurl -insecure target:443 list          # self-signed / proxy in path

インターネットに公開されたサービスでリフレクションが有効になっていること自体、報告する価値があります。本番環境での GraphQL イントロスペクションに相当する、gRPC における問題です。

2. クライアントにコンパイル済みのディスクリプター。 Protobuf は生成されたコードにシリアライズ済みの FileDescriptorProto を埋め込むため、どのクライアントバイナリからでもスキーマを復元できます。

# Mobile/desktop client: find and extract descriptor blobs
rg -a -o 'google/protobuf/descriptor.proto|\.proto' target_binary | head
# protobuf-inspector and protod can reconstruct .proto from embedded descriptors
protod target_binary -o ./protos

# JS/web clients: the descriptor is usually in the bundle as base64 or an array
rg -n 'grpc-web|serializeBinary|deserializeBinary' bundle.js | head

3. アプリのソースまたはアーティファクトから取得。 リポジトリ内の .proto ファイル、Swagger ゲートウェイの設定、またはパッケージ内の生成済みスタブを確認します。

4. フィールド単位で推測。 いずれも利用できない場合は、ワイヤーフォーマットを直接デコードします。Protobuf は、スキーマなしでも構造を復元できる程度に自己記述的です。

protoc --decode_raw < message.bin
protobuf-inspector < message.bin
# Output: field numbers, wire types, and values — enough to fuzz and to
# recognize strings, nested messages, and integers

フィールドの名前は失われますが、番号は保持されます。ワイヤーフォーマットで必要なのは番号だけです。そのため、値を変更したり、クライアントが送信しないフィールドを追加したりできます。

メソッドの呼び出し

# With reflection
grpcurl -plaintext -d '{"user_id": 1}' target:50051 package.Service/GetUser

# With a local .proto
grpcurl -import-path ./protos -proto api.proto \
        -d '{"user_id": 1}' target:50051 package.Service/GetUser

# Interactive browser UI, good for exploring
grpcui -plaintext target:50051

# Headers, including auth
grpcurl -H 'authorization: Bearer eyJ...' -plaintext target:50051 package.Service/List

ストリーミングメソッドの場合、grpcurl はクライアントストリーミングでは stdin から改行区切りの JSON を受け取り、サーバーストリーミングでは各メッセージを出力します。ストリーミングエンドポイントは単項エンドポイントよりテストが不十分なことが多いため、個別に注意する価値があります。

トラフィックのインターセプト

# mitmproxy speaks HTTP/2 and can decode gRPC with a schema
mitmproxy --mode regular --set http2=true
#   the gRPC content-view renders protobuf; supply .proto for field names

# Burp: enable HTTP/2, and use a protobuf decoder extension
#   without one, you see length-prefixed binary frames

# gRPC-Web is easier — it rides HTTP/1.1 with base64 or binary framing,
# so a normal proxy sees the requests

gRPC フレーミング:各メッセージは、1 バイトの圧縮フラグ、4 バイトのビッグエンディアン長、続いて protobuf のバイト列で構成されます。デコーダーに何も表示されない場合は、この 5 バイトを取り除いてから、ペイロードを protoc --decode_raw に渡してください。

python3 -c "
import sys
d = sys.stdin.buffer.read()
sys.stdout.buffer.write(d[5:])" < frame.bin | protoc --decode_raw

システムプロキシを無視するクライアントには、ネットワーク層でのリダイレクトが必要です。bypassing-mobile-pinning を参照してください。

テスト対象

バグのクラスは一般的な API と同じですが、gRPC では潜んでいる場所が異なります。

メソッドごとの認可。 gRPC にはパスベースのアクセス制御がないため、/admin/* をフィルタリングするリバースプロキシや WAF は機能しません。各メソッドで認可をチェックする必要があります。リフレクションからすべてのメソッドを列挙し、権限の低いトークンでそれぞれ呼び出してください。

for m in $(grpcurl -plaintext target:50051 list package.Service | tail -n +2); do
  echo "== $m"; grpcurl -H "authorization: Bearer $LOW_PRIV" -plaintext -d '{}' target:50051 "$m" 2>&1 | head -3
done

内部サービスの露出。 gRPC はサービスメッシュのプロトコルであるため、他のサービスからのみ呼び出されることを前提に書かれたサービスが多くあります。サービスに直接アクセスできる場合、認証がまったくないことを想定してください。また、通常のリクエストフィールドやメタデータとして渡される ID クレームを信頼している可能性もあります。

メタデータへの信頼。 サービスが ID として読み取るヘッダーを探してください。 x-user-id、x-tenant-id、x-forwarded-user などです。ゲートウェイがこれらを設定し、サービスが信頼している場合、自分でこれらを送信するだけで認証を完全にバイパスできます。

grpcurl -H 'x-user-id: 1' -H 'x-role: admin' -plaintext -d '{}' target:50051 package.Service/GetProfile

未知のフィールドの注入。 Protobuf は認識できないフィールドを無視しますが、中間サービスがそれらを転送する場合があります。さらに有効なのは、クライアントが送信しないものの、サーバーのスキーマで定義されているフィールド(is_admin、internal_notes、tenant_id など)を追加する方法です。マスアサインメントに相当します。

型の混同とリソース枯渇。 ワイヤー型の適用は厳密ではありません。string が想定される場所に bytes を送信したり、再帰の上限を超えるほど深くネストされたメッセージや、巨大な repeated フィールドを送信したりしてください。メッセージサイズの上限が設定されているか確認してください。

TLS と mTLS の状態。 多くの gRPC デプロイでは、内部で insecure チャネルを使用しています。サービスが平文通信を受け入れるか、mTLS が必須か、それとも任意かを確認してください。

拒否すべき言い訳

  • 「Burp に何も表示されないので、アプリはリクエストを送っていません。」 Burp では HTTP/2 を有効にする必要があります。また、gRPC クライアントはシステムプロキシを完全に迂回することがよくあります。
  • 「.proto がないのでテストできません。」 protoc --decode_raw を使えば、どのメッセージからでも構造を復元できます。必要なのはフィールド番号だけです。
  • 「リフレクションが無効なので、メソッドは隠されています。」 クライアントはスキーマを把握しています。クライアントのバイナリからディスクリプターを抽出してください。
  • 「ゲートウェイが認可を適用しています。」 ゲートウェイに見えるのはメソッド名であり、意図ではありません。また、サービスに直接到達できるものは、完全にゲートウェイを迂回します。
  • 「内部専用です。」 それを確認してください。サービスメッシュから情報が漏れることがあり、「内部専用」は通常「認証なし」を意味します。
  • 「クライアントはそのフィールドを送信しません。」 あなたはクライアントではありません。

ATT&CK の対象範囲

secskills-core/ttp-index.json から生成されています。このファイルを編集してから、 python3 scripts/sync_attack.py --write を実行してください。レポートで引用する前に、 ID が現在の ATT&CK リリースと一致していることを再確認してください。

初期アクセス(TA0001)

  • T1190 公開向けアプリケーションの悪用 — testing-web-applications、testing-apis、enumerating-network-services、attacking-graphql、exploiting-deserialization、exploiting-ssrf、exploiting-xxe も参照してください

これらのいずれかに関する検知コンテンツ:engineering-detections。プロアクティブな検索:hunting-threats。侵害後の対応:responding-to-incidents。

参考資料

  • testing-apis — ここで特化している一般的な API の手法
  • auditing-code-for-vulnerabilities — ソースコード内の .proto とハンドラーの確認
  • bypassing-mobile-pinning — モバイルの gRPC クライアントがプロキシを無視する場合
  • exploiting-cloud-platforms — サービスメッシュと内部露出の背景情報
  • grpcurl、grpcui、protoc、protobuf-inspector、protod、mitmproxy

コメント