Pentesting gRPC-Web

Tip

Aprende y practica Hacking en AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprende y practica Hacking en Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Apoya a HackTricks

Rápido repaso del protocolo y superficie de ataque

  • Transporte: gRPC‑Web speaks a browser‑compatible variant of gRPC over HTTP/1.1 or HTTP/2 via a proxy (Envoy/APISIX/grpcwebproxy/etc.). Only unary and server‑streaming calls are supported.
  • Content-Types que verás:
    • application/grpc-web (binary framing)
    • application/grpc-web-text (base64-encoded framing for HTTP/1.1 streaming)
  • Framing: cada mensaje va precedido de un header gRPC de 5 bytes (1 byte de flags + 4 bytes de longitud). En gRPC‑Web, los trailers (grpc-status, grpc-message, …) se envían dentro del body como un frame especial: primer byte con el MSB establecido (0x80) seguido de una longitud y un bloque de encabezados al estilo HTTP/1.1.
  • Encabezados de solicitud comunes: x-grpc-web: 1, x-user-agent: grpc-web-javascript/…, grpc-timeout, grpc-encoding. Las respuestas exponen grpc-status/grpc-message vía trailers/body frames y a menudo mediante Access-Control-Expose-Headers para navegadores.
  • Middleware relevantes para seguridad que suelen estar presentes:
    • Envoy grpc_web filter and gRPC‑JSON transcoder (HTTP<->gRPC bridge)
    • Nginx/APISIX gRPC‑Web plugins
    • CORS policies on the proxy

Qué significa esto para atacantes:

  • Puedes construir requests a mano (binario o texto base64), o dejar que las herramientas los generen/encodifiquen.
  • Errores de CORS en el proxy pueden permitir llamadas gRPC‑Web cross‑site autenticadas (similar a problemas clásicos de CORS).
  • Los bridges de JSON transcoding pueden exponer inadvertidamente métodos gRPC como endpoints HTTP no autenticados si las rutas/autenticación están mal configuradas.

Testing gRPC‑Web desde la CLI

Más fácil: buf curl (speaks gRPC‑Web natively)

  • List methods via reflection (if enabled):
# list methods (uses reflection)
buf curl --protocol grpcweb https://host.tld --list-methods
  • Llamar a un método con entrada JSON, manejando automáticamente el framing y los headers de gRPC‑Web:
buf curl --protocol grpcweb \
-H 'Origin: https://example.com' \
-d '{"field":"value"}' \
https://host.tld/pkg.svc.v1.Service/Method
  • Si reflection está deshabilitado, proporciona un schema/descriptor set con –schema o apunta a archivos .proto locales. See buf help curl.

Raw con curl (cabeceras manuales + framed body)

Para el modo binario (application/grpc-web), envía un framed payload (prefijo de 5 bytes + protobuf message). Para el modo texto, codifica en base64 el 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

Consejo: Forzar el modo base64/text con application/grpc-web-text cuando los intermediarios HTTP/1.1 rompen la transmisión binaria.

Comprobar el comportamiento de CORS (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'
  • Una configuración vulnerable suele reflejar un Origin arbitrario y enviar Access-Control-Allow-Credentials: true, permitiendo llamadas autenticadas cross‑site. También verifica que Access-Control-Expose-Headers incluya grpc-status, grpc-message (muchas implementaciones exponen estos para client libs).

Para técnicas genéricas para abusar de CORS, consulta CORS - Misconfigurations & Bypass.

Manipulación de payloads de gRPC‑Web

gRPC‑Web usa Content-Type: application/grpc-web-text como un stream de frames gRPC envuelto en base64 para compatibilidad con navegadores. Puedes decodificar/modificar/recodificar los frames para alterar campos, invertir flags o inyectar payloads.

Usa la herramienta gprc-coder (y su extensión para Burp) para acelerar los round‑trips.

Manual con gGRPC Coder Tool

  1. Decodifica el payload:
echo "AAAAABYSC0FtaW4gTmFzaXJpGDY6BVhlbm9u" | python3 grpc-coder.py --decode --type grpc-web-text | protoscope > out.txt
  1. Editar el contenido del payload decodificado
nano out.txt
2: {"Amin Nasiri Xenon GRPC"}
3: 54
7: {"<script>alert(origin)</script>"}
  1. Codifica el nuevo payload
protoscope -s out.txt | python3 grpc-coder.py --encode --type grpc-web-text
  1. Usar la salida en el interceptor de Burp:
AAAAADoSFkFtaW4gTmFzaXJpIFhlbm9uIEdSUEMYNjoePHNjcmlwdD5hbGVydChvcmlnaW4pPC9zY3JpcHQ+

Manual con gRPC‑Web Coder Burp Suite Extension

Puedes usar gRPC‑Web Coder Burp Suite Extension en gRPC‑Web Pentest Suite, que es más sencillo. Puedes leer las instrucciones de instalación y uso en su repositorio.

Analizando archivos JavaScript de gRPC‑Web

Las apps web que usan gRPC‑Web incluyen al menos un bundle JS/TS generado. Haz ingeniería inversa sobre ellos para extraer servicios, métodos y la estructura de los mensajes.

  • Prueba usando gRPC-Scan para parsear los bundles.
  • Busca rutas de métodos como /./, números/tipos de campos de mensaje y interceptores personalizados que añaden auth headers.
  1. Descarga el archivo JavaScript gRPC‑Web
  2. Escanéalo con grpc-scan.py:
python3 grpc-scan.py --file main.js
  1. Analizar la salida y probar los nuevos endpoints y nuevos 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            |
+--------------+----------------+--------------+

Advertencias sobre bridging y transcodificación JSON

Muchas implementaciones colocan un proxy Envoy (o similar) delante del servidor gRPC:

  • El filtro grpc_web convierte HTTP/1.1 POSTs en HTTP/2 gRPC.
  • El gRPC‑JSON Transcoder expone métodos gRPC como endpoints HTTP JSON cuando las opciones .proto (google.api.http) están presentes.

Desde la perspectiva de pentesting:

  • Intenta llamadas HTTP JSON directas a /./ con application/json cuando un transcoder está habilitado (auth/route mismatches are common):
curl -i https://host.tld/pkg.svc.v1.Service/Method \
-H 'Content-Type: application/json' \
-d '{"field":"value"}'
  • Revisa si métodos/parametros desconocidos son rechazados o simplemente se pasan. Algunas configuraciones reenvían rutas no coincidentes upstream, ocasionalmente evitando la auth o la validación de solicitudes.
  • Observa x-envoy-original-path y los encabezados relacionados añadidos por proxies. Los upstreams que confían en estos pueden ser abusables si el proxy no los sanea.

Referencias

Tip

Aprende y practica Hacking en AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprende y practica Hacking en Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Apoya a HackTricks