Skip to content
KitploitKITPLOIT
أدواتالمدونة
إرسال
أدواتالمدونة
إرسال

أدوات الاختراق واختبار الاختراق والأمن السيبراني لترسانتك الأمنية!

Kitploit هو دليل لأدوات الاختراق والأمن السيبراني واختبار الاختراق. اكتشف آخر تحديثات المشاريع للعثور على الثغرات وتحليل الأنظمة وأتمتة الاختبارات وتعزيز أمنك.

··الخلاصات·اتصال·الخصوصية·© 2026 Kitploit

دليل الأدوات

الفئات

عرض جميع الفئات
Loading categories
wix-kickstartx-challenge-writeup — شرح مفصّل لتحدي CTF: هندسة عكسية لتطبيق SPA مبني على React، وتحليل صور SVG، وبناء حلّال آلي باستخدام المطابقة الجشعة، وتحقيق علامة كاملة. | Kitploit
أدوات/GitHubGitHub/d0rb/wix-kickstartx-challenge-writeup
الهندسة العكسيةCTFالتعلم والتعليم
GitHubd0rb/wix-kickstartx-challenge-writeup

wix-kickstartx-challenge-writeup

شرح مفصّل لتحدي CTF: هندسة عكسية لتطبيق SPA مبني على React، وتحليل صور SVG، وبناء حلّال آلي باستخدام المطابقة الجشعة، وتحقيق علامة كاملة.

عرض المستودع

الأكثر شعبية

عرض الكل →

اكتشف الأدوات الأكثر استخدامًا من قبل مجتمعنا.

استكشف جميع الأدوات

تصفح مجموعتنا من الأدوات

عرض جميع الأدوات →
مشاركة
منذ 3 أشهرلم تتم المراجعة بعد

Wix KickstartX Challenge 2026 — الشرح الكامل

النتيجة: 200/200 (100%) — الرمز: WKX-9245FA70-200 التاريخ: 24 مارس 2026


1. الاكتشاف والاستطلاع

الإعلان عن التحدي

أعلن منشور على LinkedIn عن تحدٍّ خاص لبرنامج Wix KickstartX — وهو برنامج للمطوّرين المبتدئين. القواعد:

  • 30 دقيقة، محاولة واحدة فقط
  • أفضل 10 درجات أعلى يتأهلون مباشرة إلى مرحلة الامتحان
  • تم توفير رابطين: wix-kickstartx-challenge-2026.base44.app/ و wixkickstart.com

العثور على نقطة دخول التحدي

الموقع الرئيسي wixkickstart.com هو موقع مستضاف على Wix (يُقدَّم من جانب الخادم بواسطة محرك Thunderbolt الخاص بـ Wix). لا يُرجع أمر curl العادي سوى هيكل JavaScript — دون أي محتوى فعلي. استخدمنا متصفح Chromium بدون واجهة رسومية (headless) لعرضه:

root@kitploit:~
chromium --headless --disable-gpu --no-sandbox --virtual-time-budget=10000 \
  --dump-dom "https://wixkickstart.com" > /tmp/wix_rendered.html

من DOM المعروض، استخرجنا iframe مضمّنًا:

root@kitploit:~

اتضح أنه رسم متحرك جسيمات p5.js (عنصر جمالي في القسم الرئيسي)، وليس التحدي نفسه. التحدي الفعلي موجود في تطبيق Base44.


2. الهندسة العكسية لتطبيق التحدي

المنصة: Base44

يعمل التحدي على Base44 — وهي منصة تطبيقات منخفضة الكود (low-code). التطبيق هو تطبيق React أحادي الصفحة، وكل المنطق في حزمة JS واحدة:

root@kitploit:~
https://wix-kickstartx-challenge-2026.base44.app/assets/index-oTG160r9.js

الحجم: 410,809 بايت (React مُصغَّر + منطق التطبيق + Base44 SDK)

استخراج سطح الـ API

من خلال البحث في حزمة JS، قمنا بتخطيط الـ API بالكامل:

الكيانات: GameSession، Participant

نمط عنوان API:

root@kitploit:~
POST /api/apps/{appId}/functions/{functionName}

معرّف التطبيق: 69aea07cbcb9a3dd1039a58d

الثوابت الأساسية من الحزمة

root@kitploit:~
const or = 1800;   // Time limit: 1800 seconds (30 minutes)
const rm = 200;    // Total items: 200 image-description pairs

