DVWA-跨站脚本攻击XSS通关

XSS,全称Cross Site Scripting,即跨站脚本攻击(没有叫CSS是为了避免与层叠样式表(Cascading Style Sheets,CSS)的缩写混淆),某种意义上也是一种注入攻击,是指攻击者在页面中注入恶意的脚本代码,当受害者访问该页面时,恶意代码会在其浏览器上执行,需要强调的是,XSS不仅仅限于JavaScript,还包括flash等其它脚本语言。根据恶意代码是否存储在服务器中,XSS可以分为存储型的XSS与反射型的XSS。

1. Low

1.1. 反射型XSS

进行正常的数据输入。根据提示,在文本框中输入mkbk,然后提交,返回结果如下图所示。系统能够正常返回问候信息Hello mkbk

分析上面的数据输入与返回结果可以得出,服务器端的处理是在输入的名称前加上Hello,然后显示在HTML的<pre>标签之间。

进一步测试,假如提交的数据不是正常数据,而是一段JavaScript脚本,是否还能正确显示问候信息。输入 <Script>alert("XSS")</Script> 并提交,结果如图所示:

由图可知,只有Hello显示出来了,并弹出了XSS提示框。这说明嵌入的JavaScript脚本代码被浏览器正确执行,也表明系统中存在XSS攻击漏洞
本实验所利用的漏洞是提交数据时,服务器端没有对提交的数据进行过滤,导致提交的数据中含有JavaScript脚本代码,致使浏览器可以直接执行前端页面上的脚本程序。

1.1.1. 利用反射型XSS攻击窃取用户账号和口令

打开XSS(Reflected)实验环境,在Name文本框中输入如下脚本:<a href="http://192.168.217.130/dvwa/vulnerabilities/brute/">恭喜你获得500万大奖,点击领取</a>

提交后,诱导页面如上图所示。在该页面中有一个诱导用户点击的链接。一旦用户点击,就会跳转到登录页面,如下图所示:

当然,此登录页面也可以是攻击者蓄意设计的页面,一旦提交信息,攻击者就会获取用户的账号和口令信息。恶意攻击者可能会将此网站伪装成一个合法网站,甚至可以获取用户的手机号、银行卡号等更为重要的信息。

1.2. 存储型XSS

选择左侧列表中的XSS(Stored),进行攻击实验。进行正常的数据输入。根据提示,在Name文本框中输入 mkbk,在Message文本框中输入good comment,然后单击Sign Guestbook按钮,返回结果如图所示,能够正常返回刚刚提交的信息:

当再次刷新页面后,之前提交的信息仍然保留,说明提交的信息被存储在数据库中。
Alt text

进一步测试,假如提交的数据是一段JavaScript脚本,是否还能正确显示提交的信息。在Name文本框中输入mkbk,在Message文本框中输入<Script>alert("XSS")</Script>,提交之后,结果如图所示。

由上图可知,Name字段的mkbk正确显示了出来,但Message字段是空白,且弹出了XSS提示框。这说明嵌入的JavaScript脚本代码被浏览器正确执行,也表明系统中存在XSS攻击漏洞

再次刷新页面XSS提示框仍然会弹出来。因为嵌入的脚本已经被存储在数据库中,每次访问这个页面都会从数据库中加载数据,脚本都会被浏览器执行,也就是每次都会触发XSS攻击。

1.2.1 利用存储型XSS攻击窃取浏览器Cookie

打开XSS(Stored)实验环境,在Name文本框中输入Cookie,在Message文本框中输入 <Script>alert(document.cookie) </Script> ,然后提交。结果如图所示:

由图可知,获取到了用户浏览器的Cookie信息。之后只要有用户访问这个页面,该用户的浏览器Cookie信息就会被显示出来。更进一步,如果攻击者将此信息通过构造一个HTTP请求,自动发送给攻击者服务器,那么攻击者就能存储所有访问页面用户的Cookie信息。

1.2.2. 利用Cookie完成Session劫持

在DVWA实验环境中,打开登录界面 http://192.168.217.130/dvwa/login.php ,输入用户名admin和密码password,正常登录后,跳转到 http://192.168.217.130/dvwa/index.php 页面中,随后,使用审查元素,获取Cookie详细信息:

获取信息后,可以利用Cookie欺骗工具进行访问。
单击下图中数字2处的图标,将数字3处的文本框激活,将从上面获取的Cookie详细信息(security=low; PHPSESSID=vb96k8kefadp9h72gklmff3ap6)填入数字3处。将上一步骤的登录后的网址 http://192.168.217.130/dvwa/index.php 填到数字1处,单击数字4处的连接,即可完成登录操作:

