Pentesting gRPC-Web

Reading time: 7 minutes

tip

AWS 해킹 배우기 및 연습하기:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기: HackTricks Training GCP Red Team Expert (GRTE) Azure 해킹 배우기 및 연습하기: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks 지원하기

빠른 프로토콜 요약 및 공격 표면

  • Transport: gRPC‑Web는 프록시(Envoy/APISIX/grpcwebproxy/etc.)를 통해 HTTP/1.1 또는 HTTP/2 상에서 브라우저 호환 gRPC 변형을 사용합니다. 오직 unary 및 server‑streaming 호출만 지원됩니다.
  • Content-Types you will see:
  • application/grpc-web (바이너리 프레이밍)
  • application/grpc-web-text (HTTP/1.1 스트리밍을 위한 base64 인코딩 프레이밍)
  • Framing: 모든 메시지는 5‑byte gRPC 헤더(1‑byte 플래그 + 4‑byte 길이)가 접두됩니다. In gRPC‑Web, trailers (grpc-status, grpc-message, …)는 본문 내부의 특수 프레임으로 전송됩니다: MSB가 설정된 첫 바이트(0x80) 다음에 길이와 HTTP/1.1‑스타일 헤더 블록이 옵니다.
  • Common request headers: x-grpc-web: 1, x-user-agent: grpc-web-javascript/…, grpc-timeout, grpc-encoding. 응답은 grpc-status/grpc-message를 trailers/body 프레임을 통해 노출하며, 브라우저의 경우 종종 Access-Control-Expose-Headers를 통해서도 노출합니다.
  • 보안 관련 미들웨어(자주 존재):
  • Envoy grpc_web filter 및 gRPC‑JSON transcoder (HTTP<->gRPC 브리지)
  • Nginx/APISIX gRPC‑Web 플러그인
  • 프록시의 CORS 정책

이것이 공격자에게 의미하는 바:

  • 요청을 손으로 생성할 수 있습니다(바이너리 또는 base64 텍스트), 또는 도구가 생성/인코딩하도록 할 수 있습니다.
  • 프록시의 CORS 설정 오류는 교차 사이트 인증된 gRPC‑Web 호출을 허용할 수 있습니다(기존 CORS 문제와 유사).
  • JSON transcoding 브리지는 라우트/인증이 잘못 구성된 경우 gRPC 메서드를 의도치 않게 인증되지 않은 HTTP 엔드포인트로 노출할 수 있습니다.

CLI에서 gRPC‑Web 테스트하기

가장 쉬움: buf curl (gRPC‑Web을 네이티브로 지원)

  • reflection을 통해 메서드 목록 확인 (활성화된 경우):
bash
# list methods (uses reflection)
buf curl --protocol grpcweb https://host.tld --list-methods
  • JSON 입력으로 메서드를 호출하고, gRPC‑Web 프레이밍과 headers를 자동으로 처리:
bash
buf curl --protocol grpcweb \
-H 'Origin: https://example.com' \
-d '{"field":"value"}' \
https://host.tld/pkg.svc.v1.Service/Method
  • reflection이 비활성화된 경우, --schema 옵션으로 schema/descriptor set을 제공하거나 로컬 .proto 파일을 가리키세요. 자세한 내용은 buf help curl을 참조하세요.

Raw with curl (수동 헤더 + 프레임된 바디)

바이너리 모드(application/grpc-web)에서는 프레임된 페이로드(5‑byte 접두사 + protobuf message)를 전송하세요. 텍스트 모드에서는 프레임된 페이로드를 base64‑encode하세요.

bash
# 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

팁: HTTP/1.1 중간자가 바이너리 스트리밍을 방해할 때 application/grpc-web-text로 base64/text 모드를 강제하세요.

CORS 동작 확인 (프리플라이트 + 응답)

  • 프리플라이트:
bash
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'
  • 취약한 설정은 종종 임의 Origin을 반사하고 Access-Control-Allow-Credentials: true를 전송하여 교차 사이트 인증된 호출을 허용합니다. 또한 Access-Control-Expose-Headers에 grpc-status, grpc-message가 포함되어 있는지 확인하세요(많은 배포에서 클라이언트 라이브러리를 위해 이를 노출합니다).

