خب اول از همه سلام مبین هستم، توی این بلاگ میخوام یکی از فلوهایی که طی کردم که ترکیب چندین آسیبپذیری باهم هستش و در نهایت منجر میشه به اون آسیبپذیری ای که من عاشقشم و اون چیزی نیست جز Account Takeover، در ادامه با من همراه باشید.
از اون جایی که نمیتونم اطلاعاتی از تارگت افشا کنم اینجا یک سایت اصلی داریم به نام vuln-site.com و یک سایت ثانویه که داخل Trusted Origin های وب سایت اصلی هست و از اون میتونیم به وبسایت اصلی درخواست authenticated ارسال کنیم که اون رو trusted-origin.com در نظر میگیریم اینجا.
خب داخل سایت اول یک فانکشنالیتی داشتیم که با اون میتونستیم ایمیل خودمون رو تغییر بدیم و من ترجیح دادم روی همون کار کنم (تغییر ایمیل = Account Takeover)، اول از همه سناریوی CSRF به ذهنم رسید که تستش کنم اما متاسفانه Fail شد و تمامی فاکتور های CSRF رعایت شده بود به جز Cookie ها که None بودن همشون، درخواست رو توی عکس پایین میتونید مشاهده کنید:
خب اینجا درخواست ما PUT بود، یک Custom Header داشتیم و همچنین Content-Type ما JSON بود و نمیتونستیم هیچ کدوم رو تغییر بدیم، در نتیجه CSRF Failed، اما در قسمت Response Header ها چنین هدر هایی مشاهده میشد:
Access-Control-Allow-Origin: https://vuln-site.com
Access-Control-Allow-Credentials: true
خب حالا اینجا من یک سناریو به ذهنم رسید که تمامی وب سایت هایی که متعلق به این کمپانی هستند رو لیست کنم و شروع کنم به بروت فورس کردن کنم و ببینم کدومشون داخل Trusted Origin ها هستند (ساب دامنه ها جزئی از Trusted Originها نبودند و فقط دامنه هایی که خودشون ست کرده بودن مورد قبول بود و این قسمت کاملا روی String فیکس شده بود و هرکجا رو تغییر میدادی کلا هدر های CORS دیگه توی Response Header ها نشون داده نمیشد).
بعد از لیست کردن کل دامنه های کمپانی یک اسکریپت کوچیک نوشتم که بیاد و به جای هدر Origin بزاره و درخواست رو ارسال کنه هرکدوم قبول شد رو به من نشون بده که برم روی اون کار کنم، به جز دامنهی اصلی یک دامنه دیگه بود که داخل Trusted Origin ها بود و هیچ ربطی ام به این سایت نداشت اصلا متوجه نشدم که چرا باید این دامنه توی لیست Trusted Origin ها باشه !، به هر حال مهم نبود رفتم که داخل اون ببینم میتونم یه XSS پیدا کنم یا نه، هیچ فانکشنالیتی ای اونجا نبود فقط Login و Reset Password اونجا بود که حتی یوزر ام نمیتونستم بسازم گویا اصلا کسی قرار نبوده وارد اینجا بشه و برای developerها بوده.
حالا نکتهی جالبی که این وسط منو یکم قلقلک داد این بود که داخل قسمت Reset Password یک فیلد بود که ایمیل رو از من به عنوان ورودی میگرفت و یک 303 میداد دوباره به صفحهی لاگین و ایمیل اون بالا رفلکت میشد.
حالا بیاین یکم دقیق تر به موضوع نگاه کنیم:
یک درخواست پست به /password/forgot زده میشد که در ریسپانس یک Status Code 303 دریافت میکردیم که مارو دوباره به مسیر /login هدایت میکرد، و وقتی به /login ریدایرکت میشدیم ایمیل ورودی ما داخل ریسپانس و plain text نمایش داده میشد، که عکس درخواست هارو پایین میفرستم براتون:
خب اینجا من سعی کردم که کلا Ignore کنم که CSRF Token وجود داره و سعی کنم ببینم اینجا اصلا آسیبپذیر هست به xss یا نه، که خوشبختانه وجود داشت و این پیلود با موفقیت رفلکت میشد: attacker@gmail.com'”>
ولی اگه میخواستی یک تگ باز کنی انگار یک checker function اون پشت بود که کلا اجازه نمیداد تگ باز کنی، ولی خب خوشبختانه این مورد به راحتی بایپس شد فقط با یک کاراکتر non printable که url encoded اون کاراکتر میشه:
%01
در نهایت من چنین پیلودی ارسال کردم:
و در جواب چنین چیزی رفلکت شد:
خب حالا من مطمئن شدم که اینجا آسیبپذیری XSS دارم ولی خب بازی اینجا تموم نمیشه و ما یک توکن CSRF داریم که اگه اون رو ارسال نکنیم کلا قضیه کنسل میشه و هیچی رفلکت نمیشه داخل ریسپانس ما!
و هیچ جوره ام نمیشد بایپسش کرد نه میشد پارامتر رو حذف کنی نه خالی بفرستی نه درخواست GET ارسال کنی، توکن ام با سشن شما سینک شده و فقط روی سشن شما جواب میده، در نتیجه باید یه فکر دیگه ای کرد.
شروع کردم به تحقیق کردن و خوندن که این csrf_token داره از کجا میاد و چجوری ست میشه، رسیدم به یک فایل جاواسکریپتی به اسم app.js که بعد از باز کردنش با چنین صحنه ای مواجه شدم:
سریع حملهی JSONP به ذهنم رسید و دقیقا سناریو مشابه رو پیاده سازی کردم، یعنی از طرف کاربر یک درخواست به app.js بزنم و csrfToken رو بخونم و توی یک درخواست پست به همراه پیلود XSS ارسال کنم که کاربر اکسپلویت بشه و در نهایت یک درخواست PUT به اون وبسایت اصلی بزنم که ایمیل کاربر رو عوض کنم.
قبل از این که ادامه بدم و PoC رو نشونتون بدم بیاین یه بار دیگه مرور کنیم که چه اتفاقی افتاده (امیدوارم گیجتون نکرده باشم، تمام تلاشمو کردم که به ساده ترین روش ممکن توضیح بدم):
ما یک وبسایت اصلی داریم به اسم vuln-site.com که یک درخواست غیر Simple میفرسته که ایمیل کاربر رو عوض کنه، در جواب درخواست ما متوجه میشیم که وبسایت داره از مکانیزم CORS استفاده میکنه و ما یک لیست از وبسایت های متعلق به کمپانی رو پیدا میکنیم و شروع به بروت فورس میکنیم که ببینیم کدومشون داخل Trusted Origin ها هستند، یک دامنه پیدا میشه که پس از تست متوجه میشیم به XSS آسیب پذیره ولی خب csrf_token جلوی ما رو میگیره، ما متوجه میشیم که توکن csrf داخل یک فایل جاواسکریپت هست که میتونیم اینجا حملهی JSONP رو اجرا کنیم و csrf_token کاربر رو بخونیم و یک درخواست همراه با csrf_token معتبر ارسال کنیم که پیلود xss داخلش هست و داخل اون پیلود xss یک فایل جاواسکریپت رو include میکنیم که روی سرور خودمون وجود داره و یک درخواست به وبسایت اصلی میزنه که ایمیل رو عوض کنه و ازونجایی که این دامنه داخل Trusted Origin ها هست درخواست PUT ما که Simple نیست ارسال میشه و با موفقیت ایمیل کاربر داخل سایت اصلی عوض میشه ما میتونیم Reset Password انجام بدیم و یک ایمیل تایید به ایمیل ما(مهاجم) ارسال میشه که خودمون میریم و تاییدش میکنیم و وارد حساب قربانی میشیم.
خب حالا CSRF PoC ما به این شکل درومد که یک پست به سایت Trusted Origin میزنیم که پیلود XSS داخلشه که یک فایل جاواسکریپت از سرور مهاجم include میشه داخلش:
پیلود به شکل html encoded درومده اما وقتی decode کنیم به این شکل در میاد:
محتویات داخل exploit.js ام به این شکل هستش:
قربانی پس از باز کردن attacker-website.com/exploit.js ایمیل حسابش داخل سایت اصلی عوض میشه و ما با موفقیت یک حمله Account Takeover با ترکیب آسیب پذیری های (CSRF, XSS, JSONP) انجام دادیم.
نکات کلیدی:
- اگه با CORS مواجه شدید، لازم نیست که فقط چک لیستهای عمومی داخل اینترنت هست رو چک کنیم و اگه جواب نداد بیخیال شیم، فقط کافیه کمی خلاقیت به خرج بدیم و لیست دامنههای کمپانی رو به دست بیاریم و بروت فورس کنیم شاید یکی از دامنه ها داخل لیست Trusted Origin ها بود.
- همیشه چک لیستهای عمومی CSRF کافی نیستند و اینجا ام کافیه که کمی خلاقیت به خرج بدیم و متوجه مکانیزم وبسایت بشیم که چجوری داره کار میکنه شاید یک آسیبپذیری دیگه وجود داشت مثل همین JSONP اینجا که منجر میشد CSRF Token رو به دست بیاریم.
امیدوارم از خوندن این بلاگ لذت برده باشین و تونسته باشم درصدی از علم به دست اومده از این آسیبپذیری رو به اشتراک گذاشته باشم، موفق باشید و شکار خوبی داشته باشید.
عالی بود👌🏾
🌹
آقا دمت گرم که به اشتراک گذاشتی
واقعا جذاب و کارآمد بود
تشکر خواهش میکنم 🌹
عالی بود
یکم گیج شدم، اول اینکه اگه ما بخوایم یه ایمیل رو عوض کنیم به ریسپانس که نیازی نداریم چرا باید cors بزنیم، خوب فک کنم اینجوری بوده اگه اون origin تراست نباشه درخواست رو نمیزنه، درسته؟
دوم اینکه اون کاستوم هدر چی شد، نیازی بهش نبود؟
درخواستی که ارسال میشده یک درخواستی بوده که Simple نبوده، در هر صورت اگه نمیتونستی یک دامنه داشته باشی که داخل Trusted Origin ها باشه نمیتونستی اکسپلویتش کنی !
کاستوم هدر یک مقدار ثابت بود که اگه ارسال نمیشد ارور ۴۰۰ میگرفتی
خفن بود مبین 🔥
تشکر خفنی از خودتونه ❤️
عالی بود خیلی حال کردم
خیلی عالی بود دمت گرم
آفرین مبین.
حاجی یه سوال میگم این کاراکتر انکد شده غیر قابل پرینت فقط برای انگل براکت باز شده اس یا بستن هم میتونه کمک کنه اگه راجب این کاراکتر ها که توی پیلود ها بتونن کمکمون کنن چیزی داری ممنون میشم بفرستی