DVWA XSS部分

DVWA XSS练习

反射型(Reflected)

Low

输入框里随便输入,比如aaa点击submit

访问:http://localhost/DVWA/vulnerabilities/xss_r/?name=aaa#

查看源代码发现只有一处有回显:

<pre>Hello aaa</pre>

可控的变量是name

直接插script标签进行尝试:

payload:<script>alert(1)</script>

成功弹窗

代码分析:


<?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>';
}

?>

没有做任何的过滤。

Medium

插script标签进行尝试:

查看源代码:
<pre>Hello alert(1)</pre>

应该是过滤了<script>一类的

构造payload:<scr<script>ipt>alert(1)</script>

成功弹窗

代码分析


<?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>";
}

?>

<script>标签置换成了空

High

尝试了 low , medium 等级的payload都是过滤掉了,试试img标签。

payload:<img src=x onerror=alert(1)>

成功弹窗


<?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>";
}

?>

通过正则表达式进行了过滤,无论script中间夹了什么都能置空。

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

?>

将输入过来的值利用htmlspecialchars函数实体化了。就基本没有可能xss了。

htmlspecialchars:

语法:

htmlspecialchars(string,flags,character-set,double_encode)

定义和用法
htmlspecialchars() 函数把预定义的字符转换为 HTML 实体。

预定义的字符是:

& (和号)成为 &
" (双引号)成为 "
' (单引号)成为 '
< (小于)成为 <
> (大于)成为 >

提示:如需把特殊的 HTML 实体转换回字符,请使用 htmlspecialchars_decode() 函数。

存储型(Stored)

Low

随便输入一个数据,查看源代码:

<div id="guestbook_comments">
    Name: admin<br />
    Message: test<br />
</div>

构造payload:

<script>alert(1)</script>

发现Name处有长度限制。不过Message部分也可以触发xss进行弹窗。

看看能不能通过审查元素更改Name输入框的长度限制:

查看源代码:

<input name="txtName" type="text" size="30" maxlength="10">

maxlength="10"删掉,提交后发现弹了两下窗口。

测试完成以后可以点击那个Clear Guestbook来清除之前提交的记录,不然每次刷新都弹窗很烦。

代码分析

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

?>

代码的大概意思就是收到name跟message之后直接存到数据库里。基本上没有什么过滤,message是用stripslashes函数去除了一下斜杠。

Medium

提交了 Low 等级的payload后返回页面的源代码:

<div id="guestbook_comments">
    Name: aaa<br>
    Message: alert(1)<br>
</div>

也是<script>标签被过滤了。

构造一下:<scr<script>ipt>alert(1)</script>

还是被过滤了,代码可能是跟反射型漏洞的high一样叭,试试别的标签。

<img src=x onerror=alert(1)>

em~ 也过滤了。

看了一眼代码,发现是把message实体化了,只能通过Name来传payload了。

也是利用代码审计把长度限制去掉,也可以利用抓包工具在改一下数据内容。

payload:<scr<script>ipt>alert(1)</script>

就可以弹窗了。

代码分析

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

代码的意思就是说,传入message跟name,然后两个变量都是把<script>置空,然后把message实体化之后才保存至数据库。

High

既然medium难度就把message实体化了,所以high应该也是实体化了,所以把name的长度限制去掉,传入一个img标签的payload试试:

payload:<img src=x onerror=alert(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 = 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();
}

?>

处理方法跟反射型的high难度有异曲同工之妙。也是利用了正则表达式。

Impossiable

impossiable难度是安全的。

代码分析

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

?>

两个变量都实体化了。

Dom型 (DOM)

Dom的一开始做了只做会了Low等级的,就暂时放一边了。

Low

点击select时访问:http://localhost/DVWA/vulnerabilities/xss_d/?default=English

查看源代码发现default之后的值就是<option>标签里的值,查看源代码:

<option value="English">English</option>

payload:
<script>alert(1)</script>

成功弹窗:

代码里什么也没写。

弹窗以后想要逃出value="English"这个地方触发xss。但是">传入这个之后没有什么反应。查看前端代码时发现一段js代码:

if (document.location.href.indexOf("default=") >= 0) {
    var lang = document.location.href.substring(document.location.href.indexOf("default=")+8);
    document.write("<option value='" + lang + "'>" + decodeURI(lang) + "</option>");
    document.write("<option value='' disabled='disabled'>----</option>");
}
    
document.write("<option value='English'>English</option>");
document.write("<option value='French'>French</option>");
document.write("<option value='Spanish'>Spanish</option>");
document.write("<option value='German'>German</option>");

这里lang就是我们传入的值。

在浏览器的console里查看了一下lang的值,发现都是经过了url编码的。

Medium

尝试了一下Low等级的payload,直接返回到了

http://localhost/DVWA/vulnerabilities/xss_d/?default=English

这个地址。

尝试别的标签:http://localhost/DVWA/vulnerabilities/xss_d/?default=<img src=x onerror=alert(1)>

还是没有什么反应。

尝试关闭了option标签也是逃不过去,看了一下html嵌套规则:https://www.cnblogs.com/xiyangbaixue/p/4090511.html

发现得把select标签页一并关闭才可以,构造一下payload:

</option></select><img src=x onerror=alert(1)>

成功

代码分析:


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

?>

发现只要包含script标签就会执行跳转。

High

首先尝试了一下medium难度的payload,执行了跳转操作。

没什么思路,看了一下代码:


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

?>

网上搜了一下:https://www.cnblogs.com/huangming-zzz/p/9901770.html

利用了#号,URL中#号之后的内容,不会被提交到服务器,可以直接与浏览器进行交互

payload:?default=English#<script>alert(1)</script>

Impossiable

安全,后端也没有代码。前端跟之前的不一样:

document.write("<option value='" + lang + "'>" + decodeURI(lang) + "</option>");

改成了:

document.write("<option value='" + lang + "'>" + (lang) + "</option>");

去掉了url解码的部分

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