חקירת API ומיפוי - תרגיל¶
הקדמה¶
בתרגיל זה תתרגלו חקירת API מתקדמת - מציאת תיעוד נסתר, ביצוע אינטרוספקציה ב-GraphQL, מיפוי גרסאות API, וגילוי נקודות קצה שאינן מתועדות.
חלק א - גילוי תיעוד Swagger¶
משימה 1 - מציאת קובצי Swagger נסתרים¶
- צרו קובץ רשימת נתיבים של Swagger:
cat > swagger_paths.txt << 'EOF'
swagger.json
swagger.yaml
swagger/
swagger-ui/
swagger-ui.html
swagger/v1/swagger.json
swagger/v2/swagger.json
api-docs
api-docs.json
api-docs/
openapi.json
openapi.yaml
openapi/v1.json
openapi/v2.json
openapi/v3.json
v1/api-docs
v2/api-docs
v3/api-docs
docs
docs/api
redoc
api/swagger.json
api/v1/swagger.json
api/v2/swagger.json
.well-known/openapi.json
api/docs
api/spec
api/schema
graphql
graphiql
EOF
- הריצו סריקה נגד Juice Shop:
-
בדקו את התוצאות - האם נמצא קובץ תיעוד?
-
בדקו גם נתיבים עם סיומות:
משימה 2 - ניתוח תיעוד API¶
אם מצאתם קובץ Swagger, נתחו אותו:
# Download and parse
curl -s "http://localhost:3000/api-docs" | python3 -m json.tool > api_docs.json
# Extract endpoints
python3 -c "
import json
with open('api_docs.json') as f:
spec = json.load(f)
for path in sorted(spec.get('paths', {}).keys()):
methods = list(spec['paths'][path].keys())
print(f'{path}: {methods}')
"
שאלות¶
- האם מצאתם קובץ תיעוד API?
- כמה נקודות קצה מתועדות?
- האם יש נקודות קצה שנראות רגישות (admin, debug, internal)?
חלק ב - אינטרוספקציה של GraphQL¶
משימה 3 - חקירת GraphQL¶
- הפעילו את מעבדת GraphQL הפגיעה:
- ודאו שהשירות רץ:
curl -s "http://localhost:5013/graphql" -X POST \
-H "Content-Type: application/json" \
-d '{"query": "{ __typename }"}'
- בצעו שאילתת אינטרוספקציה:
curl -s -X POST "http://localhost:5013/graphql" \
-H "Content-Type: application/json" \
-d '{"query": "{ __schema { types { name kind fields { name type { name kind ofType { name } } args { name type { name } } } } } }"}' | python3 -m json.tool > introspection.json
- נתחו את הסכמה:
# Show all types (excluding system types)
python3 -c "
import json
with open('introspection.json') as f:
data = json.load(f)
types = data['data']['__schema']['types']
for t in types:
if not t['name'].startswith('__') and t.get('fields'):
print(f'\nType: {t[\"name\"]}')
for f in t['fields']:
fname = f['name']
ftype = f['type'].get('name') or f['type'].get('ofType', {}).get('name', '?')
args = [a['name'] for a in f.get('args', [])]
args_str = f'({', '.join(args)})' if args else ''
print(f' - {fname}{args_str}: {ftype}')
"
משימה 4 - exploit GraphQL¶
- מתוך הסכמה שגיליתם, נסו:
- לקבל רשימת כל המשתמשים
- לקרוא הודעות פרטיות
-
לבצע מוטציה שמשנה הרשאות
-
נסו שאילתות batch:
curl -s -X POST "http://localhost:5013/graphql" \
-H "Content-Type: application/json" \
-d '[
{"query": "{ user(id: 1) { username } }"},
{"query": "{ user(id: 2) { username } }"},
{"query": "{ user(id: 3) { username } }"}
]'
- נסו שאילתות עם depth גבוה (Nested Queries):
שאלות¶
- אילו טיפוסים מצאתם בסכמה?
- האם הצלחתם לגשת לנתונים רגישים?
- האם יש הגבלת עומק שאילתות (query depth limiting)?
- האם batch queries עובדות?
חלק ג - מיפוי גרסאות API¶
משימה 5 - גילוי גרסאות API¶
- כתבו סקריפט שבודק גרסאות API:
# api_version_scan.py
import requests
base_url = "http://localhost:3000"
endpoints = ["/users", "/products", "/orders", "/admin", "/config"]
versions = ["", "/api", "/api/v1", "/api/v2", "/api/v3", "/rest", "/rest/v1"]
for version in versions:
for endpoint in endpoints:
url = f"{base_url}{version}{endpoint}"
try:
resp = requests.get(url, timeout=5, verify=False)
if resp.status_code != 404:
print(f"[{resp.status_code}] {url} (length: {len(resp.text)})")
except:
pass
- הריצו את הסקריפט נגד Juice Shop:
- השוו בין תגובות גרסאות שונות - האם גרסה ישנה חושפת מידע נוסף?
משימה 6 - בדיקת הבדלים בין גרסאות¶
- עבור כל זוג גרסאות שמצאתם, השוו את התגובות:
# Example
curl -s "http://localhost:3000/api/Users" | python3 -m json.tool > v1_users.json
curl -s "http://localhost:3000/rest/user/login" | python3 -m json.tool > rest_login.json
- בדקו האם גרסאות שונות מחזירות שדות שונים
חלק ד - גילוי נקודות קצה לא מתועדות¶
משימה 7 - סריקה מתקדמת¶
- צרו רשימת מילים ממוקדת API:
cat > api_wordlist.txt << 'EOF'
users
user
admin
login
logout
register
signup
password
reset
forgot
profile
settings
config
configuration
debug
test
health
status
info
version
metrics
stats
logs
audit
backup
export
import
upload
download
search
query
token
session
auth
authenticate
authorize
role
permission
secret
key
api-key
webhook
callback
notify
email
send
verify
confirm
activate
deactivate
delete
remove
update
create
list
get
post
put
patch
flag
feature
internal
private
public
docs
swagger
schema
graphql
EOF
- סרקו עם ffuf:
# Scan endpoints directly
ffuf -u "http://localhost:3000/api/FUZZ" -w api_wordlist.txt -mc all -fc 404
# Scan endpoints with REST
ffuf -u "http://localhost:3000/rest/FUZZ" -w api_wordlist.txt -mc all -fc 404
- עבור כל נקודת קצה שמצאתם, בדקו שיטות HTTP שונות:
# Check HTTP methods
for method in GET POST PUT DELETE PATCH OPTIONS; do
status=$(curl -s -o /dev/null -w "%{http_code}" -X $method "http://localhost:3000/api/ENDPOINT")
echo "[$status] $method /api/ENDPOINT"
done
משימה 8 - בדיקת אותנטיקציה¶
- עבור כל נקודת קצה רגישה שמצאתם, בדקו:
# Without authentication
curl -s "http://localhost:3000/api/admin/users"
# With spoofed headers
curl -s "http://localhost:3000/api/admin/users" -H "X-Forwarded-For: 127.0.0.1"
curl -s "http://localhost:3000/api/admin/users" -H "Authorization: Bearer null"
# With special parameters
curl -s "http://localhost:3000/api/admin/users?admin=true"
curl -s "http://localhost:3000/api/admin/users?debug=1"
חלק ה - כתיבת סקריפט מיפוי מלא¶
משימה 9 - סקריפט API Mapper¶
כתבו סקריפט Python שמבצע מיפוי API מלא:
# api_mapper.py - skeleton
import requests
import json
class APIMapper:
def __init__(self, base_url):
self.base_url = base_url
self.endpoints = []
self.session = requests.Session()
self.session.verify = False
def check_swagger(self):
"""Check for Swagger documentation"""
# TODO
pass
def check_graphql(self):
"""Check for GraphQL"""
# TODO
pass
def scan_endpoints(self, wordlist_path):
"""Scan endpoints"""
# TODO
pass
def test_methods(self, endpoint):
"""Check allowed HTTP methods"""
# TODO
pass
def check_auth(self, endpoint):
"""Check authentication"""
# TODO
pass
def report(self):
"""Show final report"""
# TODO
pass
if __name__ == "__main__":
mapper = APIMapper("http://localhost:3000")
mapper.check_swagger()
mapper.check_graphql()
mapper.scan_endpoints("api_wordlist.txt")
mapper.report()
השלימו את הפונקציות והריצו נגד Juice Shop.
מעבדות PortSwigger מומלצות¶
בצעו את המעבדות הבאות:
- Exploiting an API endpoint using documentation - ניצול API דרך תיעוד נגיש
- Finding and exploiting an unused API endpoint - מציאת נקודת קצה לא בשימוש
- Exploiting a mass assignment vulnerability - ניצול חולשת mass assignment
- Accessing a GraphQL API using introspection (אם זמינה) - אינטרוספקציה של GraphQL
קישור: https://portswigger.net/web-security/api-testing
שאלות סיכום¶
- מה ההבדל בין REST API ל-GraphQL מבחינת משטח תקיפה?
- למה חשוב לבדוק גרסאות API ישנות?
- כיצד שאילתת אינטרוספקציה יכולה לחשוף מידע רגיש?
- מה הם הסיכונים של API ללא אותנטיקציה?
- כיצד ניתן לגלות נקודות קצה שאינן מתועדות?