سلسله آموزش های تست نفوذ Web Application - قسمت سوم: حملات Cross Site Scripting یا XSS


مقدمه

Cross Site Scripting یا XSS، از دسته حملات بررسی ورودی های کاربر است. در این حمله، اثر ورودی کاربر در سمت کلاینت یا سرور یا هردو، مورد بررسی قرار گرفته و در صورت عدم اعتبارسنجی ورودی کاربر، مهاجم از این ورودی برای تزریق ورودی آلوده خود بهره می برد. حملات اعتبارسنجی ورودی کاربر، XSS، SQLi، HTTP Header Tampering و ... را دربر می گیرد.

حمله XSS حمله ای است که مهاجم در آن هدف تزریق HTML یا اجرای کد جاوااسکریپت در مرورگر کاربر مشاهده کننده یک صفحه آسیب پذیر را دارد.

انواع حملات XSS

XSS بازتابی (Reflected XSS)

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

در این نوع حمله، فرد قربانی بایستی از طریق مرورگر خود و درخواست HTTP، Payload را درون صفحه وب تزریق کند  و سپس وب سرور پاسخ با کد آلوده را برگرداند و مرورگر کاربر قربانی آنرا اجرا نماید. بنابراین لازم است که مهاجم به نحوی بتواند لینک حاوی کد مخرب را برای  قربانی بفرستد و او را مجاب کند که روی آن کلیک نماید. از جمله روش های پنهان کردن Payload، استفاده از سرویس های کوتاه کننده لینک نظیر bit.ly یا tinyurl، ارسال لینک در ایمیل می باشد.

نکته: ترکیب XSS با Sender Spoof (در صورت عدم استفاده از SPF و DMARC رکوردها می تواند روش مناسبی برای رساندن Payload به قربانی باشد).

بیشترین استفاده از XSS بازتابی در ربایش Session IDها یا خود کوکی ها و در نتیجه ربایش نشست کاربران با ارزش می باشد. نمونه ای از یک سناریوی ساده اجرای XSS بازتابی را در تصویر زیر مشاهده می کنید:

rnpg-reflected-xss

XSS ذخیره شده (Stored XSS)

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

این نوع حمله خطرناک ترین نوع حمله XSS است چرا که هم بازدیدکنندگان سایت را هدف می گیرد و هم تنها نوعی از XSS است که مستقیما وبسایت (و نه فقط بازدیدکنندگان) را هدف گرفته و کد مخرب را درون آن تزریق می نماید. همچنین امکان دیفیس (Deface) و تغییر ظاهر صفحه وب توسط این نوع حمله نیز وجود دارد.

نکته دیگر آنکه، اگرچه در XSS بازتابی کاربر می تواند با هشیاری و تجربه از این حمله قسر در برود اما در XSS دائمی، به محض بازشدن صفحه آسیب پذیر، کدمخرب توسط مرورگر کاربر اجرا خواهد شد و عملا راه دفاعی برای کاربر باقی نمی ماند.

DOM XSS

نوعی از XSS است که تنها درون کد سمت کلاینت (غالبا جاوااسکریپت) قابل اجرا است. بطور کلی این آسیب پذیری درون محیط DOM (Document Object Model) یعنی اسکریپت سمت کلاینت صفحه رخ داده و به کد سمت سرور نمی رسد. همچنین این آسیب پذیری تا حد زیادی شبیه XSS بازتابی است با این تفاوت که با سمت سرور تعامل ندارد. مثلا وب اپلیکیشن می تواند پیام خوشامدگویی را به شکل متفاوت (که در تصویر زیر می بینید) نمایش دهد:

rnpg-dom-xss

نکته کلیدی در این آسیب پذیری آن است که کد سمت کلاینت می تواند به DOM مرورگر و در نتیجه تمامی اطلاعات درون آن از قبیل URL، هیستوری، کوکی ها، محل ذخیره سازی و ... دسترسی داشته باشد. DOM در اصل آبجکتی است که در هنگام Parseکردن کد صفحه وب ارائه شده توسط وب سرور توسط مرورگر ایجاد می شود تا حرکت در میان تگ های مختلف HTML و سلسله مراتب آن آسان تر شود:

rnpg-dom-structure

