امروز میخوایم راجع به حافظه کش، منع خدمت و آسیبپذیری که اخیرا رو یه کمپانی گنده پیدا کردم صحبت کنیم.
حافظه کَش (به انگلیسی: Cache) یه حافظه سیستمی میانیه که برای ذخیره موقت دادهها استفاده میشه تا بتونیم کارایی (Performance) بهتری رو هنگام گشتن تو صفحات وب داشته باشیم.
سمت کاربر (لوکال): کش مرورگر که روی دستگاه کاربر ذخیره میشه.
سمت سرور: این مورد پاسخ بعضی از درخواستهای مشخص رو روی سرور واسط ذخیره میکنه تا وقتی بقیه به اون منبع درخواست میزنن، دیگه بار روی سرور نیوفته و کاربرا پاسخشون رو از اون واسط میانی دریافت میکنند نه از سرور اصلی.
پس حتما متوجه شدید که نون توی کش سمت سروره! پس یکم بیشتر توضیح میدم:
به نقل از PortSwigger بزرگ: آسیبپذیری آلودهسازی حافظه کش وب، یک تکنیک پیشرفتست که به کمک اون، نفوذگر میاد و از این رفتار وب و حافظه کش استفاده میکنه تا پاسخهای شیطانی خودش رو برای کاربرای دیگه ارسال کنه!
یه حمله موفق آلودهسازی حافظه کش، میتونه به آسیبپذیریهای مختلفی از جمله تزریق HTML، XSS، هدایت آزاد (Open Redirect)، منع خدمت (DOS) و... منجر بشه.
برای بهرهبرداری از حافظه کش، نفوذگر باید کامل درک کنه که این سازوکار داره چجوری کار میکنه. خب ببینید، قبلتر گفتم که حافظه کش میاد و پاسخ مشابهی رو به درخواستهای مشابه میده، اما سوال اصلی اینجاست که از کجا میفهمه این درخواست مشابه قبلیه؟؟؟
خب اینجا باید با چیزی تحت عنوان مقادیر کلیدی در حافظه کش آشنا بشیم. (Chace Keys) این مقادیر درواقع بخشی از درخواست ما هستند که مثل اثر انگشت برای شناسایی درخواستهای یکسان استفاده میشه. اگر درخواستی بیاد به حافظه کش و اثر انگشت اون با اثر انگشت درخواست اولیه (ذخیره شده تو حافظه کش) یکی باشه، ینی این دو درخواست یکین و حافظه کش خودش میاد و بهش جواب میده و دیگه سمت سرور نمیفرسته. حالا درخواست ما قطعا شامل بخشهای دیگهای هم میشه که تاثیری روی شناسایی درخواستهای یکسان نداره، به اونا میگن درخواستهای Unkeyed (فارسیش نمیدونم چی میشه دیگه، آهان بهش میگیم مقادیر غیرکلیدی D: ) که حافظه کش اهمیتی نمیده این موارد تو درخواستهای مختلف یکی باشن یا با هم فرق کنن. این مقادیر غیر کلیدی دقیقا جایی هست که نفوذگر میاد و ازش برای تزریق و ایجاد حمله استفاده میکنه. مثلا خیلی از سرآیندها غیرکلیدی هستن، این درحالیه که مقدار این مقادیر توی پاسخ هم دیده میشه! (مفاهیم اولیه برای حملات تزریق HTML و XSS) بذارید یه مثال کوچیک هم بزنم. فکر کنید من یه درخواست میزنم به یه سایت و با مرورگر کروم میرم، این سایت سرآیند User-Agent مرورگر من رو روی صفحه نشون میده و مینویسه "شما با مرورگر کروم وارد شدهاید."، حالا اگه این پاسخ روی سرور کش ذخیره بشه، یکی بعدا بیاد داخل سایت که از مرورگر فایرفاکس استفاده میکنه، اگه درخواستی رو ارسال کنه به منبعی که من قبلا ارسال کردم، سرور کش میاد و همون پاسخی که من گرفته بودم رو میده به اون بنده خدا، اینجا اتفاقی که میافته اینه که اون بنده خدا با فایرفاکس اومده تو سایت اما سایت داره بهش میگه "شما با مرورگر کروم وارد شدهاید." !!!! خب این مورد میتونه باعث چی بشه؟
1- ذخیره یک مقدار تزریق شده در پاسخهای کش
2- ارائه این مقادیر تزریق شده به بقیه کاربرا
# به این میگن تزریق حافظه کش
مقادیر کلیدی میتونن متفاوت باشن و این که چه چیزی بهعنوان مقادیر کلیدی درنظر گرفته بشه، به تنظیمات سرور کش بستگی داره. بعضی وقتها فقط خط اول درخواست (Request line) و سرآیند Host بهعنوان مقدار کلیدی در نظر گرفته میشن و تمامی بخشهای دیگه بهعنوان مقادیر غیرکلیدی در نظر گرفته میشن. پس خیلی مهمه که بهعنوان هکر کلاه سفید قبل از اینکه بیایم حمله کنیم، مقادیر کلیدی و غیرکلیدی رو شناسایی کنیم.
خب من تونستم تو زمان خیلی کوتاهی این باگ رو توی یه کمپانی بزرگ پیدا کنم. اولین کاری که برای پیدا کردن این آسیبپذیری باید انجام بدیم، اینه که پاسخ سرور رو با دقت بررسی کنیم.
اولین نکته خیلی مهم تو این درخواست، سرآیند X-Cahce که مقدارش برابر با HIT هست، این نشون میده که پاسخی که ما گرفتیم داره از سرور کش میاد نه از خود سرور! ولی اگه مقدارش برابر با MISS بود ینی اینکه این پاسخ داره مستقیم از سرور میاد و کش نشده. البته خیلی مهمه که بدونید سرآیند X-Cache استاندارد نیست و ممکنه اسمش تو سایتهای مختلف عوض بشه و چیز دیگهای باشه! اما مقدارش همیشه یا HIT و یا MISS هست.
دومین نکته خیلی مهم سرآیند Age هست که اینم مربوط به تنظیمات کشه، عددی که جلوی این سرآیند نوشته شده، نشون میده که این پاسخ بهمدت چند ثانیه قراره تو حافظه کش ذخیره بمونه (بعدش پاک میشه)؛ بعضی وقتا ممکنه سرآیندهای دیگهای هم ببینید، مثلا ممکنه Cache-Control رو ببنیم که یکسری تنظیمات مربوط به کش رو همراه خودش داره، یکی از این تظیمات که خیلی مهمه، اسمش هست max-age که اینجا تو این پاسخی که عکسش رو گذاشتم وجود نداره. این پیکربندی مشخص میکنه که تا چه مدتی ما اجازه نداریم درخواست جدید برای گرفتن دادهها ارسال کنیم. (بهعبارت دیگه زمانی که دادهها باید کش بمونن) این موارد به مهاجم کمک میکنه تا تشخیص بده چه زمانی باید آلودهسازی خودش رو انجام بده.
سومین نکته خیلی مهم سرآیندیه به اسم Vary که اینجا هم ما داریمش، این سرآیند خیلی مهمه چرا؟ چون داره بهصورت واضح به ما یکسری از مقادیر کلیدی رو اعلام میکنه. مثلا اینجا دو سرآیند Accept-Encoding و x-wf-forwarded-proto کلیدی هستن و میشه ازشون برای مشخص کردن درخواستهای یکسان استفاده کرد. البته یه نکته خیلی مهم وجود داره و اونم اینه که ممکنه مقادیر کلیدی دیگهای هم وجود داشته باشن که توی این سرآیند بهشون اشارهای نشده باشه.
قبل از اینکه کار رو شروع کنیم باید این نکته رو در نظر بگیرید که توی سامانههای عملیاتی، نباید با حملات آلودهسازی حافظه کش، باعث از کار افتادن سامانه بشیم، مخصوصا وقتی که سامانه ما مهم و حیاتی باشه، چون میتونه آسیب زیادی به اون سازمان بزنه. برای اینکار از تکنیکی به اسم Cache Busting استفاده میکنیم. بعضی از اجزاء همیشه بهعنوان مقادیر کلیدی در نظر گرفته میشن، با URL شروع میکنیم. (البته همیشه استثناء وجود داره)
اگر یک پاسخ کش برای درخواست به https://www.example.com داخل کش سرور ذخیره بشه و یک کاربر بیاد و درخواست بزنه به https://www.example.com/?test=test اونوقت سرور کش، این درخواست رو بهعنوان یک درخواست جدید در نظر میگیره و اون رو به سرور اصلی ارسال میکنه. (چون URL یکی از مقادیر کلیدیه که با تغییرش باعث میشیم سرور درخواست ما رو یک درخواست جدید در نظر بگیره)
این رفتار به ما اجازه میده تا یک سامانه رو بدون اینکه آسیبی بهش وارد بشه بررسی کنیم. برای اینکار فقط کافیه تا یه پارامتر تصادفی به آدرس URL اضافه کنیم تا مطمئن باشیم کسی به اون آدرس درخواست نمیزنه. این باعث میشه تا بتونیم آسیبپذیری رو بدون آسیب زدن به سامانه پیدا کنیم.
بعد از بررسیها مشخص شد که سرور داره از سازوکار کش استفاده میکنه و دو سرآیند Accept-Encoding و x-wf-forwarded-proto هم جزو مقادیر کلیدی هستن. خب حالا من اومدم به دنبال مقادیر غیر کلیدی بگردم تا بتونم تزریق خودم رو انجام بدم. خب اینجا یه سرآیند داریم به اسم X-Timer که این مورد معمولا تو پاسخ هم رفلکت میشه (البته ازش نمیشه به XSS رسید چون داخل سرآیندها رفلکت میشه و اصلا توی بدنهی پاسخ قرار نمیگیره). اما وقتی چنین رفتاری داره، یعنی این سرآیند داره سمت سرور پردازش میشه، پس ممکنه بتونیم ازش برای ایجاد خطا استفاده کنیم. موفق هم شدم :)
همونطور که میبینید برای اینکه سامانه رو خراب نکنم، اومدم و یه پارامتر الکی به درخواست اضافه کردم (mycachebuster=zhero_) و بعدش درخواستم رو ارسال کردم. خب به خاطر اینکه سرآیند X-Timer رو دستکاری کردم به خطا خوردم، حالا یه مرورگر دیگه باز کردم و به همون آدرس درخواست زدم (بدون اینکه سرآیند X-Timer رو دست بزنم) و بووووممممم! خطا داد!
صفحه مورد نظر دیگه قابل استفاده نیست و از دسترس خارج شده!
منبع: اینجا