اكتشاف آلية الإرسال JSON

اكتشاف بالغ الأهمية — التطبيق يحتوي على وضع إرسال جماعي JSON. من المصدر المُصغَّر:

root@kitploit:~
function Ik({onSubmit:r, onClose:n}) {
    // ...
    h = JSON.parse(s)  // Parse JSON input
    // Validation: must be object like { "IMG-001": "DESC-042", ... }
    r(h)  // Submit all matches at once
}

النص النموذجي داخل النافذة المنبثقة:

root@kitploit:~
{
  "IMG-001": "DESC-042",
  "IMG-002": "DESC-017",
  ...
}

هذا يعني أننا لا نحتاج إلى النقر 200 مرة في الواجهة — يمكننا إرسال خريطة JSON لجميع المطابقات الـ200 برمجيًا.

تدفق المصادقة

يستخدم SDK الخاص بـ Base44 مصادقة JWT:

root@kitploit:~
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

حمولة JWT تحتوي على:

root@kitploit:~
{
  "sub": "[email protected]",
  "exp": 1782162460,
  "iat": 1774386460
}

الترويسات المطلوبة لجميع استدعاءات API:

root@kitploit:~
Content-Type: application/json
Authorization: Bearer {jwt_token}
X-App-Id: 69aea07cbcb9a3dd1039a58d
Base44-Functions-Version: prod
X-Origin-URL: https://wix-kickstartx-challenge-2026.base44.app/

3. فهم بيانات اللعبة

استجابة startGame

root@kitploit:~
POST /api/apps/69aea07cbcb9a3dd1039a58d/functions/startGame
Status: 200
Transferred: 62.87 kB compressed (2.20 MB decompressed)
Content-Encoding: br (Brotli)

بنية الاستجابة:

root@kitploit:~
{
  "status": "active",
  "sessionId": "69c2fd218e5b26f307c941c9",
  "startedAt": "2026-03-24T21:07:45.101Z",
  "imageOrder": ["IMG-154", "IMG-102", ...],   // 200 items (display order)
  "descOrder": ["DESC-125", "DESC-109", ...],  // 200 items (display order)
  "imagesData": { "IMG-001": "data:image/svg+xml;base64,...", ... },  // 200 SVGs
  "descriptionsData": { "DESC-105": "milky field, overlaid with...", ... }  // 200 texts
}

تنسيق الصور: SVG مضمّن (مشفّر base64)

كل صورة هي SVG بأبعاد 200x200 تحتوي على:

  1. تدرّج خلفية (بثيم فاتح أو داكن)
  2. نمط تراكب اختياري (خطوط، نقاط، حلقات، إلخ)
  3. أشكال هندسية بألوان وأحجام وشفافية ودوران ومواضع محددة

مثال لـ SVG مفكوك الترميز (IMG-001):

root@kitploit:~
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 200 200">
  <defs>
    <linearGradient id="bg" ...>
      <stop offset="0%" stop-color="#f5f0eb"/>
      <stop offset="100%" stop-color="#e8e0d5"/>
    </linearGradient>
  </defs>
  <rect width="200" height="200" fill="url(#bg)"/>
  <!-- Optional overlay lines/dots/rings here -->
  <polygon points="..." fill="#E2725B" transform="translate(128.6,185.7) rotate(90)"
           style="opacity:0.5;filter:drop-shadow(...)"/>
  <!-- More shapes... -->
</svg>

تنسيق الوصف: لغة طبيعية منظمة

كل وصف يتبع نمطًا صارمًا:

root@kitploit:~
{background} field[, overlaid with {overlay}]. {N} elements total:
{size} {opacity} {color} {shape} ({rotation}, at {position}) ·
{size} {opacity} {color} {shape} ({rotation}, at {position}) · ...

مثال:

root@kitploit:~
milky field, overlaid with tilted cross-lines. 10 elements total:
minuscule nearly solid dim gray pike (steeply angled, at center inner-left) ·
substantial solid azure pike (diagonal, at top center) · ...

4. بناء الحلّال الآلي

الخطوة 1: تخطيط جميع الثوابت

احتجنا إلى ربط خصائص SVG بمفردات الوصف. تطلّب ذلك تحليل جميع الصور الـ200 وجميع الأوصاف الـ200 للعثور على التطابقات الدقيقة.

تخطيط الخلفية (12 نوعًا)

