繞過XSS filters的幾種方法
XSS跨站腳本攻擊是指,黑客向一個頁面中注入Javascript腳本,其它的用戶訪問該頁面時會執行這個腳本。為了防止這一攻擊,一些軟件嘗試從輸入中移除Javascript代碼。這很難正確實現。在這篇文章中我會展示一些試圖移除輸入里的Javascript腳本的代碼,并演示幾中繞過它的方法。
以網上商城軟件 Magento 中的類 Mage_Core_Model_Input_Filter_MaliciousCode 為例。這個類的作用是過濾“惡意代碼”,包括以任何形式插入的Javascript。
代碼如下所示:
protected $_expressions = array(
'/(\/\*.*\*\/)/Us',
'/(\t)/',
'/(javascript\s*:)/Usi',
'/(@import)/Usi',
'/style=[^<]*((expression\s*?\([^<]*?\))|(behavior\s*:))[^<]*(?=\>)/Uis',
'/(ondblclick|onclick|onkeydown|onkeypress|onkeyup|onmousedown|onmousemove|onmouseout|onmouseover|onmouseup|onload|onunload|onerror)=[^<]*(?=\>)/Uis',
'/<\/?(script|meta|link|frame|iframe).*>/Uis',
'/src=[^<]*base64[^<]*(?=\>)/Uis',
);
function filter($value) {
return preg_replace($this->_expressions, '', $value);
}
$_expressions變量包含一個正則表達式列表,preg_replace函數會移除文本中匹配該正則表達式的內容。所以如果你輸入<script>foo</script>,兩個標簽都會被移除,只保留foo。
讓我們看一些繞過這個filter的方法。我們的目標是繞過它傳遞一些執行Javascript的HTML代碼。這個filter有若干表達式,它們的含義是阻止下面的內容:
Javascript URL
可以在URL中使用javascript:…讓該鏈接執行javascript:
<a href="javascript:alert('test')">link</a>
filter移除了代碼中的javascript:,所以我們不能直接用上面的代碼。我們可以試著改變javascript:部分,讓瀏覽器任然執行它并且正則表達式匹配不上。我們試試URL-encode:
<a href="javascript:alert('xss')">link</a>
正則表達式匹配不上了,但瀏覽器在用它之前對該鏈接做了URL-decode操作,所以依然可以執行它。
除了Javascript之外還有VBScript。它在IE11中被棄用并且禁用了,但是在Internet Explorer的老版本中依然可以使用,如果你把IE 11設置為IE 10模擬模式的話也是可用的。我們可以像Javascript鏈接那樣執行相同的代碼。
<a href='vbscript:MsgBox("XSS")'>link</a>
CSS導入
Internet Explorer在CSS中支持Javascript表達式,稱為動態屬性 https://msdn.microsoft.com/en-us/library/ms537634 (v=vs.85).aspx。允許攻擊者加載外部的CSS樣式表是非常危險的,因為攻擊者可以在原始頁面的上下文中執行Javascript。
在惡意的css中:
body {
color: expression(alert('XSS'));
}
我們可以在CSS中使用反斜杠轉義字符來規避@import過濾。
Internet Explorer允許反斜杠,現在它繞過了我們的filter。
Inline樣式
我們也可以使用Inernet Explorer支持的內嵌樣式中的動態屬性:
<div style="color: expression(alert('XSS'))">
filter會檢查這樣的字符串,style后面跟的不是<并且后面包含expression:
/style=[^<]*((expression\s*?\([^<]*?\))|(behavior\s*:))[^<]*(?=\>)/Uis
因此,我們在那里增加一個<.
<div style="color: '<'; color: expression(alert('XSS'))">
這可以繞過filter,因為[^<]匹配不上<,并且這還是一個有效的CSS,雖然“<”不是一個有效的color,但是其余部分仍然被使用了。
Javascript事件
可以在一個元素上定義事件句柄,如下:
<div onclick="alert('xss')">
這樣,這個Javascript會在有人點擊它的時候執行,但是也有一些事件是在頁面加載后或者用戶移動鼠標的時候觸發。filter移除了許多這樣的事件,但是它并沒有包含所有的事件句柄。比如,漏了onmouseenter:
<div onmouseenter="alert('xss')">
我們的代碼會在用戶把鼠標移動到div上面時執行。
另一個繞過的方法是在屬性和”=”之間加上一個空格。Magento在最新版本的惡意代碼filter中已經修復了它。
<div onclick ="alert('xss')">
Script標簽
Script標簽可以用來定義行內腳本,或者從其它位置加載腳本文件:
我們的filter移除了<script>標簽。然而,它只是做一次,因此我們可以讓我們想要的內容在移除標簽之后出現:
<scr<script>ipt>alert("XSS")</scr<script>ipt>
filter移除了兩個發現的<script>,最后我們還是執行了想要的代碼。實際上,這個嵌套標簽的辦法可以用來規避任意的filter表達式。
結論
盡管filter試圖阻止了幾種腳本注入的辦法,我們都找到了規避的方法。創建一個filter來規避XSS攻擊是不容易的。你必須考慮各種編碼類型以及不同的瀏覽器行為。這讓開發者做起來很難,卻方便了攻擊者。
安全影響
我展示了幾種繞過filter的辦法。這是一個安全威脅,除非沒有對不可信輸入使用這個filter。在 Magento 2.0.1 release notes 中有這樣一段話:
用戶在輸入HTML代碼的時候可以輕易繞過MaliciousCode filter函數。但是,Magento幾乎不用這個filter,并且當前的用法都不允許未授權用戶輸入。
1月23日,我進一步聯系了Magento,他們不認為這是一個安全問題,所以我發布了這篇文章。
*本文譯者:felix,翻譯自: http://www.sjoerdlangkemper.nl/2016/01/29/circumventing-xss-filters/
來自: http://www.freebuf.com/articles/web/104656.html