חקירת 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, נתחו אותו:
# הורדת וניתוח
curl -s "http://localhost:3000/api-docs" | python3 -m json.tool > api_docs.json
# חילוץ נקודות קצה
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
- נתחו את הסכמה:
# הצגת כל הטיפוסים (ללא טיפוסי מערכת)
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 - ניצול 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 - בדיקת הבדלים בין גרסאות¶
- עבור כל זוג גרסאות שמצאתם, השוו את התגובות:
# דוגמה
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:
# סריקת נקודות קצה ישירות
ffuf -u "http://localhost:3000/api/FUZZ" -w api_wordlist.txt -mc all -fc 404
# סריקת נקודות קצה עם REST
ffuf -u "http://localhost:3000/rest/FUZZ" -w api_wordlist.txt -mc all -fc 404
- עבור כל נקודת קצה שמצאתם, בדקו שיטות HTTP שונות:
# בדיקת שיטות HTTP
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 - בדיקת אותנטיקציה¶
- עבור כל נקודת קצה רגישה שמצאתם, בדקו:
# ללא אותנטיקציה
curl -s "http://localhost:3000/api/admin/users"
# עם כותרות מזויפות
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"
# עם פרמטרים מיוחדים
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 - שלד
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):
"""בדיקת קיום תיעוד Swagger"""
# השלימו
pass
def check_graphql(self):
"""בדיקת קיום GraphQL"""
# השלימו
pass
def scan_endpoints(self, wordlist_path):
"""סריקת נקודות קצה"""
# השלימו
pass
def test_methods(self, endpoint):
"""בדיקת שיטות HTTP מותרות"""
# השלימו
pass
def check_auth(self, endpoint):
"""בדיקת אותנטיקציה"""
# השלימו
pass
def report(self):
"""הצגת דוח סופי"""
# השלימו
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 ללא אותנטיקציה?
- כיצד ניתן לגלות נקודות קצה שאינן מתועדות?