0x01 XSS(Reflected)
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>';
}
?>
代码只是判断了name值是否为空,然后再将name打印出来,参数没有做任何的过滤,存在明显的XSS漏洞。
测试过程
输入<script>alert('0xdawn')</script>
成功弹框!
可以弹窗的函数:alert()、confirm()、prompt()
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>";
}
?>
$name = str_replace( '<script>', '', $_GET[ 'name' ] );
这句代码将<script>
替换成了空字符,从而进行简单的过滤。
测试过程
- 双写绕过:
<scr<script>ipt>alert('0xdawn')</script>
- 大写绕过:
<SCRIPT>alert('0xdawn')</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>";
}
?>
$name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $_GET[ 'name' ] );
//这段正则表达式直接将*s*c*r*i*p*t给过滤了,并且不区分大小写,使得双写绕过和大小写混淆绕过不可行,但同样是使用黑名单策略,仍存在安全隐患。
测试过程
尝试其他标签:
- img:
<img src=1 onerror=alert('0xdawn')>
当图片显示错误时,执行alert(‘0xdawn’) - 超链接:
<a href='#' onclick=alert('0xdawn')>0xdawn</a>
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();
?>
Impossible级别的代码使用htmlspecialchars函数把预定义的字符&、"、’、<、>转换为 HTML 实体,防止浏览器将其作为HTML元素。 当输入<script>alert('hack')</script>
时,因为 htmlspecialchars 函数会将 < 和 > 转换成html实体,并且${name}
取的是$name
的值,然后包围在<pre></pre>
标签中被打印出来,所以我们插入的语句并不会被执行。
0x02 XSS(Stored)
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();
}
?>
low级别的代码对我们输入的message和name并没有进行XSS过滤,而且数据存储在数据库中,存在比较明显的存储型XSS漏洞。
测试过程
name中填入0xdawn,message中填入<script>alert('0xdawn')</script>
代码立即执行
查看元素,发现js代码已经被写入进去。
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();
}
?>
代码中name值的处理增加了一个str_replace() 函数,用来将字符串中含有<script>
的字符串替换为空字符,从而有过滤作用;message值的处理中,在其第二次调用trim()函数时还内嵌了两个函数,先是使用addslashes() 函数、返回在预定义字符之前添加反斜杠的字符串,然后调用strip_tags()函数来剥去字符串中的HTML、XML 以及 PHP 的标签,在最后再调用htmlspecialchars() 函数、把预定义的字符转换为 HTML 实体,对输入的内容先进行HTML的编码然后再存储进服务器中,从而使message的SQL和XSS漏洞几乎不存在。
测试过程
-
从name入手,查看元素,修改name值的最大长度为100。
-
大小写混淆绕过,在name中填入
<SCRIPT>alert('0xdawn')</SCRIPT>
,成功写入。
- 双写绕过,在name中填入
<scr<script>ipt>alert('0xdawn')</script>
,成功写入。
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参数使用了正则表达式进行过滤,仍然可以突破。
测试过程
-
查看元素,修改name值最大限制为100.
-
name中填入
<img src=1 onerror=alert('0xdawn')>
,成功写入
-
超链接:name中填入
<a href='#' onclick=alert('0xdawn')>0xdawn</a>
,成功写入
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();
?>
Impossible在high级别的基础上对name参数也进行了更严格的过滤,导致name参数也无法进行XSS攻击。而且使用了Anti-CSRF token防止CSRF攻击,彻底防御XSS漏洞和CSRF漏洞。
0x03 XSS(DOM)
Low
源码分析
<?php
# No protections, anything goes
?>
代码没有任何的保护措施,对default参数没有任何过滤。
测试过程
直接构造xss代码,访问连接:
192.168.8.151/dvwa/vulnerabilities/xss_d/?default=English<script>alert('0xdawn')</script> //脚本成功执行
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;
}
}
?>
代码先检查default参数是否为空,如果不为空则接受参数的值,同时使用了stripos将<script>
进行过滤,并且不区分大小写。
测试过程
-
尝试用img标签进行写入:
http://192.168.8.151/dvwa/vulnerabilities/xss_d/?default=English<img src=1 onerror=alert('0xdawn')>
-
并没有弹窗,查看元素发现语句被写入了value值中,却没有插入到option标签里。
-
尝试闭合option标签注入:
http://192.168.8.151/dvwa/vulnerabilities/xss_d/?default=English</option><img src=1 onerror=alert('0xdawn')>
-
还是没有弹窗,img依然在value值中。
-
继续闭合select标签,使img成为独立标签:
192.168.8.151/dvwa/vulnerabilities/xss_d/?default=English</option></select><img src=1 onerror=alert('0xdawn')>
-
成功弹窗!写入alert事件。
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;
}
}
?>
high级别的代码先判断defalut值是否为空,如果不为空的话,再用switch语句进行匹配,如果匹配成功,则插入case字段的相应值,如果不匹配,则插入的是默认的值。
测试过程
’#‘字符之后的数据不会发送的服务器端,从而绕过服务器端过滤。
构造http://192.168.8.151/dvwa/vulnerabilities/xss_d/?default=English#<script>alert('0xdawn')</script>
即可成功弹窗。
Impossible
源码分析
<?php
# Don't need to do anything, protction handled on the client side
?>
防御机制写在了客户端里,无XSS漏洞。