API Penetration Test Notes: IDOR Discovery
API Penetration Test Notes: IDOR Discovery · from Anas-Magane/Pentesting (APIs Testing Security).
1. Context & Situation#
Target: API 1 (Secrets Endpoint)
Initial Problem:
When I tried to inspect the API response, I couldn't see the data (the JSON body). The server kept returning 304 Not Modified.
- What this means: The server thinks, "You already have the latest version of this file in your cache, so I won't send it again."
- The Culprit: My request included a header called
If-None-Match. This header acts like a validation check against the server's data.
2. The Vulnerability#
Type: IDOR (Insecure Direct Object Reference) / BOLA (Broken Object Level Authorization). Impact: I can read the private "secrets" of other users by simply changing the ID number.
3. The Goal#
- First: Bypass the
304status to force the server to show me the full data (200 OK). - Second: Test if I can access data belonging to other IDs (users) using my own valid token.
4. When to think about this?#
You should test for this whenever:
- You see numerical IDs in the URL (e.g.,
/secrets/4,/users/101). - You get a
304response and the body is empty (you need to clear headers to see the data). - The API looks predictable (IDs usually increment: 1, 2, 3...).
5. The Payload#
- To fix the 304: Remove the
If-None-Matchheader. - To exploit the IDOR: Change
/api/secrets/4to/api/secrets/2.
6. Reproduction Steps (From Logs)#
Step 1: Reconnaissance (Fail)#
I tried to access the web path, but it wasn't the API.
- Command:
curl https://.../secret/4 - Result:
404 Not Found(Wrong path).
Step 2: Hitting the API (Auth Fail)#
I found the correct API path but didn't send a token.
- Command:
curl -I https://.../api/secrets/4 - Result:
401 Unauthorized(I need a token).
Step 3: The "Cache" Problem#
I sent a valid Token, but the browser/tool added cache headers.
- Command:
curl ... -H 'If-None-Match: W/"99d..."' - Result:
304 Not Modified. - Observation: The server didn't send the JSON body. I can't see the secret.
Step 4: Bypassing the Cache (Success)#
I removed the "If-None-Match" header to force a fresh fetch.
- Command:
curl ... (without If-None-Match) - Result:
200 OK. - Data Received:
I can now see my own data.json{"secret":{"id":4, "owner":{"username":"anas2"}}}
Step 5: The Exploit (IDOR)#
I changed the ID from 4 (me) to 2 (someone else) using the same Token.
- Command:
curl .../api/secrets/2 - Result:
200 OK. - Data Received:
Success! I viewed the private secret of user "anas".json{"secret":{"id":2, "value":"test", "owner":{"username":"anas"}}}