לדלג לתוכן

אתגר CTF - צד לקוח - תרגיל

סקירה כללית

האתגר הזה מורכב מארבעה שלבים שמשלבים את כל הטכניקות שנלמדו בפרק 4. כל שלב מבוסס על השלב הקודם. המטרה הסופית היא לגנוב את ה-flag מחשבון ה-admin.


שלב 1: עקיפת CSP והרצת XSS

תיאור

אתר הבלוג https://target-blog.ctf מאפשר הוספת תגובות. התגובות מנוקות עם DOMPurify ומוצגות בדף. האתר משתמש ב-CSP הבא:

Content-Security-Policy: default-src 'none'; script-src 'self' https://cdnjs.cloudflare.com 'nonce-{RANDOM}'; style-src 'self'; img-src *; connect-src 'self'; frame-src 'none'; base-uri 'self'

משימה

הריצו alert(document.domain) בדף הבלוג.

רמזים

  1. בדקו אילו ספריות נטענות מ-cdnjs
  2. חפשו ספריית JavaScript שמאפשרת template injection
  3. זכרו - DOMPurify מאפשר HTML אבל חוסם event handlers
  4. שלבו CDN bypass עם template injection

שאלות מנחות

  • מה הגרסה של AngularJS שזמינה ב-cdnjs?
  • האם AngularJS sandbox escape עובד בגרסה הזו?
  • איזה attribute צריך כדי להפעיל AngularJS על אלמנט?
  • האם DOMPurify מאפשר את ה-attributes האלה?

שלב 2: זיהום פרוטוטייפ להסלמה ל-Stored XSS

תיאור

אחרי שמצאתם XSS ב-self context, אתם צריכים להפוך אותו ל-stored XSS שישפיע על משתמשים אחרים. האתר כולל מערכת "תגובות" שמשתמשת ב-API הבא:

// קוד הלקוח
async function loadComments(postId) {
  let response = await fetch('/api/comments/' + postId);
  let comments = await response.json();

  let config = {};
  comments.forEach(function(comment) {
    mergeConfig(config, comment.metadata || {});
  });

  comments.forEach(function(comment) {
    renderComment(comment, config);
  });
}

function mergeConfig(target, source) {
  for (let key in source) {
    if (typeof source[key] === 'object' && source[key] !== null) {
      if (!target[key]) target[key] = {};
      mergeConfig(target[key], source[key]);
    } else {
      target[key] = source[key];
    }
  }
}

function renderComment(comment, config) {
  let div = document.createElement('div');
  div.className = 'comment';

  let template = config.commentTemplate || '<b>{author}</b>: {text}';
  let html = template.replace('{author}', escapeHtml(comment.author))
                      .replace('{text}', escapeHtml(comment.text));

  div.innerHTML = html;
  document.getElementById('comments').appendChild(div);
}

משימה

השתמשו בזיהום פרוטוטייפ דרך metadata של תגובה כדי לשנות את commentTemplate ולהזריק XSS ל-stored context.

רמזים

  1. הפונקציה mergeConfig פגיעה לזיהום פרוטוטייפ
  2. שדה metadata של תגובה מגיע מה-API
  3. אם תשלחו תגובה עם metadata שמכיל __proto__, תוכלו לזהם את Object.prototype
  4. config.commentTemplate ייקרא מהפרוטוטייפ אם לא מוגדר ישירות

שאלות מנחות

  • מה ה-JSON שצריך לשלוח ב-POST לפי API?
  • איך ה-template שלכם יכול לכלול XSS אם escapeHtml מופעל על author ו-text?
  • האם יש חלק ב-template שלא עובר escape?

שלב 3: שיבוש DOM לשיבוש הגדרות האפליקציה

תיאור

ה-admin panel באתר משתמש בקוד הבא לטעינת הגדרות:

// admin.js
(function() {
  let appConfig = window.APP_CONFIG || {};
  let apiEndpoint = appConfig.apiEndpoint || '/api';
  let adminPanel = appConfig.adminPanelUrl || '/admin';

  // טעינת נתוני admin
  fetch(apiEndpoint + '/admin/data', {
    credentials: 'include',
    headers: {
      'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').content
    }
  })
  .then(function(r) { return r.json(); })
  .then(function(data) {
    document.getElementById('admin-data').textContent = JSON.stringify(data);
  });

  // טעינת סקריפט נוסף
  if (appConfig.extraScript) {
    let s = document.createElement('script');
    s.src = appConfig.extraScript;
    document.body.appendChild(s);
  }
})();

