Pentesting gRPC-Web

Tip

Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Lernen & üben Sie Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Unterstützen Sie HackTricks

Kurze Protokoll-Zusammenfassung und Angriffsfläche

  • Transport: gRPC‑Web spricht eine browser-kompatible Variante von gRPC über HTTP/1.1 oder HTTP/2 via einem Proxy (Envoy/APISIX/grpcwebproxy/etc.). Nur unary- und server‑streaming-Calls werden unterstützt.
  • Content-Types, die Sie sehen werden:
  • application/grpc-web (binary framing)
  • application/grpc-web-text (base64-encoded framing für HTTP/1.1 streaming)
  • Framing: jede Nachricht wird mit einem 5‑Byte gRPC-Header vorangestellt (1‑Byte Flags + 4‑Byte Länge). In gRPC‑Web werden Trailers (grpc-status, grpc-message, …) innerhalb des Bodys als spezieller Frame gesendet: erstes Byte mit gesetztem MSB (0x80) gefolgt von einer Länge und einem HTTP/1.1‑artigen Header-Block.
  • Gängige Request-Header: x-grpc-web: 1, x-user-agent: grpc-web-javascript/…, grpc-timeout, grpc-encoding. Responses geben grpc-status/grpc-message über Trailers/Body‑Frames und oft über Access-Control-Expose-Headers für Browser preis.
  • Sicherheitsrelevante Middleware, die häufig vorhanden ist:
  • Envoy grpc_web filter und gRPC‑JSON transcoder (HTTP<->gRPC bridge)
  • Nginx/APISIX gRPC‑Web plugins
  • CORS-Richtlinien auf dem Proxy

Was das für Angreifer bedeutet:

  • Sie können Requests manuell erstellen (binary oder base64 text), oder Tools die Erstellung/Encoding übernehmen lassen.
  • CORS-Fehler auf dem Proxy können cross‑site, authentifizierte gRPC‑Web-Calls ermöglichen (ähnlich zu klassischen CORS-Problemen).
  • JSON-transcoding-Brücken können versehentlich gRPC-Methoden als nicht-authentifizierte HTTP-Endpunkte exponieren, wenn Routen/Auth falsch konfiguriert sind.

Testen von gRPC‑Web über die CLI

Einfachste Methode: buf curl (spricht gRPC‑Web nativ)

  • Methoden via reflection auflisten (falls aktiviert):
# list methods (uses reflection)
buf curl --protocol grpcweb https://host.tld --list-methods
  • Rufe eine Methode mit JSON-Eingabe auf, wobei gRPC‑Web‑Framing und Header automatisch gehandhabt werden:
buf curl --protocol grpcweb \
-H 'Origin: https://example.com' \
-d '{"field":"value"}' \
https://host.tld/pkg.svc.v1.Service/Method
  • Wenn reflection deaktiviert ist, stelle ein schema/descriptor set mit –schema bereit oder verweise auf lokale .proto files. Siehe buf help curl.

Raw mit curl (manuelle headers + framed body)

Für binary mode (application/grpc-web) sende eine framed payload (5-byte prefix + protobuf message). Für text mode base64‑encode die framed payload.

# 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

Tipp: Erzwinge base64/text mode mit application/grpc-web-text, wenn HTTP/1.1 intermediaries binary streaming unterbrechen.

CORS-Verhalten prüfen (preflight + response)

  • Preflight:
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'
  • Eine verwundbare Konfiguration spiegelt oft beliebige Origin wider und sendet Access-Control-Allow-Credentials: true, wodurch site-übergreifende authentifizierte Aufrufe möglich werden. Prüfe außerdem, ob Access-Control-Expose-Headers grpc-status, grpc-message enthält (viele Deployments stellen diese für client libs bereit).

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

Manipulation von gRPC‑Web-Payloads

gRPC‑Web verwendet Content-Type: application/grpc-web-text als base64-verpackten gRPC-Frame-Stream zur Browser-Kompatibilität. Du kannst Frames dekodieren/modifizieren/enkodieren, um Felder zu manipulieren, Flags umzuschalten oder Payloads zu injizieren.

Use the gprc-coder tool (and its Burp extension) to speed up round‑trips.

Manuell mit gGRPC Coder Tool

  1. Payload dekodieren:
echo "AAAAABYSC0FtaW4gTmFzaXJpGDY6BVhlbm9u" | python3 grpc-coder.py --decode --type grpc-web-text | protoscope > out.txt
  1. Bearbeite den Inhalt der decodierten Payload
nano out.txt
2: {"Amin Nasiri Xenon GRPC"}
3: 54
7: {"<script>alert(origin)</script>"}
  1. Den neuen payload kodieren
protoscope -s out.txt | python3 grpc-coder.py --encode --type grpc-web-text
  1. Ausgabe im Burp Interceptor verwenden:
AAAAADoSFkFtaW4gTmFzaXJpIFhlbm9uIEdSUEMYNjoePHNjcmlwdD5hbGVydChvcmlnaW4pPC9zY3JpcHQ+

Handbuch zur gRPC‑Web Coder Burp Suite Extension

Du kannst die gRPC‑Web Coder Burp Suite Extension in gRPC‑Web Pentest Suite verwenden, was einfacher ist. Die Installations- und Nutzungsanweisungen findest du im Repository.

Analyse von gRPC‑Web JavaScript-Dateien

Web-Apps, die gRPC‑Web verwenden, liefern mindestens ein generiertes JS/TS-Bundle aus. Reverse-engineere diese, um Services, Methoden und Nachrichtenstrukturen zu extrahieren.

  • Versuche gRPC-Scan zu verwenden, um Bundles zu parsen.
  • Achte auf Method-Pfade wie /./, Nachrichtenfeldnummern/-typen und benutzerdefinierte Interceptors, die Auth-Header hinzufügen.
  1. Lade die JavaScript gRPC‑Web-Datei herunter
  2. Scanne sie mit grpc-scan.py:
python3 grpc-scan.py --file main.js
  1. Analysiere output und teste die neuen endpoints und neuen 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            |
+--------------+----------------+--------------+

Bridging und JSON-Transcoding-Fallstricke

Viele Deployments setzen einen Envoy (oder ähnlichen) Proxy vor dem gRPC-Server:

  • grpc_web filter übersetzt HTTP/1.1 POSTs in HTTP/2 gRPC.
  • gRPC‑JSON Transcoder macht gRPC-Methoden als HTTP-JSON-Endpunkte verfügbar, wenn .proto-Optionen (google.api.http) vorhanden sind.

Aus der pentesting-Perspektive:

  • Versuche direkte HTTP-JSON-Aufrufe an /./ mit application/json, wenn ein Transcoder aktiviert ist (auth/route-Mismatches sind häufig):
curl -i https://host.tld/pkg.svc.v1.Service/Method \
-H 'Content-Type: application/json' \
-d '{"field":"value"}'
  • Prüfe, ob unbekannte Methoden/Parameter abgewiesen oder weitergereicht werden. Einige Konfigurationen leiten nicht passende paths upstream weiter und umgehen dabei gelegentlich auth oder request validation.
  • Beobachte x-envoy-original-path und verwandte headers, die von proxies hinzugefügt werden. Upstreams, die diesen vertrauen, können ausnutzbar sein, wenn der proxy sie nicht bereinigt.

Referenzen

Tip

Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Lernen & üben Sie Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Unterstützen Sie HackTricks