CORS를 악용하기 위한 일반적인 기법은 CORS - Misconfigurations & Bypass를 확인하세요.

gRPC‑Web 페이로드 조작

gRPC‑Web는 브라우저 호환을 위해 Content-Type: application/grpc-web-text로 base64로 래핑된 gRPC 프레임 스트림을 사용합니다. 프레임을 디코드/수정/인코드하여 필드를 변조하거나 플래그를 뒤집거나 페이로드를 주입할 수 있습니다.

속도를 높이려면 gprc-coder 도구(및 Burp 확장)를 사용하세요.

gGRPC Coder Tool을 사용한 수동 방법

  1. 페이로드 디코드:
bash
echo "AAAAABYSC0FtaW4gTmFzaXJpGDY6BVhlbm9u" | python3 grpc-coder.py --decode --type grpc-web-text | protoscope > out.txt
  1. 디코딩된 페이로드의 내용을 편집
nano out.txt
2: {"Amin Nasiri Xenon GRPC"}
3: 54
7: {"<script>alert(origin)</script>"}
  1. 새로운 payload를 인코딩
bash
protoscope -s out.txt | python3 grpc-coder.py --encode --type grpc-web-text
  1. Burp interceptor에서 출력을 사용:
AAAAADoSFkFtaW4gTmFzaXJpIFhlbm9uIEdSUEMYNjoePHNjcmlwdD5hbGVydChvcmlnaW4pPC9zY3JpcHQ+

gRPC‑Web Coder Burp Suite Extension 사용 매뉴얼

더 쉬운 방법으로 gRPC‑Web Pentest Suite에 포함된 gRPC‑Web Coder Burp Suite Extension을 사용할 수 있습니다. 설치 및 사용법은 해당 저장소에서 확인하세요.

gRPC‑Web JavaScript 파일 분석

gRPC‑Web를 사용하는 웹 앱은 최소 하나 이상의 생성된 JS/TS 번들을 제공합니다. 이를 역분석하여 서비스, 메서드, 메시지 형식을 추출하세요.

  • 번들 파싱에는 gRPC-Scan을 사용해보세요.
  • /./와 같은 메서드 경로, 메시지 필드 번호/타입, 인증 헤더를 추가하는 커스텀 인터셉터를 찾아보세요.
  1. JavaScript gRPC‑Web 파일을 다운로드하세요
  2. grpc-scan.py로 스캔하세요:
bash
python3 grpc-scan.py --file main.js
  1. 출력 결과를 분석하고 새 엔드포인트와 새 서비스를 테스트합니다:
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            |
+--------------+----------------+--------------+

브리징 및 JSON 트랜스코딩 주의사항

많은 배포에서는 gRPC 서버 앞에 Envoy(또는 유사한) 프록시를 둡니다:

  • grpc_web filter는 HTTP/1.1 POST를 HTTP/2 gRPC로 변환합니다.
  • gRPC‑JSON Transcoder는 .proto 옵션(google.api.http)이 있을 때 gRPC 메서드를 HTTP JSON 엔드포인트로 노출합니다.

From a pentesting perspective:

  • transcoder가 활성화되어 있을 때 application/json으로 /./에 직접 HTTP JSON 호출을 시도해보세요 (auth/route mismatches are common):
bash
curl -i https://host.tld/pkg.svc.v1.Service/Method \
-H 'Content-Type: application/json' \
-d '{"field":"value"}'
  • 알 수 없는 methods/parameters가 거부되는지 또는 통과되는지 검토하세요. 일부 구성은 일치하지 않는 경로를 upstream으로 전달하여 때때로 auth 또는 request validation을 우회할 수 있습니다.
  • 프록시가 추가하는 x-envoy-original-path 및 관련 headers를 관찰하세요. 이러한 헤더를 신뢰하는 upstreams는 프록시가 이를 sanitize하지 못하면 악용될 수 있습니다.

참고자료

tip

AWS 해킹 배우기 및 연습하기:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기: HackTricks Training GCP Red Team Expert (GRTE) Azure 해킹 배우기 및 연습하기: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks 지원하기