من خلال عدّ مرات الظهور في الجانبين، أنشأنا تطابقًا 1:1:

الطريقة: عدّ ألوان بداية التدرج الفريدة في جميع ملفات SVG الـ200، وعدّ الكلمة الأولى الفريدة في جميع الأوصاف الـ200، ثم المطابقة بناءً على العدد.

تخطيط التراكب (7 أنواع)

تراكبات SVG مُنفَّذة بطرق مختلفة حسب النوع:

الملاحظة الأساسية: عناصر نمط الخلفية تستخدم opacity كـ سمة XML (مثل opacity="0.06")، بينما تستخدم الأشكال الأمامية opacity داخل سمة style (مثل style="opacity:0.7"). كان هذا التمييز حاسمًا لفصل أنماط الخلفية عن الأشكال الفعلية.

تخطيط الألوان (28 لونًا)

جميع ملفات SVG الـ200 تستخدم 28 لون تعبئة hex فريدًا بالضبط. وجميع الأوصاف الـ200 تستخدم 28 اسم لون فريدًا بالضبط.

تخطيط أنواع الأشكال (10 أنواع)

تخطيط الأحجام

استنادًا إلى أقصى نصف قطر لرؤوس الشكل من نقطة الأصل:

تخطيط الشفافية

قيمة شفافية SVGاسم الوصف
1.0solid
0.85nearly solid
0.7semi-transparent
0.5

تخطيط الدوران

شبكة المواضع

تُوضع الأشكال على شبكة 7x7 عند الإحداثيات:

root@kitploit:~
[14.3, 42.9, 71.4, 100.0, 128.6, 157.1, 185.7]

هذه تُرتبط بأسماء الأعمدة: far-left, left, inner-left, center, inner-right, right, far-right وبأسماء الصفوف: top, upper, upper-mid, center, lower-mid, lower, bottom

الخطوة 2: تحليل جميع ملفات SVG

لكل صورة من صور SVG الـ200:

  1. فكّ ترميز base64 إلى SVG XML خام
  2. استخراج الخلفية — قراءة لون أول <stop> من <linearGradient id="bg">
  3. تصنيف التراكب — التحقق من وجود <line> أو <circle fill="none" stroke> أو نقاط/أشكال منخفضة الشفافية
  4. استخراج الأشكال — العثور على جميع عناصر <polygon> و <circle> و <path> و <rect> التي:
    • ليست مستطيل الخلفية (تخطَّ width="200")
    • ليست مستطيل التظليل (تخطَّ fill="url(#vig)")
    • ليست عناصر نمط التراكب (تخطَّ opacity="0.0x" كسمة)
    • تملك style="opacity:..." (جميع الأشكال الأمامية تملك هذا)
  5. ، استخرج:

الخطوة 3: تحليل جميع الأوصاف

لكل وصف نصي من الأوصاف الـ200:

  1. الخلفية: الكلمة الأولى (مثل "milky"، "pitch"، "tenebrous")
  2. التراكب: النص بعد "overlaid with" في الجملة الأولى
  3. عدد الأشكال: التعبير النمطي (\d+) elements total
  4. الأشكال الفردية: نمط التعبير النمطي:
root@kitploit:~
   (minuscule|modest|mid-sized|substantial|massive)
   (solid|nearly solid|semi-transparent|faint)
   (color name)
   (shape type)
   ((rotation), at (position))

الخطوة 4: المطابقة القائمة على الدرجات

تستخدم خوارزمية المطابقة نهج التسجيل الجشع:

root@kitploit:~
def score_match(img, desc):
    # Hard constraints — must match exactly
    if img['num'] != desc['num']:      return -10000  # Shape count
    if img['bg'] != desc['bg']:        return -10000  # Background type
    if img['overlay'] != desc['overlay']: return -10000  # Overlay type

    score = 100  # Base score for matching hard constraints

    # Soft scoring — color overlap
    for color in img_colors:
        if color in desc_colors:
            score += 10

    # Soft scoring — type overlap
    for type in img_types:
        if type in desc_types:
            score += 8

    # Per-shape detail matching (Hungarian-style greedy)
    for each image_shape:
        find best matching desc_shape by:
            +20 if color matches
            +15 if type matches
            +10 if size matches
            +8  if opacity matches
            +5  if rotation matches
        score += best_match_score

    return score

ثم نخصّص الأزواج الأعلى درجة أولًا بطريقة جشعة:

