DVWA之XSS

学习学习

Posted by lll-yz on December 8, 2020

DVWA–XSS详解

XSS概念:通常指黑客通过HTML注入纂改了网页,插入恶意脚本,从而在用户浏览网页时,控制用户浏览器的一种攻击。

XSS三种:

反射型xss:只是简单地把用户输入的数据反射给浏览器,简单来说,黑客往往需要用户诱使用户点击一个恶意链接,才能攻击成功。

存储型XSS:将用户输入的数据存储在服务器端。用户访问了带有xss得页面代码后,产生安全问题。

DOM XSS:通过修改页面的DOM节点形成的XSS。

XSS(DOM)

DOM型xss不会和后台服务器产生交互,而是通过浏览器的dom树解析。代码流向:前端–>浏览器

low
<?php

# No protections, anything goes

?> 

没有任何代码过滤。

payload:

?default=<script>alert('oh')</script>

DzewTK.png

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

?> 

stripos(): 返回字符串在另一个字符串中第一次出现的位置。

1.此处过滤了<script>标签,所以我们可以使用:<img src=1 onerror=alert('oh')>来替代。

rpFCoF.md.png

发现语句被插入到了values值中,并没有插入到option标签中,失败了。

2.闭合前面的option标签

default=></option><img src=1 onerror=alert('oh')>

rpARG4.md.png

发现只有>被插入到了option标签中。因为</option>闭合了option标签,使用img标签并没有插入。

3.继续构造语句去闭合select标签,制造出img独立语句,闭合</option></select>标签构造XSS事件

payload:

?default=></script></select><img src=1 onerror='alert('oh')'>

rpVOKA.png

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

?> 

default=只允许French,English,German,Spanish这几个字符串,否则会直接跳转到?default=English。

payload:

?default=English#<script>alert('oh')</script>

原理:由于form表单提交的数据需要经过js过滤,所以注释部分的JavaScript代码不会被传到服务器端(也就符合了白名单的要求)从而只在客户端显示。

impossible
<?php

# Don't need to do anything, protction handled on the client side

?> 

没有任何东西,保护的代码在客户端里。


[![rpeGlQ.png](https://s3.ax1x.com/2020/12/08/rpeGlQ.png)](https://imgchr.com/i/rpeGlQ)

[![rpeL7t.md.png](https://s3.ax1x.com/2020/12/08/rpeL7t.md.png)](https://imgchr.com/i/rpeL7t)

查看源代码:


decodeURL(lang),对lang进行URL解码。而decodeURL(lang)被(lang)替代了。发现我们输入的参数并没有进行URL解码,而我们输入的参数都是经过URL编码的,被直接赋予了option标签,所以不存在XSS漏洞。

#### 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参数判断了一下是否为空,没有进行任何过滤和检测,可直接进行输入。

``<script>alert('hhh')</script>``

[![rpnxyQ.png](https://s3.ax1x.com/2020/12/08/rpnxyQ.png)](https://imgchr.com/i/rpnxyQ)

一步到位。

##### 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( ‘

// Feedback for end user
echo "<pre>Hello ${name}</pre>"; }

?>


**str_replace():** 用其他字符代替字符串中的一些字符。

medium级别的代码只是在low上增加了对``<script>``的过滤,我们可以直接大小写绕过(双写绕过)。

``<Script>alert('hhh')</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>"; }

?>


**preg_replace():**执行一个正则表达式的搜索和替换。

high级别代码使用了正则表达式直接把<script过滤了,*表示一个或多个任意字符,i代表不区分大小写。所以大小写绕过和双写绕过不能用了,所以我们可以采用其他标签进行注入。

这里让弹个cookie吧:

``<img src=1 onerror=alert('document.cookie')>``

当图片显示错误时,执行alert(),就将我们要的cookie弹出来了。

[![rplpcT.png](https://s3.ax1x.com/2020/12/08/rplpcT.png)](https://imgchr.com/i/rplpcT)

##### 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(string):** 把预定义的字符 "<", ">", "&", ""(双引号)", "'(单引号)" 转换为HTML实体,防止浏览器将其作为HTML元素。

impossible级别的代码先判断name是否为空,不为空的话然后验证其token,来防范CSRF攻击。然后再用htmlspecialchars函数将name中的预定义字符转换成html实体,这样就防止了我们填入标签。

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

?>


**trim(string,charlist):** 移除string字符两侧的预定义字符,预定义字符包括\t 、 \n 、\x0B 、\r以及空格,可选参数charlist支持添加额外需要删除的字符

**stripslashes(string):** 去除掉string字符的反斜杠\

**mysqli_real_escape_string(string,connection):**函数会对字符串string中的特殊符号(\x00,\n,\r,\,‘,“,\x1a)进行转义。

**$GLOBALS:**引用全局作用域中可用的全部变量。$GLOBALS 这种全局变量用于在 PHP 脚本中的任意位置访问全局变量(从函数或方法中均可)。PHP 在名为 $GLOBALS[index] 的数组中存储了所有全局变量。变量的名字就是数组的键。

可以看出,low级别的代码对我们输入的message和name进行了SQL防御,并没有进行XSS过滤,而且数据存储在数据库中,存在比较明显的存储型XSS漏洞

直接输入即可:

[![rp3Vl6.png](https://s3.ax1x.com/2020/12/08/rp3Vl6.png)](https://imgchr.com/i/rp3Vl6)

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

?>


**addslashes(string):** 函数返回在预定义字符之前添加反斜杠的字符串,预定义字符:"'(单引号)",""(双引号)","\\", "null"。

**strip_tags(string):** 函数剥去string字符串中的 HTML、XML 以及 PHP 的标签

**htmlspecialchars(string):** 把预定义的字符 "<" 、 ">" 、& 、‘’、“” 转换为 HTML 实体,防止浏览器将其作为HTML元素

可以看出对message参数进行了严格的过滤,但对那么参数的过滤比较简单,只是进行了script替换,和长度限制。

可以进行大小写绕过,长度限制可以F12直接修改一下 。

[![rp88UJ.png](https://s3.ax1x.com/2020/12/08/rp88UJ.png)](https://imgchr.com/i/rp88UJ)

在name栏进行注入

[![rp8wDO.png](https://s3.ax1x.com/2020/12/08/rp8wDO.png)](https://imgchr.com/i/rp8wDO)

##### 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进行正则表达式的过滤。

同样F12改一下name的限制长度,在用其他标签进行注入。

``<img src=1 onerror=alert('oh')>``

``<body onload=alert('yyy')>``

``<a herf="" onclick=alert('hhh')>click</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();

?> ```

对name也进行了更加严格的过滤,无法进行name参数注入,还增加了Anti-CSRF token防止CSRF攻击,完全杜绝了XSS漏洞和CSRF漏洞。