在该实验中,使用了老兵Cookie欺骗工具,在获取到客户端登录时的Cookie信息后,不需要输入用户名、密码,即可跳转到登录后的页面,完成Session劫持。


2. Medium

将DVWA实验平台的安全级别设置为Medium,选择左侧列表中的XSS(Reflected),进行XSS攻击实验(存储型XSS攻击和反射型XSS攻击的防御方法原理相同)。在该实验环境中,提交JavaScript脚本<script>alert("XSS")</script>,结果如图所示:

可以看到并未弹出XSS提示框,且<script>标签之间的alert("XSS")被当作name正确地显示了出来。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php

header ("X-XSS-Protection: 0");

// 有输入吗?
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL )
{
// 获取输入
$name = str_replace( '<script>', '', $_GET[ 'name' ] );

// 最终用户的反馈
echo "<pre>Hello {$name}</pre>";
}

?>

分析源代码可知,服务器端把<script>标签字符串替换成了空白。这样,后台中的$name变量就变成了alert('XSS'),浏览器收到的回应页面的代码是<pre>Hello alert('XSS')</pre>,而这不是一个可以执行的JavaScript代码段,所以提示框无法弹出。

针对上面的过滤方案,可采用此方法的方法绕过,HTML的标签是不区分大小写的,即<script><Script>是同一个标签。将之前提交的<script>alert("XSS")</script>脚本改写成<Script>alert("XSS")</Script>,XSS提示框还是可以弹出来:

字符串双写也可绕过,输入<s<script>cript>alert("xss")</script>,成功弹框:

3. High

仍然提交JavaScript脚本<script>alert("XSS")</script>,结果如图所示:

可以看到并未弹出XSS提示框,且Hello后面只剩下一个>符号。这说明XSS攻击未成功。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php

header ("X-XSS-Protection: 0");

// 有输入吗?
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL )
{
// 获取输入
$name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $_GET[ 'name' ] );

// 最终用户的反馈
echo "<pre>Hello {$name}</pre>";
}

?>

分析源代码可知,服务器端通过正则表达式对提交的内容做了过滤,导致注入脚本无法被执行。

针对上面的过滤方案,可以采用下面的方法绕过。XSS攻击除了直接嵌入触发之外,还可以利用HTML标签属性的事件进行触发。将之前提交的<script>alert("XSS")</script>脚本改写成<body onload="alert('XSS')"></body>,就能成功弹出“XSS”提示框:


4. Impossible

此时不论提交什么,XSS提示框都无法弹出。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php

// 有输入吗?
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
// 检查反 CSRF 令牌
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );

// 获取输入
$name = htmlspecialchars( $_GET[ 'name' ] );

// 最终用户的反馈
echo "<pre>Hello {$name}</pre>";
}

// 生成反 CSRF 令牌
generateSessionToken();

?>

分析源代码可知,服务器端对提交的数据调用了htmlspecialchars()函数进行处理,此函数的作用是把一些预定义的字符转换为HTML实体。例如,&显示为&amp;"显示为&quot;<显示为&lt;>显示为&gt;等。含有这些字符的恶意代码在浏览器中无法被正确执行。


5. 总结

low级别的代码直接引用了name参数,并没有任何的过滤与检查,存在明显的XSS漏洞。输入<script>alert("xss")</script>可直接弹框。对于反射型XSS,可以诱导用户点击链接从而跳转到钓鱼页面进行账号密码的骗取;对于存储型XSS,可以先将恶意代码存储到数据库中,当用户访问网站时,网站从数据库中读取恶意代码,拼接在页面中,当用户浏览页面时,就会执行恶意代码将用户的隐私信息发送到自己的服务器。

Medium级别的代码对输入进行了过滤,基于黑名单的思想,使用str_replace函数将输入中的<script>删除, 双写可绕过<sc<script>ript>alert(/xss/)</script>; 大小写混淆可绕过
<ScRipt>alert(/xss/)</script>

High级别的代码同样使用黑名单过滤输入,preg_replace() 函数用于正则表达式的搜索和替换,这使得双写绕过、大小写混淆绕过(正则表达式中i表示不区分大小写)不再有效。虽然无法使用<script>标签注入XSS代码,但是可以通过img、body等标签的事件或者iframe等标签的src注入恶意的js代码:<img src=1 onerror=alert(/xss/)>