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解碼的部分

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