DVWA-XSS (Stored) 存储型XSS

存储型XSS,顾名思义,就是会传入数据库,长久的使用,常见为留言板,用户信息资料。

LOW

审计源码

<?php
// 是否提交 btnSign
if( isset( $_POST[ 'btnSign' ] ) ) {
    // 获取输入的mtxMessage和txtName
    // trim() 首位去空
    $message = trim( $_POST[ 'mtxMessage' ] );
    $name    = trim( $_POST[ 'txtName' ] );

    // stripslashes() 将特殊字符前加入 \ 转义
    // mysqli_real_escape_string() 转义特殊字符 NUL (ASCII 0),\n,\r,\,',"
    // 对 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)) ? "" : ""));

    // 对 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)) ? "" : ""));

    // 将message 和 name 写入到 guestbook 表中 comment 和 name 字中 
    $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();
}

?>

对传入的messagename进行了转义,防止了SQL注入,对于XSS来说,这些转义没什么用
message内容中输入<script>alert(document.cookie)</script>
Nmae随便输入一个

点击提交

可以看到弹窗成功,这样每次刷新都会进行弹窗,为了方便我们测试,弹窗之后点击Clear Gueskbook
清楚之前的弹窗

进行清空数据

这是这是测试,反弹cookie可见另一篇博客:DVWA-XSS (DOM) DOM型跨站脚本攻击

Medium

审计源码

<?php
// 查看是否提交 btnSing
if( isset( $_POST[ 'btnSign' ] ) ) {
    // 获取传入的 mtxMessage 和 txtName
    // trim() 首位区控
    $message = trim( $_POST[ 'mtxMessage' ] );
    $name    = trim( $_POST[ 'txtName' ] );

    // 过滤传入 message
    // addslashes() 使用反斜线引用字符串
    // strip_tags() 去除HTML标签
    $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 中的 HTML 标签进行实例化操作
    $message = htmlspecialchars( $message );

    // 对 name 进行过滤
    // str_replace() 替换 <script> 为空
    $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)) ? "" : ""));

    // 跟新数据库
    $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();
}

?>

这里对message进行了严格的过滤,首选去除了其中的HTMl标签,让后又使用htmlspecialchars函数message进行了实例化操作
这里转到name传参,过滤了<script>标签,根据str_replace函数特性,只会过滤一次,所以这里可以进行双写绕过
测试
<scr<script>ipt>alert(document.cookie)</script>

发现只能输入10个字符,在前段做了限制,检查找到name输入框

maxlength="10"改为100

再次测试<scr<script>ipt>alert(document.cookie)</script>

可以输入,提交查看

成功弹出cookie

High

审计源码

<?php
// 判断传入的 btnSign
if( isset( $_POST[ 'btnSign' ] ) ) {
    // 获取传入的 mtxMessage、txtName
    $message = trim( $_POST[ 'mtxMessage' ] );
    $name    = trim( $_POST[ 'txtName' ] );

    // 跟上次一样的过滤,message已经被封死了
    $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 );

    // 使用 preg_replace 正则匹配 <script> 标签
    $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)) ? "" : ""));

    // 更新数据库
    $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<script>进行了严格的过滤
.*除了换行匹配所有,/i为不区分大小写,所以这次双写绕过也无法使用
使用<img />标签src属性自动请求特性,进行弹窗
首先修改name输入的长度

name输入<img src=1 onerror=alert(document.cookie) />

提交查看

成功弹窗

Impossible

审计源码

<?php
// 是否传入 btnSign
if( isset( $_POST[ 'btnSign' ] ) ) {
    // 检查 user_token
    checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );

    // 获取传入的 mtxMessage、txtName
    $message = trim( $_POST[ 'mtxMessage' ] );
    $name    = trim( $_POST[ 'txtName' ] );

    // 对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)) ? "" : ""));
    $message = htmlspecialchars( $message );

    // 对name中的标签进行实例化
    $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 );

    // 使用PDO方法更新数据库
    $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();
}

// 生成user_token
generateSessionToken();

message和name进行了HTML实例化,检查了了user_token,使用PDO方法进行数据库查询,经典的防御

posted @ 2022-06-02 11:12  Junglezt  阅读(236)  评论(0编辑  收藏  举报