daemon-sec-cheatsheet

The cheatsheet vault for operators: AD, enumeration, exploitation, priv-esc, web, DFIR
git clone https://git.daemon-sec.xyz/daemon-sec-cheatsheet.git
Log | Files | Refs | README | LICENSE

grpc-web-pentest.md (11465B)


      1 ---
      2 title: "Pentesting gRPC-Web"
      3 section: "Web Pentesting"
      4 sectionSlug: "pentesting-web"
      5 sourcePath: "src/pentesting-web/grpc-web-pentest.md"
      6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/pentesting-web/grpc-web-pentest.md"
      7 sha: "188de82beb54e70956b2952367a0af91d26758b8"
      8 isIndex: false
      9 modified: true
     10 license: "CC-BY-NC-4.0"
     11 ---
     12 
     13 # Pentesting gRPC-Web
     14 
     15 ## Quick protocol recap and attack surface
     16 
     17 - Transport: 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.
     18 - Content-Types you will see:
     19   - application/grpc-web (binary framing)
     20   - application/grpc-web-text (base64-encoded framing for HTTP/1.1 streaming)
     21 - Framing: every message is prefixed with a 5‑byte gRPC header (1‑byte flags + 4‑byte length). In gRPC‑Web, trailers (grpc-status, grpc-message, …) are sent inside the body as a special frame: first byte with MSB set (0x80) followed by a length and a HTTP/1.1‑style header block.<sup>[[3]](#references)</sup>
     22 - Common request headers: x-grpc-web: 1, x-user-agent: grpc-web-javascript/…, grpc-timeout, grpc-encoding. Responses expose grpc-status/grpc-message via trailers/body frames and often via Access-Control-Expose-Headers for browsers.
     23 - Security‑relevant middleware often present:
     24   - Envoy grpc_web filter and gRPC‑JSON transcoder (HTTP<->gRPC bridge)
     25   - Nginx/APISIX gRPC‑Web plugins
     26   - CORS policies on the proxy
     27 
     28 What this means for attackers:
     29 - You can craft requests by hand (binary or base64 text), or let tooling generate/encode them.
     30 - CORS mistakes on the proxy can allow cross‑site, authenticated gRPC‑Web calls (similar to classic CORS issues).
     31 - JSON transcoding bridges may unintentionally expose gRPC methods as unauthenticated HTTP endpoints if routes/auth are misconfigured.<sup>[[1]](#references)</sup>
     32 
     33 ## Testing gRPC‑Web from the CLI
     34 
     35 ### Easiest: buf curl (speaks gRPC‑Web natively)
     36 
     37 - List methods via reflection (if enabled):
     38 
     39 ```bash
     40 # list methods (uses reflection)
     41 buf curl --protocol grpcweb https://host.tld --list-methods
     42 ```
     43 
     44 - Call a method with JSON input, auto‑handling gRPC‑Web framing and headers:
     45 
     46 ```bash
     47 buf curl --protocol grpcweb \
     48   -H 'Origin: https://example.com' \
     49   -d '{"field":"value"}' \
     50   https://host.tld/pkg.svc.v1.Service/Method
     51 ```
     52 
     53 - If reflection is disabled, provide a schema/descriptor set with --schema or point to local .proto files. See buf help curl.
     54 
     55 ### Raw with curl (manual headers + framed body)
     56 
     57 For binary mode (application/grpc-web), send a framed payload (5‑byte prefix + protobuf message). For text mode, base64‑encode the framed payload.
     58 
     59 ```bash
     60 # Build a protobuf message, then gRPC-frame it (1 flag byte + 4 length + msg)
     61 # Example using protoscope to compose/edit the message and base64 for grpc-web-text
     62 protoscope -s msg.txt | python3 grpc-coder.py --encode --type grpc-web-text | \
     63   tee body.b64
     64 
     65 curl -i https://host.tld/pkg.svc.v1.Service/Method \
     66   -H 'Content-Type: application/grpc-web-text' \
     67   -H 'X-Grpc-Web: 1' \
     68   -H 'X-User-Agent: grpc-web-javascript/0.1' \
     69   --data-binary @body.b64
     70 ```
     71 
     72 Tip: Force base64/text mode with application/grpc-web-text when HTTP/1.1 intermediaries break binary streaming.
     73 
     74 ### Check CORS behavior (preflight + response)
     75 
     76 - Preflight:
     77 
     78 ```bash
     79 curl -i -X OPTIONS https://host.tld/pkg.svc.v1.Service/Method \
     80   -H 'Origin: https://evil.tld' \
     81   -H 'Access-Control-Request-Method: POST' \
     82   -H 'Access-Control-Request-Headers: content-type,x-grpc-web,x-user-agent,grpc-timeout'
     83 ```
     84 
     85 - A vulnerable setup often reflects arbitrary Origin and sends Access-Control-Allow-Credentials: true, allowing cross‑site authenticated calls. Also check Access-Control-Expose-Headers includes grpc-status, grpc-message (many deployments expose these for client libs).
     86 
     87 For generic techniques to abuse CORS, check [CORS - Misconfigurations & Bypass](/hacktricks/pentesting-web/cors-bypass).
     88 
     89 ## Manipulating gRPC‑Web payloads
     90 
     91 gRPC‑Web uses Content-Type: application/grpc-web-text as a base64‑wrapped gRPC frame stream for browser compatibility. You can decode/modify/encode frames to tamper with fields, flip flags, or inject payloads.<sup>[[1]](#references)</sup><sup>[[2]](#references)</sup>
     92 
     93 Use the [gprc-coder](https://github.com/nxenon/grpc-pentest-suite) tool (and its Burp extension) to speed up round‑trips.<sup>[[2]](#references)</sup>
     94 
     95 ### Manual with the gRPC Coder Tool
     96 
     97 1. Decode the payload:
     98 
     99 ```bash
    100 echo "AAAAABYSC0FtaW4gTmFzaXJpGDY6BVhlbm9u" | python3 grpc-coder.py --decode --type grpc-web-text | protoscope > out.txt
    101 ```
    102 
    103 2. Edit the content of decoded payload
    104 
    105 ```text
    106 nano out.txt
    107 2: {"Amin Nasiri Xenon GRPC"}
    108 3: 54
    109 7: {"<script>alert(origin)</script>"}
    110 ```
    111 
    112 3. Encode the new payload
    113 
    114 ```bash
    115 protoscope -s out.txt | python3 grpc-coder.py --encode --type grpc-web-text
    116 ```
    117 
    118 4. Use output in Burp interceptor:
    119 
    120 ```text
    121 AAAAADoSFkFtaW4gTmFzaXJpIFhlbm9uIEdSUEMYNjoePHNjcmlwdD5hbGVydChvcmlnaW4pPC9zY3JpcHQ+
    122 ```
    123 
    124 ### Manual with gRPC‑Web Coder Burp Suite Extension
    125 
    126 You can use gRPC‑Web Coder Burp Suite Extension in [gRPC‑Web Pentest Suite](https://github.com/nxenon/grpc-pentest-suite) which is easier. You can read the installation and usage instruction in its repo.<sup>[[2]](#references)</sup>
    127 
    128 ## Analysing gRPC‑Web JavaScript files
    129 
    130 Web apps using gRPC‑Web ship at least one generated JS/TS bundle. Reverse them to extract services, methods, and message shapes.<sup>[[1]](#references)</sup><sup>[[2]](#references)</sup>
    131 
    132 - Try using [gRPC-Scan](https://github.com/nxenon/grpc-pentest-suite) to parse bundles.<sup>[[2]](#references)</sup>
    133 - Look for method paths like `/<pkg>.<Service>/<Method>`, message field numbers/types, and custom interceptors that add auth headers.
    134 
    135 1. Download the JavaScript gRPC‑Web file
    136 2. Scan it with grpc-scan.py:
    137 
    138 ```bash
    139 python3 grpc-scan.py --file main.js
    140 ```
    141 
    142 3. Analyse output and test the new endpoints and new services:
    143 
    144 ```text
    145 Output:
    146 Found Endpoints:
    147   /grpc.gateway.testing.EchoService/Echo
    148   /grpc.gateway.testing.EchoService/EchoAbort
    149   /grpc.gateway.testing.EchoService/NoOp
    150   /grpc.gateway.testing.EchoService/ServerStreamingEcho
    151   /grpc.gateway.testing.EchoService/ServerStreamingEchoAbort
    152 
    153 Found Messages:
    154 
    155 grpc.gateway.testing.EchoRequest:
    156 +------------+--------------------+--------------+
    157 | Field Name |     Field Type     | Field Number |
    158 +============+====================+==============+
    159 | Message    | Proto3StringField  | 1            |
    160 +------------+--------------------+--------------+
    161 | Name       | Proto3StringField  | 2            |
    162 +------------+--------------------+--------------+
    163 | Age        | Proto3IntField     | 3            |
    164 +------------+--------------------+--------------+
    165 | IsAdmin    | Proto3BooleanField | 4            |
    166 +------------+--------------------+--------------+
    167 | Weight     | Proto3FloatField   | 5            |
    168 +------------+--------------------+--------------+
    169 | Test       | Proto3StringField  | 6            |
    170 +------------+--------------------+--------------+
    171 | Test2      | Proto3StringField  | 7            |
    172 +------------+--------------------+--------------+
    173 | Test3      | Proto3StringField  | 16           |
    174 +------------+--------------------+--------------+
    175 | Test4      | Proto3StringField  | 20           |
    176 +------------+--------------------+--------------+
    177 
    178 grpc.gateway.testing.EchoResponse:
    179 +--------------+--------------------+--------------+
    180 |  Field Name  |     Field Type     | Field Number |
    181 +==============+====================+==============+
    182 | Message      | Proto3StringField  | 1            |
    183 +--------------+--------------------+--------------+
    184 | Name         | Proto3StringField  | 2            |
    185 +--------------+--------------------+--------------+
    186 | Age          | Proto3IntField     | 3            |
    187 +--------------+--------------------+--------------+
    188 | IsAdmin      | Proto3BooleanField | 4            |
    189 +--------------+--------------------+--------------+
    190 | Weight       | Proto3FloatField   | 5            |
    191 +--------------+--------------------+--------------+
    192 | Test         | Proto3StringField  | 6            |
    193 +--------------+--------------------+--------------+
    194 | Test2        | Proto3StringField  | 7            |
    195 +--------------+--------------------+--------------+
    196 | Test3        | Proto3StringField  | 16           |
    197 +--------------+--------------------+--------------+
    198 | Test4        | Proto3StringField  | 20           |
    199 +--------------+--------------------+--------------+
    200 | MessageCount | Proto3IntField     | 8            |
    201 +--------------+--------------------+--------------+
    202 
    203 grpc.gateway.testing.ServerStreamingEchoRequest:
    204 +-----------------+-------------------+--------------+
    205 |   Field Name    |    Field Type     | Field Number |
    206 +=================+===================+==============+
    207 | Message         | Proto3StringField | 1            |
    208 +-----------------+-------------------+--------------+
    209 | MessageCount    | Proto3IntField    | 2            |
    210 +-----------------+-------------------+--------------+
    211 | MessageInterval | Proto3IntField    | 3            |
    212 +-----------------+-------------------+--------------+
    213 
    214 grpc.gateway.testing.ServerStreamingEchoResponse:
    215 +------------+-------------------+--------------+
    216 | Field Name |    Field Type     | Field Number |
    217 +============+===================+==============+
    218 | Message    | Proto3StringField | 1            |
    219 +------------+-------------------+--------------+
    220 
    221 grpc.gateway.testing.ClientStreamingEchoRequest:
    222 +------------+-------------------+--------------+
    223 | Field Name |    Field Type     | Field Number |
    224 +============+===================+==============+
    225 | Message    | Proto3StringField | 1            |
    226 +------------+-------------------+--------------+
    227 
    228 grpc.gateway.testing.ClientStreamingEchoResponse:
    229 +--------------+----------------+--------------+
    230 |  Field Name  |   Field Type   | Field Number |
    231 +==============+================+==============+
    232 | MessageCount | Proto3IntField | 1            |
    233 +--------------+----------------+--------------+
    234 ```
    235 
    236 ## Bridging and JSON transcoding gotchas
    237 
    238 Many deployments put an Envoy (or similar) proxy in front of the gRPC server:
    239 
    240 - grpc_web filter translates HTTP/1.1 POSTs into HTTP/2 gRPC.
    241 - gRPC‑JSON Transcoder exposes gRPC methods as HTTP JSON endpoints when .proto options (google.api.http) are present.
    242 
    243 From a pentesting perspective:
    244 - Try direct HTTP JSON calls to `/<pkg>.<Service>/<Method>` with `application/json` when a transcoder is enabled (auth/route mismatches are common):
    245 
    246 ```bash
    247 curl -i https://host.tld/pkg.svc.v1.Service/Method \
    248   -H 'Content-Type: application/json' \
    249   -d '{"field":"value"}'
    250 ```
    251 
    252 - Review whether unknown methods/parameters are rejected or passed through. Some configs forward unmatched paths upstream, occasionally bypassing auth or request validation.
    253 - Observe x-envoy-original-path and related headers added by proxies. Upstreams that trust these may be abusable if the proxy fails to sanitize them.
    254 
    255 ## References
    256 
    257 - [1] [Hacking into gRPC‑Web Article by Amin Nasiri](https://infosecwriteups.com/hacking-into-grpc-web-a54053757a45)
    258 - [2] [gRPC‑Web Pentest Suite](https://github.com/nxenon/grpc-pentest-suite)
    259 - [3] [gRPC‑Web protocol notes (PROTOCOL‑WEB.md)](https://chromium.googlesource.com/external/github.com/grpc/grpc/%2B/v1.16.1/doc/PROTOCOL-WEB.md)