← חזרה לרשימת המאמרים

Scapy-TLS-Packet-Crafter: Custom TLS 1.2 Handshake Generation

מאת שי מרדכי | 17 ביוני 2025 | פרויקט רשתות מתקדמות ע"י ברק גונן

רקע ומוטיבציה במילואים

הפרויקט הזה נולד ופותח במהלך שירות מילואים ממושך תחת תנאי לחימה. הצורך להישאר ממוקד במטרות אקדמיות ומחקריות ולשמר חדות טכנית הוביל אותי לצלילה עמוקה אל תוך ה-RFC של פרוטוקול TLS 1.2. רציתי להבין את הארכיטקטורה לא רק כמשתמש, אלא כמהנדס – ולכן בניתי מערכת המדמה באופן מלא את תהליך ה-Handshake ברמת הביט והבייט (Protocol Engineering).

מהות התשתית והאתגר הטכני

מטרת הפרויקט היא לייצר קובץ PCAP תקני המדמה תעבורת רשת של שרת ושני לקוחות המבצעים לחיצת יד מלאה של TLS 1.2. הפרויקט אינו משתמש בספריות SSL/TLS מוכנות של מערכת ההפעלה, אלא מרכיב את חבילות המידע ידנית (Packet Crafting) באמצעות Scapy ו-Cryptography.

הקוד כולל מעל 4,030 שורות קוד המתפרסות על פני 22 מודולים בפייתון, ומיישם מאפס את שלבי ה-Handshake, ניהול המפתחות (Key Management), ואימות התעודות (Certificate Validation).

צלילה למימוש הליבה (Core Implementation)

1. יצירת ה-Client Hello וה-SNI

השלב הראשון דורש יצירת מספר אקראי קריפטוגרפי ובניית ה-Extensions, כולל ה-SNI (Server Name Indication). כך מימשתי את בניית החבילה:

def create_client_hello(session: object, extensions: Optional[ClientExtensions] = None) -> TLSClientHello:
    # Generate client random as one piece securely
    session.client_random = os.urandom(32)
    
    # Extract GMT time and random bytes for TLSClientHello
    gmt_time = int.from_bytes(session.client_random[:4], 'big')
    random_bytes = session.client_random[4:]

    if not extensions:
        extensions = ClientExtensions(
            server_name=session.sni,
            supported_groups=["x25519"],
            signature_algorithms=["sha256+rsa"]
        )

    return TLSClientHello(
        version=TLSVersion.TLS_1_2,
        ciphers=[TLS_RSA_WITH_AES_128_CBC_SHA256],
        ext=extensions.get_extension_list(),
        gmt_unix_time=gmt_time,
        random_bytes=random_bytes
    )

2. חישוב ה-Master Secret (מנגנון PRF)

אחד האתגרים הקריפטוגרפיים בפרוטוקול הוא גזירת ה-Master Secret מתוך ה-Pre-Master Secret. ב-TLS 1.2, פעולה זו מבוצעת באמצעות פונקציה פסאודו-אקראית (Pseudo-Random Function - PRF) המבוססת על HMAC-SHA256.

def generate_master_secret(pre_master_secret: bytes, client_random: bytes, server_random: bytes) -> bytes:
    # TLS 1.2 PRF uses HMAC-SHA256 for key expansion
    seed = b"master secret" + client_random + server_random
    
    # Generate 48-byte master secret using PRF (P_hash)
    master_secret = P_hash(pre_master_secret, seed, 48)
    
    return master_secret

3. הצפנת ה-Application Data

לאחר הקמת המפתח, המידע האפליקטיבי מוצפן בשיטת AES-128-CBC. הייתי חייב להטמיע מנגנון HMAC כדי להבטיח את שלמות הנתונים (Data Integrity) ולהוסיף PKCS#7 Padding כדי לעמוד בדרישות הבלוקים של AES.

def encrypt_application_data(plaintext: bytes, seq_num: int, key_block: KeyBlock, is_client: bool) -> bytes:
    # Compute HMAC over seq_num + type + version + length + plaintext
    mac_data = (
        seq_num.to_bytes(8, 'big') +
        b'\x17' +  # Application Data type
        TLSVersion.TLS_1_2.value.to_bytes(2, 'big') +
        len(plaintext).to_bytes(2, 'big') +
        plaintext
    )
    mac = hmac.new(mac_key, mac_data, hashlib.sha256).digest()
    
    # Create plaintext with MAC and PKCS#7 padding for CBC
    plaintext_with_mac = plaintext + mac
    pad_length = 16 - (len(plaintext_with_mac) % 16)
    padding = bytes([pad_length - 1] * pad_length)
    padded_plaintext = plaintext_with_mac + padding
    
    # Encrypt using AES-128-CBC
    cipher = Cipher(algorithms.AES(enc_key), modes.CBC(iv))
    encryptor = cipher.encryptor()
    return encryptor.update(padded_plaintext) + encryptor.finalize()

פתרון בעיות ושילוב Wireshark

במהלך הפיתוח, התמודדתי עם אתגר מורכב בשלב הפענוח (Decryption) של ה-Application Data ב-Wireshark. הבאג נבע מאי-התאמה של מבני ה-Padding וה-MAC שחושבו בסוף התהליך. כדי לפתור זאת ולייצר תאימות מלאה, פיתחתי מנגנון אוטומטי שגנרט קובץ SSLKEYLOGFILE בזמן הריצה (המכיל את ה-CLIENT_RANDOM וה-master_secret). ניתוח מעמיק מול ה-Dissector של Wireshark איפשר לי לדייק את פריסת חבילות ה-Binary המוצפנות ולתקן את ה-MAC.

סיכום

התשתית מייצרת קובץ הסנפה תקני (capture.pcap) ופלט של מפתחות פיענוח. הפרויקט משמש כיום כבסיס מחקרי לבחינת התנהגות מפענחי רשת (Network Dissectors), חתימות פרוטוקולים, והבנה לעומק של אבטחת רשתות.

לצפייה בקוד המלא, בקרו ב-Repository בגיטהאב: scapy-tls-pcap-creator