XSS,全称Cross Site Scripting,即跨站脚本攻击,某种意义上也是一种注入攻击,是指攻击者在页面中注入恶意的脚本代码,当受害者访问该页面时,恶意代码会在其浏览器上执行,需要强调的是,XSS不仅仅限于JavaScript,还包括flash等其它脚本语言。根据恶意代码是否存储在服务器中,XSS可以分为存储型(Stored)的XSS与反射型(Reflected)的XSS。
DOM型的XSS由于其特殊性,常常被分为第三种,这是一种基于DOM树的XSS。例如服务器端经常使用document.boby.innerHtml等函数动态生成html页面,如果这些函数在引用某些变量时没有进行过滤或检查,就会产生DOM型的XSS。DOM型XSS可能是存储型,也有可能是反射型。
简单来说,XSS就通常指黑客通过HTML注入纂改了网页,插入恶意脚本,从而在用户浏览网页时,控制用户浏览器的一种攻击。
反射型XSS(Reflected)
把难度调至Low等级,然后进入XSS(Reflected),显示如下界面:
我们打开代码,看一下逻辑和限制(路径如下图所示):
可以看到,代码直接引用了name参数,并没有任何的过滤与检查,存在明显的XSS漏洞。
先利用alert测试是否存在XSS,如果有弹窗弹出,说明有XSS漏洞:
http://192.168.1.1/DVWA-master/vulnerabilities/xss_r/?name=<script>alert(1)</script>
Medium
我们先把难度调节到中等,然后进入XSS Reflected页面:
然后我们照例用alert进行测试,发现并没有弹窗出现:
http://192.168.1.1/DVWA-master/vulnerabilities/xss_r/?name=<script>alert(1)</script>
那么真的没有XSS漏洞吗,显然不是,否则这个等级就失去了意义,我们查看代码一探究竟:
这里对输入进行了过滤,使用str_replace函数将输入中的<script>删除,这种防护机制是可以被轻松绕过的。双写,大小写混合,都可以轻松绕过它:
双写绕过
http://192.168.1.1/DVWA-master/vulnerabilities/xss_r/?name=<sc<script>ript>alert(1)</script>
大小写混合绕过
http://192.168.1.1/DVWA-master/vulnerabilities/xss_r/?name=<ScRipt>alert(1)</script>
High
我们尝试用alert来看看会不会出现弹窗,结果发现并没有:
http://192.168.1.1/DVWA-master/vulnerabilities/xss_r/?name=<script>alert(1)</script>
所以我们来打开代码。看看他进行了哪些防御,结果发现,High级别的代码同样使用黑名单过滤输入,preg_replace()函数用于正则表达式的搜索和替换,这使得双写绕过、大小写混淆绕过(正则表达式中i表示不区分大小写)不再有效:
那么<script>标签确实是被限制住了,我们没有办法继续利用这个标签检测XSS漏洞。所以这里可以更换别的标签,虽然无法使用<script>标签注入XSS代码,但是可以通过img、body等标签的事件或者iframe等标签的src注入恶意的js代码:
Img标签:
http://192.168.1.1/DVWA-master/vulnerabilities/xss_r/?name=<img src=1 onerror=alert(1)>
iframe标签
http://192.168.1.1/DVWA-master/vulnerabilities/xss_r/?name=<iframe onload=alert(1)>
存储型XSS(Stored)
Low
大致上等同于反射型,但是攻击效果远远强于反射型。
我们打开源代码(路径如下):
我们呢发现用了很多新的函数:
trim(string,charlist)函数:
函数移除字符串两侧的空白字符或其他预定义字符,预定义字符包括、\t、\n、\x0B、\r以及空格,可选参数charlist支持添加额外需要删除的字符。
mysql_real_escape_string(string,connection)函数:
函数会对字符串中的特殊符号(\x00,\n,\r,\,‘,“,\x1a)进行转义。
stripslashes(string)函数:
函数删除字符串中的反斜杠。
这些函数中并没有对输入做XSS方面的过滤与检查,且存储在数据库中,因此这里存在明显的存储型XSS漏洞。我们可以果断输入<script>标签来试图测试漏洞,然后点击Sign Guestbook(这里我们是在Message文本框中输入,Name随便输入一个):
<script>alert(1)</script>
当我们点到别的页面又回来的时候,发现竟然重新弹出了弹窗,或者再次点击Sign Guestbook,也是一样,跟反射型XSS不同,反射型XSS想弹出弹窗,每一次都需要再写一次<script>标签,而存储型XSS会把文本框的内容存储下来,这个时候我们应该明白了,为什么叫做存储型XSS而不是其他名字。我们在文本框下方也可以看到存储的记录:
既然Message文本框有XSS漏洞,那么能不能通过Name文本框检测呢,我们复制代码进去,结果发现,竟然限制了字符位数,只有十个字符:
<script>alert(1)</script>
所以我们来做个代理,用Burp Suite截取DVWA发送的数据包,修改其中的Name的字符数据,从而绕过这个字符的限制。在此之前我们得把数据都清空,前面也提到了,这是一个存储型XSS,不清空的话我们无法判断执行的是原来是数据还是新的语句,简而言之,就是控制变量。
在Name和Message里面都输入任意内容,这时在Message里面我们也不能输入<script>标签,原因当然也是控制变量,如下图所示,我们在标记的属于Name的部分,更换为<script>标签的语句:
我们更换后点击Forward,返回DVWA页面,发现有返回的对话框:
由于我们前面控制变量,所以这就说明Name文本框也可以检测XSS漏洞。
Medium
还是一样,调节难度,注意的是,点击Clear Guestbook清理存储记录:
虽然知道不大行,但是还是用<script>标签试一下,然后发现,果然没有弹窗,只是多出一条记录:
那么我们就查看代码,看看有什么防御:
相关函数说明
strip_tags() 函数:
剥去字符串中的HTML、XML以及PHP的标签,但允许使用<b>标签。
addslashes() 函数:
返回在预定义字符(单引号、双引号、反斜杠、NULL)之前添加反斜杠的字符串。
尤其可以看到的是,对message参数使用了htmlspecialchars函数进行编码,因此我们无法再通过message参数注入XSS代码,但是对于name参数,只是简单过滤了<script>字符串,仍然存在存储型的XSS。所以当然,我们放弃在Message中注入,通过Burp Suite抓包在Name中构造<script>,步骤和注意事项在Low等级已经有详细内容,我们有双写和大小写混合两种方法可供选择,这里只放出语句和截图(注意清除记录),其余不再赘述:
双写:
<sc<script>ript>alert(/xss/)</script>
大小写混合:
<Script>alert(/xss/)</script>
High
我们直接来看代码:
可以看到,message参数使用了htmlspecialchars函数进行编码,我们还是无法再通过message参数注入XSS代码,至于Name,这里使用正则表达式过滤了<script>标签,但是却忽略了img、iframe等其它危险的标签,因此name参数依旧存在存储型XSS。所以我们使用其他标签来抓包,在Name中进行注入,这里只给出标签语句和截图,其他内容不再赘述:
Img标签
<img src=1 onerror=alert(233)>
iframe标签
<iframe onload=alert(1)>