三详解 DVWA_Stored存储型XSS

Posted 在下小黄

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了三详解 DVWA_Stored存储型XSS相关的知识,希望对你有一定的参考价值。

创建时间:2022年5月16日21:56:10
作者:在下小黄


存储区:后端数据库
插入点:html

  • 定义:

攻击者直接将恶意JS代码上传或者存储到漏洞服务器中,当其他用户浏览该页面时,站点即从数据库中读取恶意用户存入的非法数据,即可在受害者浏览器上来执行恶意代码;持久型XSS常出现在网站的留言板、评论、博客日志等交互处

  • 特点:

不需要用户单击特定URL便可执行跨站脚本

  • 利用方式:

直接向服务器中存储恶意代码,用户访问此页面即中招
XSS蠕虫

  • 总结:

存在用户交互的地方,带有用户保存数据功能的地方,就容易出现存储型XSS(留言板、论坛发帖、商品评论、用户私信、博客日志等)


一、Stored Low 级别:

  1. 我们拿到这个题目的时候,首先对代码进行审计:
<?php

if( isset( $_POST[ 'btnSign' ] ) ) 
    // Get input
    $message = trim( $_POST[ 'mtxMessage' ] );
    $name    = trim( $_POST[ 'txtName' ] );

    // Sanitize message input 对 message 输入进行过滤
    $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 输入进行过滤
    $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();


?> 
---------------------------------------------------------------------------------------
PHP $_POST 变量:在 PHP 中,预定义的 $_POST 变量用于收集来自 method="post" 的表单中的值。
  
isset()函数在php中用来检测变量是否设置,该函数返回的是布尔类型的值,即true/false
trim()函数移除字符串两侧的空白字符或其他预定义字符,预定义字符包括\\0、\\t、\\n、\\x0B、\\r以及空格,可选参数charlist支持添加额外需要删除的字符。
stripslashes()函数用于删除字符串中的反斜杠
is_object() 函数用于检测变量是否是一个对象。
$GLOBALS :引用全局作用域中可用的全部变量。$GLOBALS 这种全局变量用于在 PHP 脚本中的任意位置访问全局变量(从函数或方法中均可)。PHP 在名为 $GLOBALS[index] 的数组中存储了所有全局变量。变量的名字就是数组的键。
trigger_error() 函数创建用户自定义的错误消息。函数用于在用户指定的条件下触发一个错误消息。它可以与内建的错误处理程序一起使用,或者与由 set_error_handler() 函数设置的用户自定义函数一起使用。
SQL INSERT INTO 语句用于向表中插入新记录。此代码中涉及到的是第二种用法,需要指定列名和被插入的值
mysqli_query() 函数执行某个针对数据库的查询。
mysqli_real_escape_string()函数会对字符串中的特殊符号(\\x00,\\n,\\r,\\,',",\\x1a)进行转义在代码中对message,name输入框内容没有进行XSS方面的过滤和检查。且通过query语句插入到数据库中。所以存在存储型XSS漏洞
  1. 代码含义:
  • 首先判断输入,接收前台传递的method="post"表单数据
  • 对接收到的数据进行预处理一次,清除传递表单数据以外的东西
  • stripslashes(string)函数对'txtName',无处理
  • stripslashes(string)函数对'mtxMessage'清除传递数据中的反斜杠/ , 利用mysqli_real_escape_string()函数对namemessage 进行转义,一般用于防止数据库撞库。
  • 下面就是对数据进行处理,更新写入数据库
  • 接下来我们在name框中插入恶意代码,可以发现输入框对长度有所限制,一种方法我们通过bp抓包修改长度,另一种方法我们直接在控制台中修改maxlength来触发xss,如下图所示
  • <script>alert(document.cookie)</script>


二、Stored Medium 级别:

  1. 还是老套路,我们拿到一个题的时候,先去审一下代码:
<?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() 函数剥去字符串中的 HTMLXML 以及 PHP 的标签。该函数始终会剥离 HTML 注释。这点无法通过 allow 参数改变。
addslashes()函数返回在预定义字符(单引号、双引号、反斜杠、NULL)之前添加反斜杠的字符串。
可以看到,由于对message参数使用了htmlspecialchars函数进行编码,因此无法再通过message参数注入XSS代码,但是对于name参数,只是简单过滤了<script>字符串,仍然存在存储型的XSShtmlspecialchars(string): 把预定义的字符 "<" (小于)、 ">" (大于)、& 、‘’、“” 转换为 HTML 实体,防止浏览器将其作为HTML元素
  1. 双写绕过
  • Burpsuite抓包改name参数为:
  • <sc<script>ript>alert(/xss/)</script>

  1. 大小写混淆绕过
  • Burpsuite抓包改name参数为<ScRipt>alert(/xss/);</ScRipt>:

  1. 使用非** script **标签的** xss payload**
  2. 例如:img标签:
  • Burpsuite抓包改name参数为<img src=1 onerror=alert(/xss/)>>

  • 其他标签和利用还有很多很多….
  • 以上抓包修改数据Forward后,均成功弹窗:

三、Stored 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();


?> 
------------------------------------------------------------------------------------------------------------------------
$name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $name );
可以看到,这里使用正则表达式过滤了<script>标签,但是却忽略了img、iframe等其它危险的标签,因此name参数依旧存在存储型XSS
  • Burpsuite抓包改name参数为<img src=1 onerror=alert(/xss/)>:
  • Forward后,成功弹窗:


四、Stored **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();

?> 
----------------------------------------------------------------------------------------
可以看到,通过使用htmlspecialchars函数将几种特殊字符转义为HTML实体,mysqli_real_escape_string函数对单引号'转义,防止进行SQL注入,彻底防治了存储型 XSS 的利用和危害。
  • 可以看到,这次impossible在high级别的基础上对name参数也进行了更严格的过滤,导致name参数也无法进行XSS攻击。而且使用了Anti-CSRF token防止CSRF攻击,完全杜绝了XSS漏洞和CSRF漏洞。

五、参考链接:

https://www.runoob.com/sql/sql-insert.html
https://www.runoob.com/php/func-mysqli-query.html

https://www.w3school.com.cn/php/func_string_strip_tags.asp

了XSS漏洞和CSRF漏洞。


五、参考链接:

https://www.runoob.com/sql/sql-insert.html
https://www.runoob.com/php/func-mysqli-query.html

https://www.w3school.com.cn/php/func_string_strip_tags.asp

以上是关于三详解 DVWA_Stored存储型XSS的主要内容,如果未能解决你的问题,请参考以下文章

三详解 DVWA_Stored存储型XSS

反射/存储/DOM型XSS攻击原理及攻击流程详解

第849期如何让前端更安全?——XSS攻击和防御详解

XSS攻击

XSS绕过姿势

XSS(跨站脚本攻击)详解 (上)