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编码的了,所以不存在。

 

 

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