Skip to content

Commit cb92d76

Browse files
feat: implement aditional test scenarios
1 parent 861d461 commit cb92d76

19 files changed

+6359
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,3 +271,4 @@ oldsemgrep-report.json
271271
.pentest/raw-headers-frontend.txt
272272
.pentest/raw-headers-api.txt
273273
/.reports
274+
/.pentest/snapshots

.pentest/README.md

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
# ProStaff API - Pentest Lab
2+
3+
Lab de testes de segurança para a API ProStaff. Adaptado do framework chorrocho.
4+
5+
## Alvo
6+
7+
- **API**: http://localhost:3333/api/v1
8+
- **WebSocket**: ws://localhost:3333/cable
9+
- **Stack**: Rails 7.1, PostgreSQL, Redis, JWT, Pundit, Rack::Attack, Meilisearch
10+
11+
## Pre-requisitos
12+
13+
API rodando localmente:
14+
15+
```bash
16+
cd /home/bullet/PROJETOS/prostaff-api
17+
docker compose up -d
18+
docker exec prostaff-api-api-1 bundle exec rails runner scripts/create_test_user.rb
19+
```
20+
21+
Credenciais de teste: `test@prostaff.gg` / `Test123!@#`
22+
23+
## Instalacao das ferramentas
24+
25+
```bash
26+
./tools/install.sh # instala nuclei, pd-httpx, sqlmap, websocat
27+
./tools/install.sh check # verifica status das ferramentas
28+
```
29+
30+
## Scripts
31+
32+
| Script | Vetor | Destrutivo |
33+
|--------|-------|-----------|
34+
| 01_health_recon.sh | Info disclosure nos endpoints de health | Nao |
35+
| 02_auth_fingerprint.sh | Fingerprint do sistema JWT + timing oracle | Nao |
36+
| 03_jwt_attacks.sh | alg:none, RS256→HS256, claims tampering, token replay | Nao |
37+
| 04_org_isolation.sh | IDOR + isolamento multi-tenant | Nao |
38+
| 05_rbac_probe.sh | Privilege escalation + Pundit bypass | Nao |
39+
| 06_rate_limit_probe.sh | Rack::Attack + bypass via X-Forwarded-For | Nao |
40+
| 07_param_fuzzing.sh | SQLi, XSS, SSTI, type confusion, oversized payloads | Nao |
41+
| 08_ssrf_probe.sh | SSRF via integracao Riot API | Nao |
42+
| 09_export_injection.sh | CSV/Formula injection nos exports | Sim (cria player) |
43+
| 10_websocket_probe.sh | Action Cable auth + IDOR de canal | Nao |
44+
| 11_search_injection.sh | Meilisearch operators + cross-org search | Nao |
45+
| 12_info_disclosure.sh | Rails routes expostos, headers, CORS, 500 stack traces | Nao |
46+
| 13_nuclei_scan.sh | Templates customizados + headers/auth/Rails exposures | Nao |
47+
| 14_httpx_recon.sh | Recon completo de paths e headers | Nao |
48+
| 15_full_audit.sh | Roda todos os scripts em sequencia | Opcional |
49+
50+
## Uso rapido
51+
52+
```bash
53+
# Todos os testes (sem os destrutivos)
54+
./scripts/15_full_audit.sh --skip-destructive
55+
56+
# Todos os testes
57+
./scripts/15_full_audit.sh
58+
59+
# Script individual
60+
./scripts/01_health_recon.sh
61+
./scripts/03_jwt_attacks.sh
62+
63+
# Auditoria rapida (sem nuclei e search)
64+
./scripts/15_full_audit.sh --quick
65+
```
66+
67+
## Ordem recomendada
68+
69+
1. `01``02` (recon e auth - baseline)
70+
2. `03``04``05` (atacar auth e autorizacao)
71+
3. `06``07` (rate limits e fuzzing)
72+
4. `08``09` (integracao externa e exports)
73+
5. `10``11` (WebSocket e search)
74+
6. `12``13``14` (info disclosure e scan automatizado)
75+
76+
## Vetores principais (Rails/JWT)
77+
78+
### Autenticacao
79+
- JWT alg:none bypass
80+
- Modificacao de claims (role, org_id)
81+
- Timing oracle para enumeracao de usuarios
82+
- Token replay apos logout
83+
84+
### Autorizacao
85+
- Multi-tenant IDOR (organization_id scope)
86+
- Pundit policy bypass por role
87+
- Mass assignment via campos extras no body
88+
- HTTP method override (X-HTTP-Method-Override)
89+
90+
### Infraestrutura
91+
- Rack::Attack bypass por header spoofing
92+
- Rails info routes exposto em dev
93+
- CORS wildcard em API autenticada
94+
- Stack trace em respostas de erro
95+
96+
### Integracao
97+
- SSRF via sync Riot API (region parameter)
98+
- CSV formula injection em exports
99+
- Meilisearch cross-org data leakage
100+
101+
## Resultados
102+
103+
Salvos em `snapshots/` com timestamp. Nunca commitar - adicione ao .gitignore.
104+
105+
## Diferenca do chorrocho
106+
107+
| Chorrocho | ProStaff |
108+
|-----------|----------|
109+
| HTTP POST JSON simples | REST completo com rotas aninhadas |
110+
| Google Apps Script backend | Rails 7.1 + PostgreSQL |
111+
| Cloudflare Turnstile (bot protection) | JWT Bearer token |
112+
| Sem usuarios/roles | JWT com roles + multi-tenant |
113+
| Google Sheets (nao SQL) | PostgreSQL (SQL real) |
114+
| Cloudflare Workers (sem state) | Rails stateful + Redis |
Lines changed: 245 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
#!/usr/bin/env bash
2+
# =============================================================================
3+
# 01_health_recon.sh - Health endpoint reconnaissance
4+
#
5+
# Purpose: Probe all health/status endpoints and document what internal system
6+
# information is exposed (DB URLs, Redis addresses, service names,
7+
# version strings, environment names, etc.)
8+
#
9+
# Usage:
10+
# bash 01_health_recon.sh
11+
# bash 01_health_recon.sh 2>&1 | tee custom_output.txt
12+
#
13+
# Output: ../snapshots/health_recon_TIMESTAMP.txt
14+
# =============================================================================
15+
16+
set -euo pipefail
17+
18+
# ---------------------------------------------------------------------------
19+
# Configuration
20+
# ---------------------------------------------------------------------------
21+
BASE_URL="http://localhost:3333"
22+
API="http://localhost:3333/api/v1"
23+
TIMESTAMP="$(date +%Y%m%d_%H%M%S)"
24+
SNAPSHOT_DIR="$(cd "$(dirname "$0")/../snapshots" 2>/dev/null && pwd || echo "/home/bullet/PROJETOS/prostaff-api/.pentest/snapshots")"
25+
OUTPUT_FILE="${SNAPSHOT_DIR}/health_recon_${TIMESTAMP}.txt"
26+
27+
# ---------------------------------------------------------------------------
28+
# Color helpers (stdout only; file output is plain)
29+
# ---------------------------------------------------------------------------
30+
RED='\033[0;31m'
31+
GREEN='\033[0;32m'
32+
YELLOW='\033[1;33m'
33+
CYAN='\033[0;36m'
34+
BOLD='\033[1m'
35+
RESET='\033[0m'
36+
37+
ok() { echo -e "${GREEN}[OK]${RESET} $*"; }
38+
finding() { echo -e "${RED}[!!]${RESET} $*"; }
39+
info() { echo -e "${CYAN}[*]${RESET} $*"; }
40+
header() { echo -e "\n${BOLD}${CYAN}=== $* ===${RESET}\n"; }
41+
42+
# ---------------------------------------------------------------------------
43+
# Logging: write to both stdout and file (file gets plain text)
44+
# ---------------------------------------------------------------------------
45+
mkdir -p "${SNAPSHOT_DIR}"
46+
exec > >(tee -a "${OUTPUT_FILE}") 2>&1
47+
48+
log_separator() {
49+
echo "--------------------------------------------------------------------------------"
50+
}
51+
52+
# ---------------------------------------------------------------------------
53+
# Probe a single endpoint and record everything
54+
# ---------------------------------------------------------------------------
55+
probe_endpoint() {
56+
local label="$1"
57+
local url="$2"
58+
local method="${3:-GET}"
59+
60+
echo ""
61+
log_separator
62+
echo "ENDPOINT : ${label}"
63+
echo "URL : ${url}"
64+
echo "METHOD : ${method}"
65+
echo "TIME : $(date --iso-8601=seconds)"
66+
log_separator
67+
68+
# Run curl, capture status + time + headers + body
69+
local tmp_headers
70+
tmp_headers="$(mktemp)"
71+
local tmp_body
72+
tmp_body="$(mktemp)"
73+
74+
local http_code
75+
local total_time
76+
77+
http_code=$(curl -s -o "${tmp_body}" \
78+
-D "${tmp_headers}" \
79+
-w "%{http_code}" \
80+
--max-time 10 \
81+
-X "${method}" \
82+
"${url}" 2>/dev/null) || http_code="CURL_ERROR"
83+
84+
total_time=$(curl -s -o /dev/null \
85+
-w "%{time_total}" \
86+
--max-time 10 \
87+
-X "${method}" \
88+
"${url}" 2>/dev/null) || total_time="N/A"
89+
90+
echo "HTTP STATUS : ${http_code}"
91+
echo "RESPONSE TIME: ${total_time}s"
92+
echo ""
93+
94+
echo "--- Response Headers ---"
95+
cat "${tmp_headers}" 2>/dev/null || echo "(no headers captured)"
96+
echo ""
97+
98+
echo "--- Response Body ---"
99+
local body
100+
body="$(cat "${tmp_body}" 2>/dev/null || echo '(empty)')"
101+
if [ -z "${body}" ]; then
102+
echo "(empty body)"
103+
else
104+
# Pretty-print if JSON, otherwise raw
105+
echo "${body}" | python3 -m json.tool 2>/dev/null || echo "${body}"
106+
fi
107+
echo ""
108+
109+
# -------------------------------------------------------------------------
110+
# Findings analysis - look for sensitive data patterns
111+
# -------------------------------------------------------------------------
112+
echo "--- Findings Analysis ---"
113+
114+
local found_anything=0
115+
116+
# DB connection strings
117+
if echo "${body}" | grep -qiE '(postgres|mysql|mongodb|database_url|db_host|db_url|jdbc:)'; then
118+
finding "Possible database connection info in response body"
119+
found_anything=1
120+
fi
121+
122+
# Redis
123+
if echo "${body}" | grep -qiE '(redis://|redis_url|redis_host|:6379|:6380)'; then
124+
finding "Redis connection info leaked in response body"
125+
found_anything=1
126+
fi
127+
128+
# Internal hostnames / IPs
129+
if echo "${body}" | grep -qE '(127\.|10\.|192\.168\.|172\.(1[6-9]|2[0-9]|3[01])\.|localhost)'; then
130+
finding "Internal IP or localhost reference in response body"
131+
found_anything=1
132+
fi
133+
134+
# Service version strings
135+
if echo "${body}" | grep -qiE '(version|ruby|rails|rack|puma|unicorn|nginx|apache)'; then
136+
finding "Version or server technology disclosed in response body"
137+
found_anything=1
138+
fi
139+
140+
# Environment name
141+
if echo "${body}" | grep -qiE '(environment|env.*:.*production|env.*:.*staging|env.*:.*development|RAILS_ENV)'; then
142+
finding "Environment name disclosed in response body"
143+
found_anything=1
144+
fi
145+
146+
# API keys / secrets (partial)
147+
if echo "${body}" | grep -qiE '(api_key|secret|token|password|credential)'; then
148+
finding "Possible credential/key reference in response body"
149+
found_anything=1
150+
fi
151+
152+
# Stack traces
153+
if echo "${body}" | grep -qiE '(\.rb:|ActiveRecord|ActionController|app/|backtrace|stack trace|Traceback)'; then
154+
finding "Stack trace or Ruby internal path in response body"
155+
found_anything=1
156+
fi
157+
158+
# Server header disclosure
159+
local server_header
160+
server_header=$(grep -i '^server:' "${tmp_headers}" 2>/dev/null | head -1 || true)
161+
if [ -n "${server_header}" ]; then
162+
finding "Server header disclosed: ${server_header}"
163+
found_anything=1
164+
fi
165+
166+
# X-Powered-By
167+
local powered_by
168+
powered_by=$(grep -i '^x-powered-by:' "${tmp_headers}" 2>/dev/null | head -1 || true)
169+
if [ -n "${powered_by}" ]; then
170+
finding "X-Powered-By header disclosed: ${powered_by}"
171+
found_anything=1
172+
fi
173+
174+
# Meilisearch
175+
if echo "${body}" | grep -qiE '(meilisearch|meili)'; then
176+
finding "Meilisearch service reference in response body"
177+
found_anything=1
178+
fi
179+
180+
# Supabase
181+
if echo "${body}" | grep -qiE '(supabase|\.supabase\.co)'; then
182+
finding "Supabase reference in response body"
183+
found_anything=1
184+
fi
185+
186+
if [ "${found_anything}" -eq 0 ]; then
187+
ok "No obvious sensitive data detected in response"
188+
fi
189+
190+
# Check security headers
191+
echo ""
192+
echo "--- Security Headers Check ---"
193+
local sec_headers=("X-Frame-Options" "X-Content-Type-Options" "Content-Security-Policy" "Strict-Transport-Security" "X-XSS-Protection")
194+
for hdr in "${sec_headers[@]}"; do
195+
local val
196+
val=$(grep -i "^${hdr}:" "${tmp_headers}" 2>/dev/null | head -1 || true)
197+
if [ -n "${val}" ]; then
198+
ok "Present: ${val}"
199+
else
200+
info "Missing: ${hdr}"
201+
fi
202+
done
203+
204+
rm -f "${tmp_headers}" "${tmp_body}"
205+
}
206+
207+
# ===========================================================================
208+
# MAIN
209+
# ===========================================================================
210+
header "HEALTH ENDPOINT RECONNAISSANCE"
211+
echo "Target : ${BASE_URL}"
212+
echo "Started : $(date --iso-8601=seconds)"
213+
echo "Output : ${OUTPUT_FILE}"
214+
215+
info "Probing health and status endpoints..."
216+
217+
# Probe all candidate endpoints
218+
probe_endpoint "Root health (Rails default)" "${BASE_URL}/up"
219+
probe_endpoint "Generic /health" "${BASE_URL}/health"
220+
probe_endpoint "Liveness probe" "${BASE_URL}/health/live"
221+
probe_endpoint "Readiness probe" "${BASE_URL}/health/ready"
222+
probe_endpoint "Detailed health" "${BASE_URL}/health/detailed"
223+
probe_endpoint "API v1 status" "${API}/status"
224+
probe_endpoint "API root" "${API}"
225+
226+
# Also check for common info-disclosure paths
227+
probe_endpoint "Rails info (should be blocked in prod)" "${BASE_URL}/rails/info"
228+
probe_endpoint "Rails info properties" "${BASE_URL}/rails/info/properties"
229+
probe_endpoint "Sidekiq web UI" "${BASE_URL}/sidekiq"
230+
probe_endpoint "Cable endpoint" "${BASE_URL}/cable"
231+
232+
echo ""
233+
log_separator
234+
header "RECONNAISSANCE SUMMARY"
235+
echo "Completed : $(date --iso-8601=seconds)"
236+
echo "Results saved to: ${OUTPUT_FILE}"
237+
echo ""
238+
echo "Review the [!!] findings above for sensitive disclosures."
239+
echo "Key questions to answer from this output:"
240+
echo " 1. Does /up or /health/detailed reveal DB, Redis, or service URLs?"
241+
echo " 2. Are Server/X-Powered-By headers disclosing tech stack?"
242+
echo " 3. Does /rails/info/properties return data (should 404 in prod)?"
243+
echo " 4. Is the Sidekiq dashboard accessible without auth?"
244+
echo " 5. Do any endpoints return stack traces or internal paths?"
245+
log_separator

0 commit comments

Comments
 (0)