root@kitploit:~
all_scores.sort(reverse=True)
for score, img_id, desc_id in all_scores:
    if img_id not in matched and desc_id not in used:
        matches[img_id] = desc_id

5. التنفيذ والإرسال

استدعاءات API المنفَّذة

1. Start Game

root@kitploit:~
POST /api/apps/69aea07cbcb9a3dd1039a58d/functions/startGame
Body: {"email": "[email protected]"}
Response: 200 OK (2.2 MB — all game data)

2. Score Game

root@kitploit:~
POST /api/apps/69aea07cbcb9a3dd1039a58d/functions/scoreGame
Body: {
  "matches": {"IMG-032": "DESC-182", "IMG-198": "DESC-134", ...},
  "sessionId": "69c2fd218e5b26f307c941c9"
}
Response: 200 OK
{"correctCount": 200, "scoreSeal": "3d1ac8a7e7be4856"}

3. Generate Token

root@kitploit:~
POST /api/apps/69aea07cbcb9a3dd1039a58d/functions/generateToken
Body: {"sessionId": "69c2fd218e5b26f307c941c9"}
Response: 200 OK
{"token": "WKX-9245FA70-200", "score": 200}

الخط الزمني

الخطوةالإجراء
21:07:45 UTCبدأت اللعبة (تم استدعاء startGame)
21:07–21:15تطوير سكربت الحلّال (التحليل + المطابقة)
~21:15تم إرسال scoreGame —

إجمالي وقت الحل: ~8 دقائق من نافذة مدتها 30 دقيقة.


6. ملخص التقنيات المستخدمة


7. الرؤى الأساسية

لماذا نجح هذا

  1. نقطة الإرسال JSON كانت العامل الحاسم — دونها، كنا سنحتاج إلى أتمتة المتصفح للنقر 400 مرة (اختيار الصورة + اختيار الوصف × 200).

  2. التخطيط القائم على العدّ كان الاختراق للألوان والخلفيات والتراكبات. بدلًا من تخمين ما يقابله اللون السداسي #cd7f32 بالإنجليزية، عددنا مرات ظهوره في ملفات SVG فوجدناه 65 مرة، ووجدنا "brass" تظهر 65 مرة في الأوصاف — العدد الفريد = تطابق مضمون.

  3. القيود الصارمة تستبعد المرشحين بسرعة. كل صورة لها تركيبة فريدة من (نوع الخلفية، نوع التراكب، عدد الأشكال). مع 12 خلفية × 7 تراكبات × أعداد أشكال متفاوتة، معظم الصور لديها حفنة فقط من أوصاف المرشحين المحتملين، وليس 200.

  4. SVG بيانات منظمة. على عكس الصور النقطية (PNG/JPG)، فإن SVGs هي XML — كل شكل ولون وموضع ودوران مشفَّر صراحةً كنص. لا حاجة لرؤية حاسوبية.

