AUTONOMY DIRECTORATE

๐Ÿ  Main

๐Ÿงช Interactive Apps

๐Ÿ“ฐ News

๐Ÿ›ก๏ธ PQ Crypta Proxy

๐Ÿ‘ค Account

โŸจ QUANTUM ERROR PORTAL โŸฉ

Navigate the Error Dimensions

PQ Crypta Logo

Script Viewer

Red Team Suite › 32_grpc_protobuf.sh

32_grpc_protobuf.sh 178 lines
1 #!/bin/bash
2 # 32 - gRPC / Protobuf Security
3 # Scope note: pqcrypta.com public surface is REST/HTTP. This script probes for
4 # any accidentally-exposed gRPC endpoints on standard and non-standard ports.
5 # If none found, results document "no gRPC surface" โ€” which is itself a finding.
6 #
7 # Tests: port scan for gRPC, HTTP/2 gRPC content-type probes, protobuf fuzzing,
8 # gRPC reflection (service enumeration), gRPC-Web (browser gateway),
9 # auth bypass via gRPC metadata, message injection
10
11 SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
12 source "$SCRIPT_DIR/../config.sh"
13 OUT_FILE="$OUT/32_grpc_protobuf.txt"
14 echo "=== 32. gRPC / Protobuf ===" | tee "$OUT_FILE"
15 echo "Target: $TARGET API: $API_TARGET" | tee -a "$OUT_FILE"
16 echo "" | tee -a "$OUT_FILE"
17
18 HOST=$(echo "$TARGET" | sed 's|https\?://||' | cut -d/ -f1)
19 IP=$(dig +short "$HOST" | grep -oP '^\d+\.\d+\.\d+\.\d+$' | head -1)
20 [ -z "$IP" ] && IP="$HOST"
21
22 # โ”€โ”€ 1. Port scan for gRPC โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
23 echo "--- gRPC Port Scan ---" | tee -a "$OUT_FILE"
24 GRPC_PORTS=(50051 50052 50053 9090 9091 9092 8080 8443 3000 3001 4000 4001 7070 7071)
25 FOUND_PORTS=()
26 for PORT in "${GRPC_PORTS[@]}"; do
27 if timeout 2 bash -c "echo >/dev/tcp/$IP/$PORT" 2>/dev/null; then
28 printf ' [OPEN] port %s on %s\n' "$PORT" "$IP" | tee -a "$OUT_FILE"
29 FOUND_PORTS+=("$PORT")
30 else
31 printf ' [CLOSED] port %s\n' "$PORT" | tee -a "$OUT_FILE"
32 fi
33 done
34
35 if [ ${#FOUND_PORTS[@]} -eq 0 ]; then
36 echo "" | tee -a "$OUT_FILE"
37 echo " [SCOPE] No gRPC ports found on public surface." | tee -a "$OUT_FILE"
38 echo " If internal services use gRPC, test from within the network or VPN." | tee -a "$OUT_FILE"
39 echo " See SCOPE.md for gRPC coverage gap documentation." | tee -a "$OUT_FILE"
40 fi
41 echo "" | tee -a "$OUT_FILE"
42
43 # โ”€โ”€ 2. gRPC Content-Type probe on existing HTTPS endpoints โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
44 echo "--- gRPC Content-Type Probe (HTTP/2) ---" | tee -a "$OUT_FILE"
45 # A gRPC server will respond with HTTP/2 + content-type: application/grpc
46 # even if the path is wrong. A REST server will return 415/400.
47 GRPC_CT_PROBES=(
48 "application/grpc"
49 "application/grpc+proto"
50 "application/grpc-web"
51 "application/grpc-web+proto"
52 "application/grpc-web-text"
53 )
54 for CT in "${GRPC_CT_PROBES[@]}"; do
55 for ENDPOINT in "/" "/encrypt" "/decrypt" "/status" "/grpc" "/api"; do
56 CODE=$(curl -sk --http2 -o /dev/null -w '%{http_code}' --max-time 8 \
57 -A "$BROWSER_UA" \
58 -X POST \
59 -H "Content-Type: $CT" \
60 -H "TE: trailers" \
61 --data-binary $'\x00\x00\x00\x00\x05\x08\x01\x10\x01\x18\x01' \
62 "$API_TARGET$ENDPOINT")
63 # 415 = Unsupported Media Type (REST server rejecting gRPC CT โ€” expected)
64 # 200 = possible gRPC server accepting request
65 # 400 = server parsed but rejected โ€” might be gRPC
66 if [ "$CODE" != "415" ] && [ "$CODE" != "404" ] && [ "$CODE" != "401" ] && [ "$CODE" != "403" ]; then
67 printf ' [%s] %s โ†’ %s (unexpected โ€” check if gRPC endpoint)\n' "$CODE" "$CT" "$ENDPOINT" | tee -a "$OUT_FILE"
68 else
69 printf ' [%s] %s โ†’ %s\n' "$CODE" "$CT" "$ENDPOINT" | tee -a "$OUT_FILE"
70 fi
71 done
72 done
73 echo "" | tee -a "$OUT_FILE"
74
75 # โ”€โ”€ 3. gRPC Reflection probe โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
76 echo "--- gRPC Server Reflection (service enumeration) ---" | tee -a "$OUT_FILE"
77 # Minimal protobuf-encoded ServerReflectionRequest
78 # Field 1 (list_services): empty string โ†’ b'\n\x00' wrapped in gRPC frame
79 # gRPC frame: 1-byte flag(0) + 4-byte length + payload
80 REFLECT_PAYLOAD=$(python3 -c "
81 import struct, sys
82 # ServerReflection.ServerReflectionInfo request: list_services = ''
83 proto_body = b'\x0a\x00' # field 1 (string): empty
84 frame = struct.pack('>BI', 0, len(proto_body)) + proto_body
85 sys.stdout.buffer.write(frame)
86 " 2>/dev/null | base64 -w0)
87
88 for PORT in 443 50051 9090 8080; do
89 TARGET_REFLECT="https://$HOST:$PORT/grpc.reflection.v1alpha.ServerReflection/ServerReflectionInfo"
90 CODE=$(echo "$REFLECT_PAYLOAD" | base64 -d | \
91 curl -sk --http2 -o /tmp/grpc_reflect.bin -w '%{http_code}' \
92 --max-time 8 -A "$BROWSER_UA" \
93 -X POST \
94 -H "Content-Type: application/grpc" \
95 -H "TE: trailers" \
96 --data-binary @- \
97 "$TARGET_REFLECT" 2>/dev/null)
98 RESP_HEX=$(xxd /tmp/grpc_reflect.bin 2>/dev/null | head -3)
99 if [ "$CODE" = "200" ]; then
100 echo " [VULN] gRPC reflection responded on port $PORT โ€” service enumeration possible!" | tee -a "$OUT_FILE"
101 echo "$RESP_HEX" | sed 's/^/ /' | tee -a "$OUT_FILE"
102 else
103 printf ' [%s] gRPC reflection probe on port %s\n' "$CODE" "$PORT" | tee -a "$OUT_FILE"
104 fi
105 done
106 echo "" | tee -a "$OUT_FILE"
107
108 # โ”€โ”€ 4. Protobuf fuzzing (malformed frames) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
109 echo "--- Protobuf Malformed Frame Fuzzing ---" | tee -a "$OUT_FILE"
110 FUZZ_CASES=(
111 "Empty frame:\x00\x00\x00\x00\x00"
112 "Oversized length:\x00\xff\xff\xff\xff"
113 "Truncated payload:\x00\x00\x00\x00\x10\x08\x01"
114 "Compressed flag set:\x01\x00\x00\x00\x05\x08\x01\x10\x01\x18\x01"
115 "Max field number:\xff\xff\xff\xff\x7f"
116 "Nested overflow:\x0a\xff\xff\xff\x7f"
117 )
118 for CASE in "${FUZZ_CASES[@]}"; do
119 LABEL="${CASE%%:*}"
120 PAYLOAD="${CASE#*:}"
121 CODE=$(printf "$PAYLOAD" | curl -sk --http2 -o /dev/null -w '%{http_code}' \
122 --max-time 8 -A "$BROWSER_UA" \
123 -X POST \
124 -H "Content-Type: application/grpc" \
125 -H "TE: trailers" \
126 --data-binary @- \
127 "$API_TARGET/encrypt" 2>/dev/null)
128 printf ' [%s] Protobuf fuzz: %s\n' "$CODE" "$LABEL" | tee -a "$OUT_FILE"
129 done
130 echo "" | tee -a "$OUT_FILE"
131
132 # โ”€โ”€ 5. gRPC-Web gateway probe โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
133 echo "--- gRPC-Web Gateway ---" | tee -a "$OUT_FILE"
134 # gRPC-Web allows browsers to speak gRPC via HTTP/1.1 through a gateway
135 GRPC_WEB_PATHS=(/grpc-web /grpcweb /grpc.gateway /api/grpc /v1/grpc)
136 for GWPATH in "${GRPC_WEB_PATHS[@]}"; do
137 CODE=$(curl -sk --http2 -o /dev/null -w '%{http_code}' --max-time 8 \
138 -A "$BROWSER_UA" \
139 -X POST \
140 -H "Content-Type: application/grpc-web+proto" \
141 -H "X-Grpc-Web: 1" \
142 --data-binary $'\x00\x00\x00\x00\x00' \
143 "$TARGET$GWPATH" 2>/dev/null)
144 [ "$CODE" != "404" ] && [ "$CODE" != "301" ] && \
145 printf ' [%s] gRPC-Web gateway: %s\n' "$CODE" "$GWPATH" | tee -a "$OUT_FILE" || \
146 printf ' [%s] %s\n' "$CODE" "$GWPATH" | tee -a "$OUT_FILE"
147 done
148 echo "" | tee -a "$OUT_FILE"
149
150 # โ”€โ”€ 6. gRPC metadata auth bypass โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
151 echo "--- gRPC Metadata Auth Bypass ---" | tee -a "$OUT_FILE"
152 # gRPC auth is carried in HTTP/2 headers (metadata). Test missing/invalid auth.
153 for ENDPOINT in "/encrypt" "/decrypt" "/status"; do
154 # No auth metadata
155 CODE=$(printf '\x00\x00\x00\x00\x05\x08\x01\x10\x01\x18\x01' | \
156 curl -sk --http2 -o /dev/null -w '%{http_code}' --max-time 8 \
157 -X POST \
158 -H "Content-Type: application/grpc" \
159 -H "TE: trailers" \
160 --data-binary @- \
161 "$API_TARGET$ENDPOINT" 2>/dev/null)
162 printf ' [%s] gRPC no-auth โ†’ %s\n' "$CODE" "$ENDPOINT" | tee -a "$OUT_FILE"
163
164 # Fake auth token in grpc-metadata
165 CODE=$(printf '\x00\x00\x00\x00\x05\x08\x01\x10\x01\x18\x01' | \
166 curl -sk --http2 -o /dev/null -w '%{http_code}' --max-time 8 \
167 -X POST \
168 -H "Content-Type: application/grpc" \
169 -H "TE: trailers" \
170 -H "authorization: Bearer FAKE_GRPC_TOKEN" \
171 --data-binary @- \
172 "$API_TARGET$ENDPOINT" 2>/dev/null)
173 printf ' [%s] gRPC fake-auth โ†’ %s\n' "$CODE" "$ENDPOINT" | tee -a "$OUT_FILE"
174 done
175 echo "" | tee -a "$OUT_FILE"
176
177 echo "=== 32. gRPC / Protobuf COMPLETE ===" | tee -a "$OUT_FILE"
178