משימה

השתמשו ב-DOM clobbering (דרך ה-stored XSS מהשלב הקודם) כדי:
1. לשבש את window.APP_CONFIG
2. לגרום לטעינת סקריפט מהשרת שלכם
3. הסקריפט שלכם יאסוף את ה-CSRF token מהדף

רמזים

  1. הזריקו HTML שיוצר אלמנטים עם id="APP_CONFIG"
  2. השתמשו ב-collection clobbering (שני אלמנטי <a> עם אותו id)
  3. appConfig.extraScript צריך להחזיר URL - השתמשו ב-<a> עם href

שאלות מנחות

  • איזה HTML payload ידרוס window.APP_CONFIG.extraScript?
  • האם DOMPurify מאפשר אלמנטי <a> עם id ו-href?
  • מה הסקריפט שלכם צריך לעשות אחרי שנטען?

שלב 4: הזרקת CSS לחילוץ CSRF Token של ה-admin

תיאור

אחרי שלב 3, אתם צריכים את ה-CSRF token של ה-admin כדי לבצע פעולת "Export All Data" שמחזירה את ה-flag. ה-CSRF token נמצא ב:

<meta name="csrf-token" content="a7f3b2c9d1e4f5a6b7c8d9e0f1a2b3c4">

ה-CSP מגביל סקריפטים, אבל style-src 'self' מאפשר CSS מהאתר עצמו. יש נקודת הזרקה ב-CSS:

<link rel="stylesheet" href="/css/theme?color=USER_INPUT">

משימה

  1. השתמשו בהזרקת CSS כדי לחלץ את ה-CSRF token תו אחר תו
  2. השתמשו ב-token כדי לשלוח בקשת POST ל-/admin/export
  3. קבלו את ה-flag

רמזים

  1. הזריקו CSS דרך פרמטר ה-color
  2. השתמשו ב-attribute selectors על meta tag
  3. צרו שרת שמקבל את התווים ומחזיר CSS חדש
  4. השתמשו ב-@import לטעינה סדרתית

שאלות מנחות

  • איך אפשר להפוך meta tag ל-visible כדי שהדפדפן יטען background?
  • מה ה-CSS payload שיחלץ את התו הראשון?
  • איך מפעילים את החילוץ מהדפדפן של ה-admin?

משאבים נוספים

מעבדות PortSwigger מומלצות

מעבדה נושא רמה
CSP bypass עקיפת CSP Expert
Prototype pollution to XSS זיהום פרוטוטייפ Practitioner
DOM clobbering שיבוש DOM Expert
DOM XSS via postMessage ניצול postMessage Practitioner
WebSocket vulnerabilities תקיפות WebSocket Practitioner

אתגרי HackTheBox ו-CTF

אתגר תיאור
HackTheBox - CSP Bypass challenges אתגרי עקיפת CSP ברמות שונות
XSS Game by Google אתגרי XSS מרמת מתחיל עד מתקדם
alert(1) to win אתגרי XSS מתקדמים
Cure53 XSS challenges אתגרי mXSS ו-DOM clobbering
CTFtime.org - Web challenges אתגרי CTF בתחום web

טיפים כלליים לפתרון

מתודולוגיה

1. סקרו את קוד המקור בקפידה
2. זהו את ה-CSP ומצאו חולשות
3. מצאו את כל ה-sinks (innerHTML, eval, location, etc.)
4. מצאו את כל ה-sources (URL params, postMessage, WebSocket, etc.)
5. שרטטו את זרימת המידע מ-source ל-sink
6. חפשו gadgets (prototype pollution, DOM clobbering)
7. בנו את שרשרת הניצול שלב אחר שלב
8. בדקו כל שלב בנפרד לפני שמחברים

כלים שימושיים

- Burp Suite - יירוט ומניפולציה של תעבורה
- DevTools Console - בדיקת payloads
- DevTools Application > Service Workers - ניטור SW
- CSP Evaluator - ניתוח מדיניות CSP
- DOMPurify test page - בדיקת payloads נגד DOMPurify

שגיאות נפוצות

  • שכחה לקודד (encode) תווים מיוחדים ב-URL
  • אי התחשבות ב-Content-Type של תגובות
  • אי בדיקה שה-payload עובר DOMPurify
  • שכחה שצריך HTTPS ל-Service Workers
  • אי התחשבות ב-SameSite cookies