DVWA靶場的XSS詳解

目錄

反射型

low

medium

high

impossible

存儲型

low

medium

high

impossible

DOM型

low

medium

high

impossible


 

反射型

 

low

服務器代碼:

<?php
header ("X-XSS-Protection: 0");
// Is there any input?
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
// Feedback for end user
$html .= '<pre>Hello ' . $_GET[ 'name' ] . '</pre>';
}
?>

代碼解釋:

對輸入的內容沒有任何過濾。直接構造:

<script>alert(1)</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
$html .= "<pre>Hello ${name}</pre>";
}
?>

關鍵代碼解釋:

str_replace():以其他字符替換字符串中的一些字符(區分大小寫)。

第一個參數:必需,指定需要被替換的值。

第二個參數:必需,指定要替換成的值。

第三個參數:必需,指定被檢索的字符串。

第四個參數:可選,指定對替換數進行計數的變量。

代碼解釋:

可以看到把<script>替換成了空,str_replace函數區分大小寫。這裏我們可以不用這個標籤了,也可以換成大寫。

<Script>alert(1)</Script>
<img src=1 οnerrοr=alert(1)>

 

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
$html .= "<pre>Hello ${name}</pre>";
}
?>

關鍵代碼解釋:

preg_replace():執行一個正則表達式的替換和搜索。

第一個參數:必需,指定要搜索的模式,可以是字符串或者一個字符串數組。

第二個參數:必需,指定用於替換的字符串或者字符串數組。

第三個參數:必需,指定要被檢索替換的字符串或者字符串數組。

第四個參數:可選,指定每個被檢索的字符串的最大可替換數。

第五個參數:可選,指定爲替換執行的次數。

代碼解釋:

/i忽略大小寫,所以大寫也不可以了。並且只要有script順序的都被過濾了。這裏用別的標籤即可。

<img src=1 οnerrοr=alert(1)>

 

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
$html .= "<pre>Hello ${name}</pre>";
}
// Generate Anti-CSRF token
generateSessionToken();
?>

關鍵代碼解釋:

Htmlspecialchars():把預定義的字符 "<" 、 ">" 、& 、‘’、“” 轉換爲 HTML 實體,防止瀏覽器將其作爲HTML元素。

代碼解釋:

輸入進去的內容只會被當做字符串,不會被當做html元素,不管輸入什麼都不會被執行。

 

 

存儲型

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();
}
?>

關鍵代碼解釋:

1.trim():移除字符串兩側的字符。

第一個參數:必需,指定要檢查的字符串。

第二個參數:可選,指定從字符串中刪除哪些字符。如果省略,則移除預定義字符,\0 ,\t,\n,\x0B,\r,空格。

2.stripslashes():刪除反斜槓。

只有一個參數,必需,指定要檢查的字符串。

3.mysqli_real_escape_string():轉義在 SQL 語句中使用的字符串中的特殊字符,\x00,\n,\r,\,‘,“,\x1a。

第一個參數:必需,指定要使用的mysql的連接。

第二個參數:必需,指定要轉義的字符串。

代碼解釋:

對用戶的輸入沒有做任何防護措施,直接存儲到數據庫中。

這裏對name做了長度的限制,可以在前端改一下。message可以直接輸入。

<script>alert(1)</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();
}
?>

關鍵代碼解釋:

1.addslashes():在每個預定義字符(單引號,雙引號,反斜槓,null)前面添加反斜槓。

只有一個參數,必需,指定需要轉義的字符串。

2.strip_tag():函數剝去字符串中的 HTML、XML 以及 PHP 的標籤。該函數始終會剝離 HTML 註釋。

第一個參數:必需,指定要檢查的字符串。

第二個參數:可選,指定允許的標籤,這些標籤將不會被刪除。

代碼解釋:

對message先在每個預定義字符前面添加反斜槓,再去除html的標籤,並且做了實體化的處理。所以只能在name中進行xss測試。

可以看到對name的處理是將<script>替換成空,只做了這一項措施。可以雙寫繞過

<sc<script>ript>alert(/xss/)</script>

也可以大小寫混合繞過

<Script>alert(/xss/)</script>

還可以換一個標籤

<img src=1 οnerrοr=alert(1)>

 

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();
}
?>

代碼解釋:這一關就是比medium裏面多了對name的一項處理,這裏用了正則表達式的處理,處理同反射型的high。只要是script順序的都不行,不區分大小寫,所以用img標籤還是可以的。

 

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都進行了實體轉換impossible。同前。

 

DOM型

low

服務器端代碼什麼也沒有。

前端代碼:

 

關鍵代碼解釋:

1.document對象和windows對象。

document是一個文檔對象,代表給定瀏覽器窗口中的HTML文檔;windows是一個窗口對象,表示瀏覽器中打開的窗口。一個窗口下面可以有多個文檔對象。