می توان این ساختار را با استفاده از افزونه هایی نظیر Firebug و Dom Inspector در فایرفاکس و Inspect Element در کروم استخراج نمود. در این نوع حمله نیز مهاجم قادر به ربایش کوکی ها و نشست ها یا ربایش اکانت کاربر خواهد بود. همچنین این حمله را می توان در صورت ذخیره درون وب اپلیکیشن از طریق یک کوکی آلوده بصورت دائمی نیز اجرا کرد.

یافتن XSS

کجا دنبال XSS بگردیم؟

بطور کلی، همه این سه نوع آسیب پذیری تنها در صورتی رخ خواهند داد که ورودی کاربر اصلا پاکسازی (Sanitize) نشود یا فقط به شکل جزئی پاکسازی شود. در تست جعبه سیاه یک هدف، از آنجا که به کد منبع اپلیکیشن دسترسی نداریم، بایستی خودمان بفهمیم که با گرفتن ورودی کاربر، اپلیکیشن چگونه آنرا پردازش می کند و چه خروجی می دهد؟ اگر هرگونه وابستگی بین ورودی و خروجی وجود داشته و ورودی کاربر بخشی از خروجی باشد، آنگاه یک نقطه مستعد XSS یافته ایم.

پس هرجا که از کاربر ورودی گرفته می شود، می تواند به صورت بالقوه یک نقطه آسیب پذیر باشد که از طریق آن بتوان کد HTML یا جاوااسکریپت را تزریق نمود. از جمله موارد زیر:

  1. باکس جستجو
  2. باکس نظرات و کامنت ها
  3. متغیرهای GET/POST
  4. متغیرهای کوکی
  5. سرایندهای HTTP
  6. به طور کلی هرجا که به ازای ورودی کاربر، در URL علائم <=> به همراه آن ورودی مشاهده شود.

پس از یافتن یکی از این موارد، یکی از ابتدایی ترین کارها تزریق کد HTML است. مثلا اگر جایی در باکس جستجو، عبارت جستجوشده در URL به صورت …keyword=aaa… آمد، می توانیم تگ <plaintext> را در URL جایگزین نموده و صفحه را تازه سازی (refresh) کنیم. در صورتی که بخشی از صفحه نتایج جستجو تغییر شکل داده  به شکل کد HTML (بعلت استفاده از تگ Plaintext) مشاهده شد، یعنی یک قدم در اجرای حمله جلوتر رفته ایم. مثال:

rnpg-html-injection1

rnpg-html-injection2

گام بعدی، بررسی امکان تزریق اسکریپت است که با تگ <script> جاوااسکریپت می توان انجام داد. در صورتی که جواب Permission Denied یا Denied Access نگیریم، بازهم یک گام در یافتن XSS جلو رفته ایم.

بطور کلی این فرایند بایستی برای تمامی جاهایی که وب اپلیکیشن اقدام به گرفتن ورودی کاربر می کند بررسی شود (چگونگی یافتن این ورودی ها در فصل قبل توضیح داده شده است -بعنوان نمونه با استفاده از اسپایدر Burp Suite-).

اکسپلویت کردن XSS

همانگونه که در قسمت یافتن XSS گفته شد، اولین گام در فرایند اکسپلویت کردن و اجرای XSS، آن است که نقطه مستعد XSS (یعنی جایی که ورودی کاربر گرفته می شود) از لحاظ پاکسازی کردن/نکردن ورودی کاربر مورد بررسی قرار گیرد. اگر ورودی کاربر پاکسازی نشود، آنگاه بعنوان نمونه می توان اسکریپت زیر را تست کرد که یک پیام با محتوای XSS Example را در مرورگر نمایش می دهد:

rnpg-script-injection1

این قطعه کد در سمت وب اپلیکیشن بصورت زیر رندر و پردازش می شود:

rnpg-script-injection2

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

rnpg-script-injection3

به طور کلی تگ Body برای انتقال Payloadهای XSS بسیار مفید و کارامد می باشد:

rnpg-script-injection4

اما درباره این کد چطور؟

rnpg-script-injection5

در این صورت خواهیم داشت:

rnpg-script-injection6

 با توجه به این که DOM Eventها امکان استفاده از کاراکترهای مشکوک < و > را دارند بنابراین استفاده از آنها نیز می تواند بسیار کارساز باشد.

در صورتی که روتین های بررسی و اعتبارسنجی ورودی برقرار باشد، بایستی کمترین میزان کاراکتر مشکوک را استفاده نمود. در این حالت، در رویداد onload می توانیم javascript: را به شکل زیر تغییر دهیم:

rnpg-script-injection7

همچنین برای تغییر بیشتر می توانیم کد زیر را استفاده کنیم:

rnpg-script-injection8

نکته قابل ذکر آنکه، مرورگرهایی نظیر کروم و IE برای تست این آسیب پذیری ها چندان مناسب نیستند چرا که خود ممکن است این ورودی ها را فیلتر کنند و بنابراین استفاده از فایرفاکس بهتر است.

به طور کلی مهاجم می تواند موارد زیر را با استفاده از XSS انجام دهد:

  1. ربایش کوکی
  2. تغییر صفحه
  3. فیشینگ/بدافزار
  4. کرم های XSS

که در ادامه به سه مورد از مهمترین ها یعنی ربایش کوکی و دیفیس و فیشینگ می پردازیم.

ربایش کوکی

ربایش کوکی از آنجا مهم است که می تواند منجر به ربایش نشست شود که در مقابل، بکارگیری SOP (که در فصل مقدمه شرح داده شد) جلوی این ربایش را می گیرد. در مقابل، XSS به ما امکان این ربایش را می دهد. مراحل ربایش کوکی یک کاربر (و در نتیجه نشست او) و ارسال آن به سرور راه اندازی شده مهاجم به شرح زیر است:

  • یافتن یک آسیب پذیری XSS در هدف مورد نظر (که می تواند بازتابی یا دائم باشد)؛ مثلا در سرچ باکس هدف.
  • استفاده از پی لود صحیح؛ مثال:

rnpg-interesting-payload

که در آن:

rnpg-payload-part1

URL و پارامتر آسیب پذیر،

rnpg-payload-part2

آغاز و پایان اسکریپت تزریقی جاوااسکریپت و

rnpg-payload-part3

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

  • رساندن پی لود به کاربر هدف (در صورت استفاده از XSS بازتابی) یا تزریق کد در وب اپلیکیشن در صورت استفاده از XSS دائمی.
  • راه اندازی سرور مهاجم برای جمع آوری کوکی ها: سمت سرور مهاجم. محتوای steal.php چیزی شبیه به قطعه کد زیر است:

rnpg-server-side-code

که در این حالت هرکسی که URL آلوده را مشاهده کند، کوکی او برای مهاجم فرستاده می شود.

دیفیس کردن

در این حمله، قربانی خود وبسایت است و مهاجم نیاز به یک XSS دائمی دارد تا بتواند دیفیس واقعی را اجرا کند. پس بایستی مهاجم در پی ورودی از کاربر باشد که بدون پاکسازی و اعتبارسنجی در دیتابیس وب اپلیکیشن ذخیره می شود (مانند کامنت باکس ها، که باید هم قسمت عنوان کامنت چک شود و هم قسمت متن کامنت). پس از یافتن این XSS دائم، خواهیم توانست ظاهر صفحه وب را با دستکاری DOM تغییر دهیم.

یک نوع ساده دستکاری DOM استفاده از کد زیر است:

rnpg-dom-deface

آبجکت body در DOM متناظر با تگ BODY است که محتوای صفحه را نگاه می دارد. با تنظیم این مقدار، در اصل محتوای مدنظر خود را با محتوای فعلی جایگزین می کنیم که به این عمل دیفیس گفته می شود.

فیشینگ

به منظور انجام فیشینگ و ربایش Credential یک کاربر، بایستی مهاجم بتواند در صفحه لاگین هدف موردنظر، یک XSS بیابد. در این صورت تنها لازم است که تغییری در FORM لاگین ایجاد نماید: یوزرنیم و پسورد بایستی به دامنه تحت کنترل مهاجم ارسال شود. اصلی ترین کار در این راستا، تغییر پارامتر ACTION در FORM لاگین است. تگ FORM معمولا ساختار زیر را دارد:

rnpg-xss-phishing1

که با تزریق قطعه اسکریپت زیر می توان عمل فیشینگ را انجام داد:

rnpg-xss-phishing2

گواهینامه های SSL، چک های DNS و ... در مقابل چک های DNS و ... در مقابل XSS بسیار ضعیف عمل می کنند.

 

پی نوشت: حقوق برخی از تصاویر استفاده شده در متن متعلق به elearnsecurity می باشد.