ما الذي جعله صعبًا

  1. كان اكتشاف التراكب صعبًا. استخدمت أنماط الخلفية 5 تقنيات SVG مختلفة: عناصر <line>، و <circle> بحدود فقط، و <circle> بسمة شفافية منخفضة، و <polygon> بسمة شفافية منخفضة، وغياب كل هذه. التمييز الأساسي كان opacity كسمة XML (للخلفية) مقابل داخل style (لأشكال المقدمة).

  2. مفردات الألوان لم تكن واضحة. أسماء مثل "oxblood" (#800020) و"brass" (#cd7f32) و"deep sapphire" (#0f52ba) تطلبت نهج العدّ — لا يمكنك تخمينها بشكل موثوق من القيم السداسية وحدها.

  3. تصنيف الأشكال من مسارات SVG تطلّب فهم أوامر مسار SVG:

    • M (moveto)، L (lineto)، A (arc)، Z (closepath)
تنزيل الأداة
Functionالغرض
startGameينشئ جلسة لعبة، ويعيد 200 صورة + 200 وصف
scoreGameيقبل {matches: {}, sessionId: ""}، ويعيد {correctCount: N}
generateTokenيأخذ معرّف الجلسة، ويعيد رمز الإكمال
getLeaderboardيعيد أعلى الدرجات
saveNicknameيحفظ الاسم المعروض للوحة المتصدرين
لون بداية تدرج SVGالعددكلمة الوصفالعدد
#0a162828pitch28
#eef2f720frosted20
#0d0d0d19tenebrous19
#fef9f018pearlescent18
#1e0a2e18nocturnal18
#0a1a0a17midnight17
#1a0a0a15inky15
#f5f0eb14milky14
#f7f3ee14ethereal14
#f0f0f014radiant14
#f0f7f413glowing13
#1a1a2e10somber10
نمط SVGطريقة الاكتشافالعدداسم الوصفالعدد
عناصر <line> أفقية (dy=0)فحص x1,y1,x2,y235striped overlay35
عناصر <line> عمودية (dx=0)فحص x1,y1,x2,y234lattice pattern34
<circle> مع opacity="0.06" (نقاط)عدّ الدوائر منخفضة الشفافية30stippled layer30
لا توجد عناصر تراكب إطلاقًالا خطوط، ولا أشكال خلفية28(none)28
عناصر <line> قطريةفحص اتجاه الميل27tilted cross-lines27
<polygon>/<path> صغيرة مع opacity="0.06"أشكال بسمة شفافية منخفضة25arrow-band texture25
<circle> مع fill="none" stroke="#888"دوائر بحدود فقط21ringed pattern21
Hexاسم الوصفHexاسم الوصف
#708090blue-gray#cd7f32brass
#f5f5f5near white#dc143cfiery red
#00bcd4electric cyan#2196f3azure
#ff6b6bsalmon pink#228b22rich green
#98ff98pale green#b0b0b0platinum
#0f52badeep sapphire#800020oxblood
#ff8c00deep orange#4b0082dark purple
#e2725bterra rosa#ffbf00marigold
#b7410erusset#ff69b4candy pink
#ffd700bright gold#c0c0c0tin
#6b8e23moss#008080deep teal
#40e0d0pale teal#0047abroyal blue
#e34234burnt sienna#a0522ddeep red
#4a4a4adim gray#36454fdark gray
عنصر SVGمنطق الاكتشافاسم الوصف
<polygon> 3 رؤوسعدّ أزواج النقاط المفصولة بمسافاتpike
<polygon> 4 رؤوسtilted square
<polygon> 5 رؤوسquint form
<polygon> 6 رؤوسbee cell
<polygon> 10 رؤوسasterisk
<rect> (ليس خلفية)له width/height، وليس 200x200tilted square
<circle>اسم الوسمdisc
<path> مع fill-rule="evenodd"مساران قوسيان متحدا المركزdonut
<path> مع قوس واحد + Zمسار نصف دائرةhalf-disc
<path> مع 6+ أوامر Lشكل صليب/زائدcrosshair
<path> مع 3-5 أوامر Lشكل شبيه بالسهمpointer
نطاق نصف القطراسم الوصف
0–12minuscule
13–16modest
17–20mid-sized
21–25substantial
26+massive
faint
قيمة rotate() في SVGاسم الوصف
0°upright
1–20°slightly tilted
21–55°diagonal
56–75°steeply angled
76–105°sideways
لكل شكل
  • اللون: من سمة fill، ويُربط عبر COLOR_MAP
  • النوع: من وسم العنصر + عدد الرؤوس / أوامر المسار
  • الحجم: من إحداثيات الرؤوس أو نصف القطر
  • الشفافية: من style="opacity:X"
  • الدوران: من transform="... rotate(X)"
  • الموضع: من transform="translate(X,Y) ..."
200/200 صحيح
~21:15تم استدعاء generateToken — WKX-9245FA70-200
المكوّنالتقنية
منصة التحديBase44 (أداة بناء تطبيقات منخفضة الكود)
الواجهة الأماميةReact SPA (حزمة JS واحدة، ~410KB)
الواجهة الخلفيةPython/uvicorn خلف Cloudflare
CDN/وكيلCloudflare (HTTP/3، ضغط Brotli)
المصادقةJWT (HS256)، مخزَّنة في localStorage
تنسيق البياناتSVG (مضمّن base64)، JSON API
الوقت الفعليWebSocket (socket.io) لتحديثات الجلسة المباشرة
الحلّالPython 3 (تحليل بالتعبيرات النمطية، دون مكتبات خارجية)
  • الدونات = مساران قوسيان متحدا المركز مع fill-rule="evenodd"
  • نصف القرص = مسار قوسي واحد
  • المشبك/التصويب = مسار يحتوي على 6+ مقاطع خطية (شكل صليب/زائد)
  • المؤشر = مسار يحتوي على 3-5 مقاطع خطية (شكل سهم)