۰۶۲۴۹ ۳۶۸ ۰۲۶
[email protected]
Unk9vvN
  • راهکارها
    • شبیه سازی تهاجمی
    • عملیات تدافعی
    • شکارچی باگ
  • خدمات
    • تست نفوذ و ارزیابی امنیتی
    • تیم قرمز و مهندسی اجتماعی
    • امنیت سیستم های کنترل صنعتی
    • جرم شناسی دیجیتال و پاسخ به حادثه
    • تیم آبی و دفاع سایبری
    • بازبینی امنیتی و کشف آسیب پذیری
  • دوره ها
    • تست نفوذ
      • وب
      • موبایل
      • فضای ابری
      • شبکه
      • شبکه بی سیم
      • اینترنت اشیاء
    • تیم قرمز
    • امنیت صنعتی
    • جرم شناسی دیجیتال
    • تیم آبی
    • بازبینی امنیتی
  • منابع
    • وبلاگ ما
    • وبینار ها
    • تایید گواهی
  • درباره ما
  • تماس با ما
  • حساب من
  • فارسی
محصول به سبد خرید شما افزوده شد.

مسمومیت حافظه پنهان وب

نوشته شده در 12 تیر 1400
بدون دیدگاه

در این مطلب قصد داریم، یکی از حملات سایبری بر بستر وب، به نام Cache Poisoning، را شرح دهیم. اول، کمی با Cache و انواع آن آشنا خواهیم شد. دوم، به سراغ مفهوم پایه ای این آسیب پذیری و چگونگی شناسایی آن می رویم. سوم، عواقب آن را مرور می کنیم. چهارم، مکانیزم های دفاع در برابر این آسیب پذیری (Mitigations) و پنجم راه های دور زدن این مکانیزم ها را بررسی می کنیم.

فهرست محتوا پنهان
1 در مورد Cache و انواع آن
2 توضیح Cache Poisoning
2.1 کلید شده و کلید نشده
2.1.1 کلید شده (Keyed)
2.1.2 کلید نشده (Unkeyed)
3 کشف
3.1 سرور Cache شفاف
3.2 سرور Cache مخفی
3.3 یافتن موارد استفاده شده
4 بهره برداری (Exploit)
5 عواقب (Impact)
6 راه های جلوگیری (Mitigations)
6.1 جلوگیری از ایجاد Gadget
6.2 جلوگیری از Cache شدن نادرست
7 راه های دور زدن (Bypass)
7.1 با استفاده از HTTP Header Pollution
7.2 وصله نادرست، باعث منع سرویس
7.3 شماره Port در Host
8 مثال Cache تو در تو
8.1 سناریوی کلی
8.2 کلید نشده و استفاده شده
8.3 یک Gadget در Drupal
8.4 بهره برداری

در مورد Cache و انواع آن

به طور کلی حافظه نهان (Cache) در سطوح مختلف دنیای کامپیوتر مورد استفاده قرار می گیرد. حافظه نهان، یک سخت افزار یا محصول مشخص نیست؛ بلکه یک روش معماری و طراحی است. هدف از آن افزایش سرعت و کاهش تاخیر زمانی است. در سطح وب از حافظه نهان در قسمت های مختلفی استفاده می شود، که می توان آن را به دو بخش سمت-کاربر و سمت-سرور تقسیم کرد. در این مطلب، تمرکز ما روی حافظه های نهان سمت سرور است. این سرور ها خود به دو دسته قابل تقسیم بندی هستند. دسته اول، سرور های میانی ای که به صورت یک Proxy عمل می کنند و در عین حال عملیات Caching را نیز انجام می دهند. دسته دیگر، مکانیزم Caching تعبیه شده در سرور وب اصلی است. خیلی از Framework های وب به طور پیشفرض، حافظه نهان نیز دارند (مثلا Drupal).

  1. حافظه نهان در سرور Proxy (بیرونی)
  2. حافظه نهان در سرور وب اصلی (داخلی)

از این پس، هر جا از سرور Cache صحبت می کنیم، منظورمان سرور Web Cache است.

توضیح Cache Poisoning

می دانیم که وب، پر است از منابع تکراری. مثلا فایل های CSS و JS و حتی برخی صفحات PHP و ASP و … که هر بار توان پردازشی سرور را درگیر می کنند تا سرور وب، آن ها را به کاربران ارائه کند. سرور Cache به وجود آمده است تا منابع (Resources) تکراری (صفحات HTML، فایل های CSS و JS، صفحات PHP تکراری و …) را در خود ذخیره کند و از درگیری بیش از حد سرور وب اصلی برای ارائه این منابع تکراری جلوگیری کند. سرور Cache بین کاربر (Client) و سرور وب اصلی قرار دارد و تمام درخواست ها به سمت سرور اصلی را بررسی می کند. چنانچه منبع مورد نظر را داشته باشد، بدون ارسال درخواست به سرور وب اصلی، آن منبع را به کاربر باز می گرداند. در غیر این صورت، مجبور است درخواست را به سرور وب اصلی بفرستد و نتیجه را به دست آورد.

تعریف ساده Cache
تعریف ساده Cache
در شکل بالا، کارکرد ساده یک سرور Cache وب را مشاهده می کنید

کلید شده و کلید نشده

سرور های Cache بر چه اساس باید اطلاعات را ذخیره کنند؟ چه معیاری به آن ها کمک می کند که بین محتوای متفاوتی که از سمت وب سرور دریافت می کنند، تمایز قائل شوند؟ همچنین از کجا متوجه می شوند که درخواست چندین کاربر (که ظاهرا متفاوت است) برای دریافت یک منبع واحد ارسال شده است؟

جواب سوالات بالا در مفهوم کلید خلاصه می شود. تصور کنید درخواست زیر از سمت کاربر به سمت سرور ارسال می شود. در بین راه سرور Cache این درخواست را دریافت می کند و باید بررسی کند که آیا قبلا چنین چیزی را در حافظه خود ذخیره کرده است یا خیر؟

