Cross-site scripting (XSS)
زمان مطالعه :8 دقیقه
DOM-based XSS, Testing, Exploiting
DOM-based XSS
https://portswigger.net/web-security/cross-site-scripting/dom-based
در این بخش، ما درباره DOM-based cross-site scripting (DOM XSS) توضیح خواهیم داد، نحوه یافتن آسیبپذیریهای DOM XSS را بیان میکنیم و درباره چگونگی بهرهبرداری از DOM XSS با منابع و مقصدهای مختلف صحبت میکنیم.
?What is DOM-based cross-site scripting
آسیبپذیریهای DOM-based XSS معمولاً زمانی به وجود میآیند که جاوااسکریپت دادهها را از یک منبع قابلکنترل توسط مهاجم، مانند URL، دریافت میکند و آن را به یک مقصد که از اجرای کد دینامیک پشتیبانی میکند، مانند eval() یا innerHTML، منتقل میکند. این امکان را به مهاجمان میدهد تا جاوااسکریپت مخرب را اجرا کنند که معمولاً به آنها اجازه میدهد حسابهای کاربری دیگران را هک کنند.
برای اجرای یک حمله DOM-based XSS، شما باید دادهها را به یک منبع (source)وارد کنید تا به یک مقصد منتقل شوند و باعث اجرای جاوااسکریپت دلخواه شوند.
رایجترین منبع برای DOM XSS، URL است که معمولاً با object،window.location دسترسی پیدا میکند. یک مهاجم میتواند لینکی ایجاد کند تا قربانی را به یک صفحه آسیبپذیر با payload در query string و بخشهای fragment از URL ارسال کند. در شرایط خاص، مانند زمانی که یک صفحه 404 هدف قرار میگیرد یا یک وبسایت در حال اجرای PHP است، payload میتواند در مسیر نیز قرار بگیرد.
برای توضیح دقیق جریان آلوده بین منابع و مقصدها، لطفاً به صفحه آسیبپذیریهای DOM-based مراجعه کنید.
How to test for DOM-based cross-site scripting
اکثر آسیبپذیریهای DOM XSS میتوانند سریع و قابل اطمینان با استفاده از Burp Suite's web vulnerability scanner یافت شوند. برای تست دستی DOM-based cross-site scripting، شما معمولاً نیاز به استفاده از مرورگری با ابزارهای توسعهدهنده، مانند Chrome، دارید. شما باید از هر منبع موجود به ترتیب کار کنید و هر یک را به طور جداگانه تست کنید.
Testing HTML sinks
برای تست DOM XSS در یک مقصد HTML، یک رشته تصادفی الفبایی (random alphanumeric string) را به منبع وارد کنید (مانند location.search) سپس از ابزارهای توسعهدهنده برای بررسی HTML و یافتن مکانی که رشته (string)شما ظاهر میشود استفاده کنید. توجه داشته باشید که گزینه "View source" مرورگر برای تست DOM XSS کار نمیکند زیرا تغییراتی که توسط جاوااسکریپت در HTML ایجاد شدهاند را در نظر نمیگیرد. در ابزارهای توسعهدهنده Chrome، شما میتوانید با استفاده از Control+F (یا Command+F در MacOS) در DOM رشته خود را جستجو کنید.
برای هر مکانی که رشته شما در داخل DOM ظاهر میشود، شما باید زمینه آن را شناسایی کنید. بر اساس این زمینه، شما باید ورودی خود را بهبود دهید تا ببینید چگونه پردازش میشود. به عنوان مثال، اگر رشته شما در داخل یک ویژگی نقلقول دوتایی (double-quoted)ظاهر میشود، سعی کنید نقلقولهای دوتایی را به رشته خود وارد کنید تا ببینید آیا میتوانید از ویژگی خارج شوید.
توجه داشته باشید که مرورگرها با توجه به URL-encoding متفاوت رفتار میکنند، Chrome، Firefox و Safari، URL-encode location.search و location.hash میکنند، در حالی که IE11 و Microsoft Edge (قبل از Chromium) این منابع را URL-encode نمیکنند. اگر دادههای شما قبل از پردازش URL-encoded شوند، احتمالاً یک حمله XSS کار نخواهد کرد.
Testing JavaScript execution sinks
تست مقصدهای اجرای جاوااسکریپت برای DOM-based XSS کمی سختتر است. با این مقصدها، ورودی شما الزاماً در جایی در داخل DOM ظاهر نمیشود، بنابراین نمیتوانید آن را جستجو کنید. در عوض، شما باید از اشکالزدای جاوااسکریپت استفاده کنید تا تعیین کنید که آیا و چگونه ورودی شما به یک مقصد ارسال میشود.
برای هر منبع بالقوه، مانند location، ابتدا باید مواردی را در داخل کد جاوااسکریپت صفحه پیدا کنید که منبع در حال استفاده است. در ابزارهای توسعهدهنده Chrome، میتوانید از Control+Shift+F (یا Command+Alt+F در MacOS) برای جستجو در تمام کد جاوااسکریپت صفحه برای منبع استفاده کنید.
پس از پیدا کردن جایی که منبع خوانده میشود، میتوانید از اشکالزدای جاوااسکریپت برای افزودن یک نقطه توقف و دنبال کردن نحوه استفاده از مقدار منبع استفاده کنید. ممکن است ببینید که منبع به متغیرهای دیگر اختصاص داده میشود. در این صورت، شما باید دوباره از تابع جستجو برای پیگیری این متغیرها استفاده کنید و ببینید آیا به یک مقصد ارسال میشوند یا خیر. هنگامی که یک مقصد پیدا کردید که دادهها از منبع اصلی به آن اختصاص داده میشوند، میتوانید از اشکالزدا برای بازرسی مقدار استفاده کنید و با قرار دادن نشانگر ماوس روی متغیر، مقدار آن را قبل از ارسال به مقصد مشاهده کنید. سپس، مانند مقصدهای HTML، شما باید ورودی خود را بهبود دهید تا ببینید آیا میتوانید یک حمله XSS موفق ارائه دهید یا خیر.
Testing for DOM XSS using DOM Invader
شناسایی و بهرهبرداری از DOM XSS در محیط واقعی میتواند فرآیندی خستهکننده باشد که اغلب نیاز به بررسی دستی جاوااسکریپت پیچیده و minified دارد. با این حال، اگر از مرورگر Burp استفاده کنید، میتوانید از افزونه DOM Invader داخلی آن که بسیاری از کارهای سخت را برای شما انجام میدهد، بهرهمند شوید.
Read more
Exploiting DOM XSS with different sources and sinks
در اصل، یک وبسایت به DOM-based cross-site scripting آسیبپذیر است اگر یک مسیر اجرایی وجود داشته باشد که از طریق آن دادهها بتوانند از منبع به مقصد منتقل شوند. در عمل، منابع و مقصدهای مختلف دارای خصوصیات و رفتارهای متفاوتی هستند که میتواند بر قابلیت بهرهبرداری تأثیر بگذارد و تعیین کند که چه تکنیکهایی لازم است. علاوه بر این، اسکریپتهای وبسایت ممکن است اعتبارسنجی یا پردازش دیگری از دادهها انجام دهند که باید هنگام تلاش برای بهرهبرداری از یک آسیبپذیری در نظر گرفته شوند. انواع مختلفی از مقصدها وجود دارد که به آسیبپذیریهای DOM-based مربوط هستند. لطفاً به لیست زیر برای جزئیات مراجعه کنید.
مقصد document.write با عناصر اسکریپت کار میکند، بنابراین میتوانید از یک payload ساده مانند زیر استفاده کنید:
;document.write('... <script>alert(document.domain)</script> ...')
اما توجه داشته باشید که در برخی موارد محتوای نوشته شده به document.write شامل مقداری زمینه اطراف است که باید در بهرهبرداری خود در نظر بگیرید. به عنوان مثال، ممکن است نیاز به بستن برخی از عناصر موجود قبل از استفاده از payload جاوااسکریپت خود داشته باشید.
مقصد innerHTML عناصر اسکریپت را در هیچ مرورگر مدرنی قبول نمیکند و همچنین رویدادهای onload برای svg اجرا نمیشوند. این بدان معنی است که شما باید از عناصر جایگزینی مانند img یا iframe استفاده کنید. میتوانید از مدیریت رویدادها مانند onload و onerror همراه با این عناصر استفاده کنید. برای مثال:
element.innerHTML='... <img src=1 onerror=alert(document.domain)> ...'
Sources and sinks in third-party dependencies
برنامههای وب مدرن معمولاً با استفاده از تعدادی کتابخانه و فریمورک شخص ثالث ساخته میشوند که اغلب امکانات و قابلیتهای اضافی را برای توسعهدهندگان فراهم میکنند. مهم است که به یاد داشته باشید برخی از اینها نیز منابع و مقصدهای بالقوه برای DOM XSS هستند.
DOM XSS in jQuery
اگر یک کتابخانه جاوااسکریپت مانند jQuery استفاده میشود، به دنبال مقصدهایی باشید که میتوانند عناصر DOM در صفحه را تغییر دهند. به عنوان مثال، تابع jQuery's attr() میتواند ویژگیهای عناصر DOM را تغییر دهد. اگر دادهها از منبعی که توسط کاربر کنترل میشود مانند URL خوانده شوند و سپس به تابع attr() منتقل شوند، ممکن است بتوان مقدار ارسالی را به گونهای دستکاری کرد که باعث XSS شود. به عنوان مثال، در اینجا ما جاوااسکریپتی داریم که ویژگی href یک عنصر anchor را با استفاده از دادههای URL تغییر میدهد:
$(function() {
$('#backLink').attr("href",(new URLSearchParams(window.location.search)).get('returnUrl'));
});
میتوانید از این طریق URL را تغییر دهید تا منبع location.search شامل یک URL جاوااسکریپت مخرب باشد. پس از اینکه جاوااسکریپت صفحه این URL مخرب را به href لینک بازگشت اعمال کرد، کلیک کردن بر روی لینک بازگشت آن را اجرا خواهد کرد:
?returnUrl=javascript:alert(document.domain)
یک مقصد بالقوه دیگر که باید به آن توجه کنید، تابع jQuery's $() selector است که میتواند برای تزریق اشیاء مخرب به DOM استفاده شود.
jQuery به شدت محبوب بود و یک آسیبپذیری کلاسیک DOM XSS ناشی از استفاده وبسایتها از این selector همراه با منبع location.hash برای انیمیشنها یا اسکرول خودکار به یک عنصر خاص در صفحه بود. این رفتار اغلب با استفاده از یک handler رویداد hashchange آسیبپذیر، مشابه زیر، اجرا میشد:
$(window).on('hashchange', function() {
var element = $(location.hash);
element[0].scrollIntoView();
});
از آنجایی که hash قابل کنترل توسط کاربر است، یک attacker میتواند از این موضوع برای تزریق یک XSS vector به sink سلکتور $() استفاده کند. نسخههای جدیدتر jQuery این آسیبپذیری خاص را با جلوگیری از تزریق HTML به یک سلکتور (selector)وقتی که ورودی با کاراکتر hash (#) شروع میشود، برطرف کردهاند. با این حال، هنوز ممکن است کدهای آسیبپذیر در دنیای واقعی یافت شوند.
برای بهرهبرداری از این آسیبپذیری کلاسیک، باید راهی برای ایجاد یک رویداد hashchange بدون تعامل کاربر پیدا کنید. یکی از سادهترین روشهای انجام این کار، ارسال Exploit خود از طریق یک iframe است:
<iframe src="https://vulnerable-website.com#" onload="this.src+='<img src=1 onerror=alert(1)>'">
در این مثال، ویژگی src به صفحه آسیبپذیر با یک hash خالی اشاره میکند. هنگامی که iframe بارگذاری میشود، یک XSS vector به hash اضافه میشود که باعث اجرای رویداد hashchange میشود.
Note
حتی نسخههای جدیدتر jQuery نیز میتوانند از طریق sink سلکتور $() آسیبپذیر باشند، به شرطی که کنترل کامل بر ورودی آن از یک منبع که نیاز به پیشوند # ندارد، داشته باشید.
DOM XSS in AngularJS
اگر از فریمورکی مانند AngularJS استفاده شود، ممکن است امکان اجرای JavaScript بدون براکتهای زاویهای یا رویدادها وجود داشته باشد. هنگامی که سایتی از ویژگی ng-app در یک عنصر HTML استفاده میکند، این ویژگی توسط AngularJS پردازش خواهد شد. در این حالت، AngularJS کد JavaScript را داخل دو آکولاد دوتایی که میتواند مستقیماً در HTML یا داخل ویژگیها قرار بگیرد، اجرا خواهد کرد.
DOM XSS combined with reflected and stored data
برخی از آسیبپذیریهای خالص DOM-based درون یک صفحه واحد قرار دارند. اگر یک اسکریپت مقداری داده را از URL بخواند و آن را به یک sink خطرناک بنویسد، در این صورت آسیبپذیری کاملاً سمت کلاینت است.
با این حال، منابع محدود به دادههایی که مستقیماً توسط مرورگرها افشا میشوند، نیستند - آنها میتوانند از وبسایت نیز سرچشمه بگیرند. به عنوان مثال، وبسایتها اغلب URL parameters را در HTML response از سرور منعکس میکنند. این امر معمولاً با XSS عادی مرتبط است، اما میتواند منجر به آسیبپذیریهای reflected DOM XSS نیز شود.
در یک آسیبپذیری reflected DOM XSS، سرور دادهها را از request پردازش کرده و دادهها را به response منعکس میکند. دادههای منعکسشده ممکن است در یک literal رشتهای JavaScript یا یک مورد دادهای درون DOM، مانند یک فیلد فرم قرار گیرند. یک اسکریپت در صفحه سپس دادههای منعکسشده را به روشی ناامن پردازش کرده و در نهایت آنها را به یک sink خطرناک مینویسد.
eval('var data = "reflected string"');
وبسایتها ممکن است دادهها را روی سرور ذخیره کرده و آنها را در جای دیگری منعکس کنند. در یک آسیبپذیری stored DOM XSS، سرور دادهها را از یک request دریافت کرده، آنها را ذخیره میکند و سپس دادهها را در یک response بعدی شامل میشود. یک اسکریپت درون response بعدی حاوی یک sink است که سپس دادهها را به روشی ناامن پردازش میکند.
element.innerHTML = comment.author
?Which sinks can lead to DOM-XSS vulnerabilities
موارد زیر برخی از sinkهای اصلی هستند که میتوانند منجر به آسیبپذیریهای DOM-XSS شوند:
document.write()
document.writeln()
document.domain
element.innerHTML
element.outerHTML
element.insertAdjacentHTML
element.onevent
عملکردهای زیر در jQuery نیز sinkهایی هستند که میتوانند منجر به آسیبپذیریهای DOM-XSS شوند:
add()
after()
append()
animate()
insertAfter()
insertBefore()
before()
html()
prepend()
replaceAll()
replaceWith()
wrap()
wrapInner()
wrapAll()
has()
constructor()
init()
index()
jQuery.parseHTML()
$.parseHTML()
How to prevent DOM-XSS vulnerabilities
علاوه بر اقدامات کلی که در صفحه آسیبپذیریهای DOM-based توضیح داده شده است، باید از اجازه دادن به نوشتن پویا دادهها از هر منبع غیرقابل اعتماد به سند HTML خودداری کنید.
امیر رضا کبریادار
مشاهده مقاله های بیشتر
مقالات مرتبط
What is XSS, How does XSS work? Impact of an attack
زمان مطالعه :6 دقیقه
Reflected XSS, Impact, Contexts, Testing, FAQs
زمان مطالعه :5 دقیقه
.Stored XSS, Impact , Contexts, Testing for vulnerabilities
زمان مطالعه :3 دقیقه
XSS contexts: Between HTML tags, In HTML tag attributes, JavaScript, Client-side template injection
زمان مطالعه :6 دقیقه
Exploiting XSS vulnerabilities & Dangling markup injection
زمان مطالعه :4 دقیقه