所以一個窗口下面只能有一個window.location.href,但是可以有多個document.URL,document.location.href。

使用document對象可以對HTML文檔進行檢查、修改或添加內容,並處理該文檔的內部事件。

瀏覽器會爲HTML文檔創建一個window對象,併爲每個框架創建一個額外的window對象。

window是一個頂層對象,而不是另一個對象的屬性即瀏覽器的窗口。

document對象是window對象和frame對象的一個屬性,是顯示與窗口或框架內的一個文檔。

document只是屬於window的一個子對象。

Window.location包含href屬性,直接取值賦值相當於window.location.href(當前頁面完整URL)。

document.URL取值時等價於window.location.href或者document.location.href。在某些瀏覽器中通過對docum.URL賦值來實現頁面跳轉,但是某些瀏覽器中不行。

document.write可以在文檔流中寫入字符串。所以可以寫入標籤以及js代碼。參考 https://blog.csdn.net/m0_37589327/article/details/78992784

2.indexOf()方法:返回某個指定的字符串值在字符串中首次出現的位置。

第一個參數:必需的,規定要檢索的字符串。

第二個參數:可選,整數,規定要開始檢索的位置。省略將從頭開始檢索。

對大小寫敏感,如果沒有出現返回-1。

3.substring()方法:用於提取字符串中介於兩個指定下標之間的字符。

第一個參數:必需,開始的位置,非負整數。

第二個參數:可選,停止的位置,非負整數。如果省略,則到結尾。

4.decodeURI()方法:可對 encodeURI() 函數編碼過的 URI 進行解碼。只有一個參數,就是要解碼的URI或者其他文本。

代碼解釋:

先判斷 default= 是否存在,存在的話就將default的值取出來寫入option標籤中<option value='lang的值'>lang解碼的值</option>。對default的值沒有進行任何過濾,所以我們可以直接構造。

構造:

 http://127.0.0.1/DVWA/vulnerabilities/xss_d/?default=%3Cscript%3Ealert(1)%3C/script%%3E

 

 

medium

服務器端代碼:

<?php
// Is there any input?
if ( array_key_exists( "default", $_GET ) && !is_null ($_GET[ 'default' ]) ) {
$default = $_GET['default'];
\# Do not allow script tags
if (stripos ($default, "<script") !== false) {
header ("location: ?default=English");
exit;
}
}
?>

關鍵代碼解釋:

1.array_key_exists():檢查某個數組中是否存在指定的鍵名,如果鍵名存在則返回 true,如果鍵名不存在則返回 false。

第一個參數:必需,指定鍵名。

第二個參數:必需,指定數組。

2.stripos() :查找字符串在另一字符串中第一次出現的位置(不區分大小寫)。

第一個參數:必需,指定被檢索的字符串。

第二個參數:必需,指定要查找的字符串。

第三個參數:可選,指定開始檢索的位置。

如果沒有找到則返回false。

3.header():向客戶端發送原始的HTTP報頭。

第一個參數:必需,指定要發送的報頭字符串。

第二個參數:可選,指定該報頭是否替換之前的,默認是true即替換。否則添加第二個報頭,即false,允許同類型的多個報頭。

第三個參數:可選,強制指定HTTP響應碼。

 

代碼解釋:

過濾了<script>標籤。可以用別的標籤繞過。這裏不能用雙寫。

medium的前端代碼和low的一樣,沒有過濾。但是插入的內容在select標籤的option標籤裏面,這裏用img標籤插入,所以我們要想執行的話要先閉合option標籤,再閉合select標籤。

構造一下:

</option></select><img src=1 οnerrοr=alert(1)> 

 

 

high

前端代碼同前面一樣,沒有過濾。

服務器端代碼:

<?php
// Is there any input?
if ( array_key_exists( "default", $_GET ) && !is_null ($_GET[ 'default' ]) ) {
\# White list the allowable languages
switch ($_GET['default']) {
case "French":
case "English":
case "German":
case "Spanish":
\# ok
break;
default:
header ("location: ?default=English");
exit;
}
}
?>

代碼解釋:根據傳入default參數的值,執行switch語句,switch的default裏面給default設置的值是English,所以傳入的只能是French,English,German,Spanish其中的一個。所以需要傳入的代碼不經過服務器的過濾。而url中如果有字符 # ,那麼#後面的數據不會送到服務器端。我們可以根據這個來構造:

English #<script>alert(1)</script>

 

impossible

服務器端什麼也沒有。

前端代碼:

跟之前的區別就是在將default的值寫入標籤的時候沒有對輸入的值進行解碼,所以我們輸入的任何值都是經過URL編碼的了,所以不存在。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章