GET /path/to/file.js HTTP/2
Host: unk9vvn.com
User-Agent: Firefox/89.0
Accept: application/javascript,*/*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: https://domain.com/
Connection: keep-alive
Cookie: SESSION=fe6de2fcec446e6050ec22f7a65a5bfd

یک راه این است که تمام درخواست بررسی شود. یعنی تمام درخواست (شامل Cookie و User-Agent و …) به عنوان کلید جستجو در پایگاه داده سرور Cache استفاده شود. اما این کار چندان منطقی نیست. چون احتمالا هر کاربری Cookie خاص خود را دارد و باعث می شود برای هر کاربر یک مورد در سرور Cache ذخیره شود. پس بهتر است سرور Cache موارد کم تری را کلید شده و برخی موارد را نیز کلید نشده در نظر بگیرد.

مثلا سرور Cache می تواند GET /path/to/file.js و هدر Host (یعنی unk9vvn.com) را به عنوان کلید درنظر بگیرد. در این صورت دو درخواست زیر از نظر سرور Cache برابر به حساب می آیند:

GET /path/to/file.js HTTP/2
Host: unk9vvn.com
User-Agent: Firefox/89.0
Referer: https://domain.com/
Connection: keep-alive
Cookie: SESSION=fe6de2fcec446e6050ec22f7a65a5bfd
GET /path/to/file.js HTTP/1.1
Host: unk9vvn.com
User-Agent: Chrome/81.0
Referer: https://example.com/
Connection: close
Cookie: SESSION=2a616eda330dc33e0c7b264b4caf4acd

یعنی، بار اول که درخواست اول توسط سرور Cache دریافت می شود، درخواستی به سمت سرور وب اصلی ارسال می کند و منبع مورد نظر را دریافت می کند و با کلید مشخص شده ذخیره می کند. دفعه بعدی که درخواستی با همان کلید به سرور Cache برسد، می داند کدام منبع را باید به کاربر بازگرداند (دیگر نیازی به درخواست دوباره به سرور وب اصلی نیست).

مثال دقیق عملکرد Cache
مثال دقیق عملکرد Cache
این بار جزئیات درخواست های ارسالی را نیز مشاهده می کنید که از کاربر به سمت سرور Cache و از سرور Cache به سرور وب اصلی ارسال می شود
کلید شده (Keyed)

ما در انجام حمله Cache Poisoning، باید بدانیم که سرور Cache کدام بخش های درخواست را به عنوان کلید در نظر می گیرد. نام این بخش ها را کلید شده یا Keyed می گذاریم. در صورت تغییر مقدار موارد کلید شده، پاسخ دریافتی از سرور Cache متفاوت خواهد بود و یک رکورد Cache جدید در سرور Cache اضافه خواهد شد.

کلید نشده (Unkeyed)

در مقابل کلید شده، کلید نشده یا Unkeyed قرار دارد. موارد کلید نشده در درخواست وب، مواردی هستند که با تغییر آن ها، سرور Cache، پاسخ متفاوتی نمی دهد. یعنی از حافظه خود، موردی را بر می گرداند که قبلا توسط ما یا کاربر دیگری مشاهده شده است.

کشف

به طور خلاصه، زمانی یک وبسایت به Cache Poisoning آسیب پذیر است که از مقادیر کلید نشده توسط سرور Cache به شکلی نادرست استفاده کند. استفاده نادرست به این معنی است که جریان داده (Data Flow) از این مقدار بدون صحت سنجی (Validation) و پاکسازی (Sanitization) مناسب بر پاسخ ارسالی به کاربر تاثیر بگذارد. این استفاده نادرست به خودی خود باعث آسیب پذیری هایی مثل XSS، HTML Injection و … است. به این آسیب پذیری موجود در سمت سرور (بدون دخالت سرور Cache) اصطلاحا Gadget می گوییم. پس لازم است، دو مورد زیر وجود داشته باشند تا ما بتوانیم یک حمله موثر انجام دهیم.

  1. لازم است مقداری را پیدا کنیم که در سرور Cache کلید نشده باشد. (قابل بهره برداری از راه Web Cache Poisoning)
  2. باید مطمئن شویم که این مقدار توسط وبسایت استفاده شده باشد. (یافتن Gadget)

بار دیگر مثال بالا را بررسی می کنیم. فرض کنید، چنین درخواستی از سمت کاربر به وبسایت ارسال می شود.

GET /path/to/file.js HTTP/2
Host: unk9vvn.com
User-Agent: Firefox/89.0
Referer: https://domain.com/
Connection: keep-alive
Cookie: SESSION=fe6de2fcec446e6050ec22f7a65a5bfd

در کد سمت سرور که به زبان PHP نوشته شده است، از مقدار هدر Referer استفاده شده است. تست جعبه سیاه این کد کار سختی نیست. می توان مقدار Referer را به مقداری مشخص تغییر داد و در صفحه به دنبال آن مقدار گشت.

<a href="<?= $_SERVER['HTTP_REFERER'] ?>">Go Back</a>

ما در صورتی که بتوانیم مقدار هدر Referer را کنترل کنیم، می توانیم به آسیب پذیری XSS برسیم (Gadget). هیچ یک از روش های سنتی بهره برداری از XSS در اینجا عملی نیست؛ چرا که ما لازم داریم مقدار هدر (Header) را دستکاری کنیم. اما اگر مقدار Referer کلید نشده باشد، می توان از تکنیک Cache Poisoning برای آلوده کردن نه تنها یک کاربر، بلکه تعداد زیادی کاربر استفاده کرد. اما چطور می توان تشخیص داد که Referer کلید شده است یا کلید نشده؟ برای حل این چالش، معمولا با دو حالت متفاوت مواجه می شویم:

  1. شفاف: برخی سرور های Cache، خود را مخفی نمی کنند و به صورت شفاف کار می کند. این نوع سرور ها به گونه تنظیم شده اند که حضور خود را به سمت کاربر اعلام می کنند و بعضا اطلاعات مفیدی در خصوص منبع Cache شده در اختیار ما می گذارند.
  2. مخفی: برخی سرور های Cache به گونه ای تنظیم شده اند که کاربر نتواند به راحتی از حضور آن ها با خبر شود. این سرور ها هیچ اطلاعاتی را در خصوص منبع Cache شده به سمت کاربر ارسال نمی کنند.

سرور Cache شفاف

در موارد شفاف، کار ساده تر است. مثلا در پاسخ وب زیر، مشاهده می کنید که سرور Cache چند هدر به پاسخ سرور وب اصلی اضافه کرده است:

HTTP/2 200 OK
Date: Fri, 11 Jun 2021 06:44:05 GMT
Content-Type: text/html; charset=UTF-8
Via: 1.1 vegur
Age: 242
Cache-Control: public, max-age=1500

هدر Via به ما اعلام می کند که سرور Cache به نام vegur نسخه 1.1 بین ما و سرور وب اصلی قرار دارد. هدر Age، مدت زمانی که این منبع، Cache شده است را نشان می دهد. قسمت max-age در هدر Cache-Control (در HTTP 1 از Pragma استفاده می شد) نشان دهنده مدت زمانی است که این منبع در سرور Cache ذخیره خواهد شد. در این مثال، اگر بعد از چند ثانیه درخواست خود را تکرار کنیم، مشاهده می کنیم که مقدار Age زیاد تر شده است (معمولا به ازای هر ثانیه یک واحد). با ادامه این روند، هر گاه مقدار Age به حداکثر آن، یعنی 1500 برسد، منبع از سرور Cache حذف می شود و در صورت درخواست دوباره، مقدار Age از صفر شروع می شود که این نشان دهنده ثبت یک Cache جدید در سرور Cache است.

پاسخ Miss شده
پاسخ Miss شده
در تصویر می بینید که سرور Cache منبع مورد نظر ما را نداشته و یک مورد جدید ایجاد کرده و Age آن را برابر صفر قرار داده است
پاسخ Hit شده
پاسخ Hit شده
بعد از چند ثانیه، درخواستی دیگر به سرور Cache ارسال کرده ایم و می بینید که Age کمی بیشتر شده است

یک مثال دیگر از کارکرد شفاف سرور Cache، مربوط به سرور های ابری CloudFlare است. این سرور ها می توانند در پاسخ خود هدر CF-Cache-Status را بر گردانند. در صورتی که مقدار آن MISS باشد، یعنی مقدار Cache شده معادل درخواست ارسالی یافت نشد و HIT یعنی یافت شد. یک نمونه پاسخ دریافتی از CDN های CloudFlare:

HTTP/2 200 OK
date: Wed, 16 Jun 2021 07:12:12 GMT
content-type: text/html; charset=utf-8
cf-ray: 66023a7b9cda4a56-FRA
age: 88
cache-control: max-age=120
strict-transport-security: max-age=31536000
vary: Accept-Encoding
cf-cache-status: HIT
cf-request-id: 0ab542e14300004a56849d8000000001
expect-ct: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
x-xss-protection: 1; mode=block
report-to: {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v2?s=BO8GHGmWbq0IQ3ZCLdn3DwheDLtLCEbqL9pmhpkWKsCtSA3N2o6%2B8bjhCUHtD1zRt9rC5iOoFHmjcHqWUDRSTf7DmL%2FbshOU4PDzCux1ecycMGQAOlH1VBC4PnxNoC4%3D"}],"group":"cf-nel","max_age":604800}
nel: {"report_to":"cf-nel","max_age":604800}
server: cloudflare
content-encoding: br
alt-svc: h3-27=":443"; ma=86400, h3-28=":443"; ma=86400, h3-29=":443"; ma=86400, h3=":443"; ma=86400
X-Firefox-Spdy: h2

برای تشخیص موارد کلید شده، کافی است هر بار، بخشی از هدر درخواست را تغییر دهیم. اگر مقدار Age پاسخ، برابر صفر بود، یعنی درخواست ما Cache شده است. این یعنی مقدار مورد نظر، کلید شده است؛ اما اگر در صورت تغییر مقدار، همان موارد Cache شده قبلی با Age بزرگتر از صفر بود، کلید نشده است.

توجه: در این تست ها، معمولا یک پارامتر تصادفی بی اثر در URI درخواست ارسالی اضافه می کنیم. با این کار از Cache شدن درخواست برای کاربران دیگر، یا دیدن مقادیر Cache شده قبلی جلوگیری می کنیم. به این مقدار تصادفی اصطلاحا Cache Buster می گویند.

طرز کار Cache Buster
طرز کار Cache Buster
در تصویر بالا طرز کار Cache Buster را در کنار مقادیر کلید شده و کلید نشده می بینید. به جزئیات مربوط به Cache در تصویر دقت کنید.

سرور Cache مخفی

در بعضی سرور های Cache، حتی نام سرور نیز معرفی نمی شود؛ چه برسد به Age و max-age. در چنین مواردی باید از تغییرات پاسخ دریافتی، تشخیص دهیم که این یک پاسخ، Cache شده است یا پاسخ جدید. از آنجایی که حالت های زیادی وجود دارد و بعضا تشخیص دقیق غیرممکن می شود، پیشنهاد می کنیم از افزونه Param Miner که برای Burp Suite توسعه داده شده است، استفاده کنید. برای مشاهده یک مثال از چگونگی کار با این افزونه به ویدیویی که در آخر این مطلب قرار داده شده است مراجعه کنید. اما تست دستی هم در بعضی موارد مفید است. مهم ترین نکته، درک مفاهیم کلید شده و استفاده شده است که ذکر شد. با تغییر تصادفی مقادیر مختلف و بررسی منطقی نتیجه، بر اساس این مفاهیم، شاید بتوان به نتیجه رسید. خوب است بدانید که معمولا این موارد جزو کلید هستند:

  • Path
  • Query String
  • Method
  • Host Header
  • و معمولا یک یا دو هدر دیگر

چند نکته را نیز در ذهن داشته باشید:

  • بسیار نادر است که Path کلید شده نباشد.
  • در سایت هایی که از CloudFlare استفاده می کنند، معمولا Origin کلید شده است.
  • از مقادیر تصادفی در بخش های مختلفی از درخواست که فکر می کنید ممکن است کلید شده باشند، استفاده کنید.
  • هدر Vary در پاسخ، نشان دهنده هدر هایی است که سرور وب اصلی به سرور Cache دستور داده است تا کلید شوند.

بعد از تشخیص موارد کلید شده و کلید نشده، زمان آن است که موارد استفاده شده را پیدا کنیم. این به ما کمک می کند که بتوانیم آسیب پذیری تزریق کد سمت کاربر کشف کنیم. در عنوان بعدی، نکاتی در این مورد نوشته شده است.

یافتن موارد استفاده شده

در اینجا هدف، پیدا کردن Gadget است. برای این کار لازم است مقادیر را به صورت تصادفی تغییر دهیم. البته طبق چیزی که قبلا گفتیم، باید در بین موارد کلید نشده به دنبال موارد استفاده شده بگردیم. از آنجایی که با هر بار تغییر یک مقدار کلید نشده، منبع Cache شده از سرور Cache دریافت می شود، لازم است مقدار کلید شده بی تاثیر را نیز تغییر دهیم (Cache Buster). مثلا:

GET /path/to/file.php?junk=456987451 HTTP/2
Host: unk9vvn.com
User-Agent: fe6de2fcec446e6050ec22f7a65a5bfd

در مثال بالا مشاهده می کنید که پارامتر junk در درخواست ارسال شده است. نقش این پارامتر تنها تغییر مقدار کلید است، تا سرور Cache درخواستی تازه به سمت سرور وب اصلی ارسال کند. در ادامه، می بینید که مقدار User-Agent به مقداری تصادفی تغییر کرده است. هدف از این کار شناسایی نقطه تاثیر این مقدار در پاسخ دریافتی است. پس از دریافت پاسخ، باید در آن به دنبال همین مقدار تصادفی گشت. اگر وجود داشته باشد، یعنی جریان داده از هدر User-Agent تا پاسخ دریافتی وجود دارد. حال با تست های دقیق تر (وارد کردن Payload های XSS و …) می توان از این جریان داده، یک آسیب پذیری به دست آورد. اگر صحت سنجی و پاکسازی مناسبی روی ورودی انجام نشده باشد، آسیب پذیری وجود دارد و این، همان Gadget است که به دنبال آن می گشتیم. این هدر ها معمولا در سمت سرور مورد استفاده قرار می گیرند و در صورت استفاده نادرست برنامه نویس سمت سرور، می توان از آنها بهره برداری کرد.

  • X-Forwarded-Host
  • X-Forwarded-For
  • X-Original-URL
  • X-Host
  • X-Forwarded-Server
  • X-Rewrite-Url
  • X-Forwarded-Scheme

پس از یافتن چنین موردی، ما تمام تکه های پازل را داریم. مرحله بعد مسموم کردن Cache با ورودی مخرب (Payload) برای بهره برداری از Gadget روی تعداد زیادی از کاربران وبسایت است. چگونگی بهره برداری (Exploit) این آسیب پذیری در قسمت بعد توضیح داده شده است.

بهره برداری (Exploit)

هکر می تواند با دستکاری مقدار کلید نشده، محتوای بدخواهانه خود را در صفحه وارد کند. سپس هکر با مسموم کردن سرور Cache، دو ویژگی پایداری (1) و امکان انتقال به قربانی (2) را به آن محتوا می دهد. در نتیجه این دو ویژگی، احتمالا تعداد زیادی قربانی، با ورود به صفحه Cache شده (بر اساس بخش کلید شده درخواست)، محتوای بدخواهانه را مشاهده می کنند و در دام هکر می افتند. این محتوای بدخواهانه می تواند کد جاوا اسکریپت سمت کاربری باشد که امکان نشت اطلاعات قربانی و انجام عمل از سوی قربانی را به هکر می دهد.

  1. منظور از پایداری محتوا این است که از این پس، حتی بدون تزریق Payload مربوطه در هدر درخواست، محتوای بدخواهانه در صفحه Cache شده وجود دارد.
  2. منظور از امکان انتقال به قربانی این است که لازم نیست کار اشتباهی از سمت کاربر اتفاق بیفتد تا Payload ما روی مرورگر او اجرا شود.

تا اینجا ارزش Web Cache Poisoning مشخص شد. اما در عمل باید چه کار کرد؟ به محض این که عمر (Age) یک منبع Cache شده به پایان برسد، اولین درخواستی که با همان کلید به سرور Cache ارسال شود، یک رکورد جدید را در سرور Cache ایجاد می کند. ما امکان تغییر درخواست ارسالی از سمت کاربر را نداریم؛ پس نهایتا با حذف Cache Buster باید درخواست معمولی را ارسال کنیم. با این کار به دلیل تشابه کلید درخواست ما با تمام کاربران، همه یک نتیجه واحد را می بینیم. این همان چیزی است که اگر با ورودی مخرب ما همراه باشد، مسموم کردن Cache، به حساب می آید.

در نتیجه برای بهره برداری از Gadget روی مرورگر کاربران، باید به محض پایان عمر منبع مورد نظر، آن را با ورودی حاوی Payload خودمان جایگزین کنیم. در سرور های Cache شفاف، این قضیه ساده تر است. با دنبال کردن مقدار هدر Age در پاسخ دریافتی از سرور Cache، لحظه مناسب را تشخیص می دهیم. چند ثانیه قبل از رسیدن مقدار Age به max-age شروع به ارسال حجم زیادی درخواست آلوده می کنیم. اما اگر سرور Cache مخفی باشد، کار سخت می شود. یک راه این است که به طور مداوم، درخواست ها را با تعداد زیاد ارسال کنیم تا تصادفا در زمان درست، پاسخ درخواست ما Cache شود. اما این کار در واقعیت باعث شناسایی حمله خواهد شد. یک راه دیگر هم هست. با این که زمان دقیق پایان عمر Cache مشخص نیست؛ اما شاید بتوان آن را حدس زد. با تجزیه و تحلیل رفتار سرور Cache و پاسخ های دریافتی (اصطلاحا مهندسی معکوس)، می توانیم زمان تقریبی را حدس بزنیم. جزئیات چگونگی حدس زدن زمان پایان عمر Cache از محدوده این مطلب خارج است. نتیجه این شد که، اگر ما در زمان مناسب، درخواست آلوده خود را ارسال کنیم، سرور Cache پاسخ آن را ذخیره می کند و به تمام کاربران نمایش می دهد.

مسموم کردن Cache
مسموم کردن Cache
در این تصویر یک نمونه از مسموم سازی Cache را مشاهده می کنید. از این پس هر کس به سایت آسیب پذیر وارد شود، محتوای آلوده Cache شده را مشاهده خواهد کرد.

عواقب (Impact)

  1. تزریق کد سمت کاربر (XSS, HTML Injection , …): توضیحات این مطلب تا اینجا، مربوط به این Impact بوده است. یعنی مهاجم می تواند محتوای صفحه را دست کاری کند و در نتیجه آن، اطلاعاتی را بدزدد یا عملی را از سوی کاربر دیگری انجام دهد.
  2. نشت اطلاعات حساس (Sensitive Data Disclosure): نوعی Impact آسیب پذیری مربوط به Web Cache وجود دارد که در آن، نیازی به یافتن موارد استفاده شده نیست. این Impact مربوط به نشت اطلاعات حساس کاربران به کمک Web Cache است. اگر سرور وب، هدر های مناسب را برای جلوگیری از Cache شدن اطلاعات حساس کاربران استفاده نکند، ممکن است اطلاعات شخصی، احراز هویت و … در سرور Cache ذخیره شود. در چنین حالتی تنها با ارسال درخواستی که کلید معادل درخواست قربانی را دارد، می توان منبع Cache شده را دریافت کرد. (نمونه این Impact)

    قابل ذکر است که حمله مربوط به این Impact با نام Web Cache Deception شناخته می شود. اساسا Web Cache Poisoning و Web Cache Deception تفاوت دارند و اصل تفاوت در همین نکته است که اولی با آلوده کردن Cache تلاش در بهره برداری از یک آسیب پذیری در سمت کاربر دارد؛ اما دومی به دنبال اطلاعاتی است که از ذخیره شدن در Cache می تواند نشت پیدا کند.

  3. منع سرویس (DoS): گاهی ممکن است، مقدار کلید نشده استفاده شده، باعث تزریق کد سمت کاربر نشود. ممکن صحت سنجی یا پاکسازی مناسب داده ها جلوی چنین چیزی را بگیرد. یا ممکن است ورودی اصلا در پاسخ ارسالی به کاربر استفاده نشده باشد؛ بلکه فقط در محاسبات داخلی سرور کاربرد داشته باشد. در چنین مواردی، هر چند نمی توان به Impact شماره 1 رسید؛ اما شاید بتوان DOS انجام داد. ممکن است یک ورودی خاص، باعث وقوع خطا در سرور شود و پاسخ نهایی را مختل کند. می توان با کشف این ورودی خاص، سرور Cache را آلوده کرد و از این پس، هر کاربری که بخواهد آن منبع را مشاهده کند، با پیغام خطای ذخیره شده در سرور Cache مواجه خواهد شد.
  4. هدایت آزاد (Open Redirect): در بعضی موارد از مقدار استفاده شده در درخواست برای هدایت (Redirect) کاربر به آدرسی دیگر استفاده می شود. چنانچه این مقدار کلید نشده باشد و صحت سنجی مناسب انجام نشود، می توان تعداد زیادی از کاربران سایت را به سمت سرور مهاجم (مثلا attacker.com) هدایت کرد؛ بدون این که متوجه شوند.

راه های جلوگیری (Mitigations)

اول از همه این نکته را باید بدانید که بهترین راه برای جلوگیری از حمله Web Cache Poisoning این است که از Cache استفاده نکنید!! در بسیاری از سرویس ها (CloudFlare) و فریمورک ها (مثل Drupal) قابلیت Cache به طور پیش فرض فعال است؛ در صورتی که بسیاری از کاربران به آن نیازی ندارند. پس اگر به آن نیازی ندارید، آن را غیرفعال کنید. اما جدا از این، برای جلوگیری از این آسیب پذیری، دو نقطه اثر مهم وجود دارد. یکی در سرور Cache و دیگری در سرور وب اصلی. از طرفی دیدیم که همراه شدن آسیب پذیری Web Cache Poisoning با یک آسیب پذیری موجود در سرور وب اصلی (Gadget)، امکان ایجاد Impact را فراهم می کند. پس این دو تکه پازل باید با هم وجود داشته باشند تا امکان ایجاد Impact فراهم شود. پس در اینجا، تلاش می کنیم یکی از این تکه ها را از بین ببریم.

جلوگیری از ایجاد Gadget

به عنوان توسعه دهنده وبسایت، اولین نکته ای که باید به آن توجه کرد، این است که تمام مقادیری که از سمت کاربر به سمت سرور وارد می شوند، باید صحت سنجی و پاکسازی شوند. حال این مقدار ممکن است، مقدار هدر باشد یا پارامتر های URI. این قاعده ای کلی است که از به وجود آمدن بسیاری از آسیب پذیری ها جلوگیری می کند. هر یک از این آسیب پذیری ها ممکن است در حمله Web Cache Poisoning به عنوان یک Gadget مورد استفاده قرار گیرند. راه دیگر جلوگیری از به وجود آمدن Gadget ها استفاده CSP (Content Security Policy) در مرورگر های مدرن است. و نهایتا در یک کلام باید گفت، هر چیزی که به عنوان جلوگیری از حملات XSS، HTML Injection و … شناخته می شود، اینجا نیز قابل استفاده است؛ زیرا Gadget چیزی جز این آسیب پذیری های سمت کاربر نیست که مستقل از Cache وجود دارند و عمل می کنند.

جلوگیری از Cache شدن نادرست

در حالت کلی نباید یک مقدار هم کلید نشده باشد و هم استفاده شده. این نکته، کلید ایجاد آسیب پذیری Web Cache Poisoning است. اصلاح این مشکل هم در سرور وب اصلی ممکن است و هم در سرور Cache. اگر به تنظیمات سرور Cache دسترسی داشته باشیم، می توانیم موارد استفاده شده در برنامه سمت سرور را، کلید شده در نظر بگیریم. اما اگر به تنظیمات سرور Cache دسترسی نداشته باشیم، باید از مقدار مورد نظر استفاده نکنیم و جایگزینی در موارد کلید شده برای آن پیدا کنیم.

راه های دور زدن (Bypass)

در بحث دور زدن راه های جلوگیری از Gadget ها به تعداد انواع آسیب پذیری سمت کاربر مطلب هست. یعنی هر نوع آسیب پذیری ای که بتوان از راه Web Cache Poisoning از آن بهره برداری کرد، می تواند به چندین روش پوشش داده شود و برای هر روش چندین روش دور زدن وجود دارد. اما در جلوگیری از Cache شدن نادرست، موارد خاص آسیب پذیری Web Cache Poisoning وجود دارد که در اینجا چند مثال را که از تحقیقات James Kettle استخراج شده است، می بینیم:

با استفاده از HTTP Header Pollution

در این مثال (از آسیب پذیری Cloudflare)، درخواست زیر، قبل از وصله (Patch) آسیب پذیری ارسال شده است. قسمت کلید شده در سرور Cache به صورت GET /|example.com است.

GET / HTTP/1.1
Host: example.com
X-Forwarded-Host: evil.net

در نتیجه این درخواست، پاسخ زیر دریافت می شود. در قسمتی که evil.net قرار گرفته است، محلی است که ما می توانیم Payload مربوط به XSS را نیز وارد کنیم. در نتیجه دو تکه پازل تکمیل است و امکان حمله وجود دارد.

HTTP/1.1 200 OK

<a href="https://evil.net/">

برای وصله کردن این آسیب پذیری، مدیران سایت به وصله نوع دوم اکتفا کرده اند. یعنی Gadget همچنان باقی است و تنها بخش استفاده شده X-Forwarded-Host نیز به کلید اضافه شده است. در نتیجه کلید درخواست قبلی در سرور Cache به شکل GET /|example.com|evil.net خواهد بود. اما آیا همین کفایت می کند؟ مشکلی در سرور Cache وجود دارد که از کلید کردن مقادیر تکراری خودداری می کند. مثلا در درخواست زیر، کلید GET /|evil.net خواهد بود، در صورتی که ما دو بار از evil.net استفاه کرده ایم.

GET / HTTP/1.1
Host: evil.net
X-Forwarded-Host: evil.net

یک مشکل دیگر نیز وجود دارد. تفاوت عملکرد سرور وب اصلی با سرور Cache در برخورد با هدر تکراری می تواند ما را به نتیجه نهایی برساند. درخواست زیر را ببینید:

GET / HTTP/1.1
Host: example.com
X-Forwarded-Host: example.com
X-Forwarded-Host: evil.net"><!-- Some Injected Javascript or HTML -->

بخش کلید شده در سرور Cache به شکل GET /|example.com است. در حالی که این پاسخ دریافتی از سمت سرور است.

HTTP/1.1 200 OK

<a href="https://example.com, evil.net"><!-- Some Injected Javascript or HTML -->

می بینیم که سرور Cache تنها مورد اول را در نظر گرفته است و از آن در کلید استفاده کرده است. در حالی که سرور وب اصلی، هر دو مورد را در نظر گرفته و مقادیر آن ها را، در پاسخ، با ویرگول از هم جدا کرده است. پس با انجام HTTP Header Pollution ما می توانیم این وصله را دور بزنیم.

وصله نادرست، باعث منع سرویس

گاهی اوقات، یک WAF (Web Application Firewall) یا مکانیزمی دفاعی در سمت سرور، خود باعث آسیب پذیری می شود. این اشتباه بسیار معمول است که برای جلوگیری از یک حمله، باعث به وجود آمدن منع سرویس از راه مسموم کردن Cache می شوند. مثلا ممکن است، برای جلوگیری از به وجود آمدن Gadget های مناسب در حمله Web Cache Poisoning، یک WAF نصب شود. این WAF هر گونه ورودی خطرناک در درخواست ارسالی را با کد وضعیت 403 (Forbidden) جواب می دهد. حال، اگر این پاسخ 403 در سرور Cache ذخیره شود، امکان DoS وجود دارد. برای مثال، در سایت www.example.com از یک WAF استفاده شده است که در صورت دیدن burpcollaborator.net در هر یک از هدر های ورودی، پاسخی با کد وضعیت 403 بر می گرداند.

GET /en_GB/roadster HTTP/1.1
Host: www.example.com
Any-Header: burpcollaborator.net

و این هم پاسخ دریافتی:

HTTP/1.1 403 Forbidden

Access Denied. Please contact [email protected]

از این به بعد، هر کس تلاش کند درخواستی با کلید GET /en_GB/roadster|www.example.com را مشاهده کند، با همان پاسخ بالا روبرو می شود. اشتباه این است که هدر مناسبی برای جلوگیری از Cache شدن خطای 403 وجود ندارد و سرور Cache هم تمایزی بین خطا و پاسخ صحیح قائل نیست.

شماره Port در Host

گاهی اوقات، برای وصله یک آسیب پذیری، تمام جوانب را در نظر نمی گیرند. مثلا برای جلوگیری از دستکاری هدر X-Forwarded-Host فقط مقدار request.host را نسبت به یک لیست سفید چک می کنند، در صورتی که request.port را در نظر نمی گیرند. مثلا این درخواست را ببینید:

GET / HTTP/1.1
Host: example.com
X-Forwarded-Host: example.com:123

توسعه دهنده های وبسایت، به این نکته توجه نکرده اند که ممکن است در مقدار X-Forwarded-Host شماره Port نیز وارد شود. و همین اشتباه به هکر کمک می کند با وارد کردن شماره Port ناموجود، باعث منع سرویس شود.

HTTP/1.1 301 Moved Permanently
Location: https://example.com:123/

عملکرد صفحه بدون مشکل انجام شد و کاربر را به صفحه ای دیگر هدایت کرد. همین پاسخ در سرور Cache ذخیره می شود و از این به بعد هر کسی که بخواهد به صفحه اصلی سایت example.com وارد شود، به example.com:123 هدایت می شود که صفحه ای ناموجود است.

در سه مثال قبلی دیدیم که جلولیگری از حمله Web Cache Poisoning گاهی اوقات می تواند پیچیده باشد. در نتیجه کسی که به دنبال رفع این آسیب پذیری است باید نکات زیادی را مد نظر قرار دهد. بهتر است چنین شخصی دانش کافی در مورد Web Cache و نحوه عملکرد آن داشته باشد. معمولا توسعه دهنده های Framework ها، کتابخانه ها و Web Server ها کسانی هستند که بهتر می توانند در این زمینه موثر باشند.

مثال Cache تو در تو

تا اینجا تمام مطالب گفته شد. اما یک مثال فوق العاده از آسیب پذیری Web Cache Poisoning طی تحقیقات James Kettle در سایت Portswigger منتشر شده است که در اینجا مطرح می کنیم. تلاش کردیم، روند توضیح خود محقق را ساده سازی کنیم و با روندی پیوسته و خلاصه توضیح دهیم.

سناریوی کلی

سناریوی این آسیب پذیری که بر روی سایت unity.com کشف شده است به این شکل است: سرور وب اصلی (سایت Unity) از Drupal استفاده می کند. Drupal یک مکانیزم Cache داخلی برای بهبود سرعت بارگزاری صفحات دارد. علاوه بر این، یک یا چند سرور Cache خارجی نیز برای سایت Unity تعبیه شده است. می توان به طور انتزاعی، چنین شکلی تصور کرد:

دو سرور Cache تو در تو
دو سرور Cache تو در تو

کلید نشده و استفاده شده

ابتدا باید هر دو سرور Cache را بررسی کنیم و مقادیر کلید شده و کلید نشده را پیدا کنیم. اما همینجا چالشی وجود دارد. ما یک درخواست ارسال می کنیم و یک پاسخ دریافت می کنیم. تشخیص این که کدام نتیجه، توسط کدام سرور، Cache شده است، کار آسانی نیست. اما طبق تحقیقات انجام شده، سرور Cache داخلی و خارجی، درخواست ها را اینطور می بینند:

سرور Cache داخلی Drupal
سرور Cache داخلی Drupal
طبق تحقیقات انجام شده، مشخص شده است که بخش query داخل URI استفاده شده و کلید نشده است که برای حمله مناسب است
سرور Cache خارجی
سرور Cache خارجی
طبق تحقیقات انجام شده، مشخص شده است که بخش path داخل X-Original-URL استفاده شده و کلید نشده است که برای حمله مناسب است

طبق چیزی که قبلا گفتیم، این نوع استفاده از مقادیر کلید نشده در درخواست وب، باعث به وجود آمدن آسیب پذیری Web Cache Poisoning می شود. خب تا اینجا فقط یک تکه پازل موجود است. تکه دیگر، وجود Gadget مناسب برای بهره برداری از راه مسموم کردن Cache است.

یک Gadget در Drupal

وقتی در سایت Drupal، مسیر را به // تغییر می دهیم، یک redirect به صفحه اصلی اتفاق می افتد. حال اگر پارامتر destination را در URI وارد کنیم، کاربر به جای انتقال به صفحه اصلی، به جایی که destination مشخص می کند، هدایت می شود. با این حال، Drupal فیلتری، روی ورودی destination اعمال می کند تا امکان انتقال به صفحه ای، خارج از سایت فعلی وجود نداشته باشد. مثلا اگر دامنه سایت unk9vvn.com باشد، Drupal چک می کند که آیا دامنه آدرس مشخص شده در destination نیز unk9vvn.com هست یا نه. اما ضعف در این فیلتر، امکان دور زدن آن را، به راحتی، فراهم می کند. ورودی http://evil.com\@unk9vvn.com از نظر Drupal جزوی از دامنه unk9vvn.com است. زیرا فکر می کند علامت \ برای escape کردن علامت @ استفاده شده است. با این فرض همه چیز طبق استاندارد (RFC3976) است و آدرس بالا جزوی از دامنه unk9vvn.com است. در حالی که در مرورگر ها، علامت \ به عنوان escape نیست. مرورگر ها علامت \ را با عادی سازی (Normalization) به / تبدیل می کنند. در نتیجه آدرس فوق، در مرورگر، به http://evil.com/@unk9vvn.com تبدیل خواهد که خارج از unk9vvn.com است. این یعنی با یک تکنیک ساده، فیلتر Drupal دور خورد و ما یک آسیب پذیری Open Redirect داریم. درخواست زیر را ببینید:

GET //?destination=https://evil.net\@unity.com/ HTTP/1.1
Host: unity.com

و این پاسخ دریافتی از Drupal است که باعث انتقال کاربر به آدرس https://evil.net/@unity.com می شود.

HTTP/1.1 302 Found
Location: https://evil.net\@unity.com/

بهره برداری

هدف این است که وقتی کاربران به صفحه ای در سایت اصلی مراجعه می کنند، به سایت مخرب evil.com منتقل شوند. با استفاده از Gadget بالا، ما می توانیم این کار را برای یک کاربر مشخص، از راه مهندسی اجتماعی، انجام دهیم. اما با Web Cache Poisoning می توان این کار را روی هزاران کاربر که مثلا می خواهند به صفحه unk9vvn.com/user/login وارد شوند، انجام داد. چطور باید Cache را مسموم کرد؟ درخواست زیر را ببینید:

آلوده کردن Cache داخلی
آلوده کردن Cache داخلی
رنگ متن ها متناسب با تصویر بالا، مربوط به Cache داخلی است تا بخش های مختلف و کلید شده یا نشده و استفاده شده یا نشده بودن آن ها مشخص شود

و این پاسخ دریافتی است:

HTTP/1.1 302 Found
Location: https://evil.net\@unity.com/

از این پس، هرگاه مسیر /foo.js?v=1 مشاهده شود، همین پاسخ باز می گردد که یک redirect به صفحه https://evil.net/@unity.com است. پس یعنی کاربر به جای فایل foo.js، فایل دلخواه هکر را مشاهده می کند.

حال این روش را برای دو لایه Cache باید پیاده کنیم. در درخواست اول، Cache داخلی را آلوده می کنیم:

GET /?destination=https://evil.net\@store.unity.com/ HTTP/1.1
Host: store.unity.com
X-Original-URL: /redirect

همان طور که در مثال قبل گفتیم، نتیجه این درخواست، یک redirect به آدرسی است که در destination مشخص شده است. مرحله بعدی این است که سرور Cache خارجی را نیز آلوده کنیم.

GET /download?v=1 HTTP/1.1
Host: store.unity.com
X-Original-URL: /redirect

نتیجه درخواست بالا این می شود که از این پس هر کس به مسیر /download?v=1 مراجعه کند، به صفحه مورد نظر هکر، یعنی https://evil.net\@store.unity.com/ هدایت می شود. علت این اتفاق این است که سرور Cache خارجی، بار اول که مسیر /download?v=1 را به عنوان کلید در پایگاه داده خود جستجو می کند، منبعی پیدا نمی کند. پس درخواستی به آدرس /redirect که مقدار X-Original-URL است، ارسال می کند تا منبع را دریافت کند. این درخواست به Cache داخلی می رسد. در آنجا مقدار /redirect به عنوان کلید در پایگاه داده جستجو می شود. این مقدار در Cache موجود و محتوای آن، redirect به صفحه مورد نظر هکر است که در مرحله قبلی Cache شده است. پس پاسخی که به سرور Cache خارجی باز می گردد، همان redirect است. و نتیجه، این می شود که redirect در Cache خارجی نیز ذخیره می شود و این همان چیزی است که ما می خواهیم؛ آلوده شدن Cache خارجی با پاسخ redirect به صفحه ای دلخواه.

مثال Cache تو در تو
مثال Cache تو در تو
با درخواست اول، Cache داخلی مسموم می شود و منبع مربوط به redirect به صفحه مورد نظر ما در آن ذخیره می شود. با درخواست دوم، این منبع به Cache خارجی منتقل می شود و این بار با کلید /download?v=1 که فایلی است که می خواهیم آن را آلوده کنیم تا کاربران به جای دانلود برنامه Unity برنامه مخرب ما را دانلود کنند. 😈
Post Views: 2,373
نوشتهٔ پیشین
تزریق کد قالب سمت کاربر به AngularJS
نوشتهٔ بعدی
دنیای آسیب پذیری XSS

دیدگاهتان را بنویسید لغو پاسخ

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

این فیلد را پر کنید
این فیلد را پر کنید
لطفاً یک نشانی ایمیل معتبر بنویسید.
شما برای ادامه باید با شرایط موافقت کنید

نویسنده

Eiliya Keshtkar
Chief Technology Officer

نوشته‌های تازه

  • آسیب پذیری های روز صفر ایمیل سرور Zimbra 12 تیر 1400
  • تحلیل تکنیکال جاسوس افزار پگاسوس (قسمت اول) 12 تیر 1400
  • دنیای آسیب پذیری XSS 12 تیر 1400
  • مسمومیت حافظه پنهان وب 12 تیر 1400
  • تزریق کد قالب سمت کاربر به AngularJS 12 تیر 1400

دسته‌ها

  • وبلاگ – آسیب پذیری ها (4)
  • وبلاگ – جرم شناسی دیجیتال (1)
  • وبلاگ – فتح پرچم (1)

آخرین نوشته ها

آسیب پذیری های روز صفر ایمیل سرور Zimbra
13 دی در 6:24 pm
تحلیل تکنیکال جاسوس افزار پگاسوس (قسمت اول)
14 مرداد 1400
دنیای آسیب پذیری XSS
13 تیر 1400

ارتباط با ما

[email protected]
۰۶۲۴۹ ۳۶۸ ۰۲۶
استان البرز، کرج، فردیس، فلکه اول، برج نگین
Twitter
GitHub
Telegram
YouTube
LinkedIn
Instagram

تمامی حقوق این سایت متعلق به شرکت اکسین ایمن نیکراد است.

  • شرایط استفاده
  • سیاست حفظ حریم خصوصی