0

0

一次存储型XSS的攻防实战

王林

王林

发布时间:2019-12-03 17:42:52

|

4083人浏览过

|

来源于freebuf

转载

一次存储型XSS的攻防实战

什么是存储型xss

它是通过对网页注入可执行代码且成功地被浏览器执行,达到攻击的目的,一般是注入一段javascript脚本。在测试过程中,我们一般是使用:

通过这段js代码,弹个框来证明存在xss漏洞。那么,可能新手就会问了,弹个框有什么用呢?

其实,弹框只是为了证明存在此漏洞。而此漏洞的利用方式由很多种。

比如,你可以使用xss平台:

0f29abcb0ef8b6631c32c75d18abdd7.png

写入一段平台生成的xss脚本:

当某人进入带有这个脚本的页面时,js脚本会获取他的cookie并发往xss平台。

你只需要登录xss平台等待即可,拿到cookie后,可以不需要密码登录他的账号。

注意:本文的重点是一步一步以黑客的角度进行xss攻击,再讨论如何站在开发者的角度去一步一步防御xss攻击。所以我会在本文中以开发的身份修正后端代码,再以黑客的身份进行前端页面的xss攻击,这一点需要注意哦。

对于存储型xss漏洞的表现形式,比较经典的是留言板。但是我们都是遵纪守法的好同学,不能对外面的网站进行测试,所以就花半个小时自己手撸一个留言板咯。

首先,应该有前端展示的页面Message_Board.php和后端存储数据的页面addMessage.php

dd340fe4f0d84836614e548b0430943.png

前端代码不是本文重点(感兴趣的可以自行查看前端代码),我们重点关注后端代码addMessage.php:

可以看到,我们对传入的四个参数完全没有处理,而是直接存入数据库中。

所以,只要我们这样输入:

eccc01dfd6e78c932ded3b7bbd82c15.png

提交之后,系统会自动刷新页面出现弹框:

e0df2cc1a008b2baa6e2a9286eb03d1.png

点击确定后,你会发现留言内容和留言者的部分都为空。

8cbf337e184fb5c36f922a1ce06d6b2.png

这是因为js脚本已经被解析了,这时我们按F12,打开浏览器的开发者工具,发现了js脚本。

8.jpg

那么,问题来了。

毕竟我们还有另外一个身份,开发者该如何防御呢?

0×00、来个最简单的,只修改前端代码

在input标签里面加上maxlength属性

至于原理嘛,就是因为js脚本的形式为长度为17,所以只要我们在前端对长度进行限制,就可以阻止黑客进行xss攻击了。

可是!开发可没这么好做!

我们是想做开发的黑客,所以还得自己搞自己。

作为攻击者,我们同样可以修改前端代码,具体的操作是使用浏览器的F12(开发者工具)

9.jpg

可以看到,我们可以直接进行长度的修改。

另外,还可以用抓包的方法,在包里面直接写,也是不受长度限制的。

0×01、对关键字script进行过滤

作为开发者,你很容易发现,要想进行xss攻击,必须插入一段js脚本,而js脚本的特征是很明显的,脚本中包含script关键字,那么我们只需要进行script过滤即可。

回到之前的代码。

为方便说明,我只取nickname参数,其实传入的四个参数需要做同样的处理。

$nickname = str_replace("script", "", @$_POST['nickname']);//昵称

上面这个str_replace()函数的意思是把script替换为空。

可以看到,script被替换为空,弹框失败。

10.jpg

那么黑客该如何继续进行攻击呢?

答案是:大小写绕过

5ab06447fe511961dfb712752a6b2a5.png

因为js是不区分大小写的,所以我们的大小写不影响脚本的执行。

成功弹框!

aa626e7887d96823133082d89bf6299.png

0×02、使用str_ireplace()函数进行不区分大小写地过滤script关键字

作为一名优秀的开发,发现了问题当然要及时改正,不区分大小写不就行了嘛。

后端代码修正如下:

$nickname = str_ireplace("script", "", @$_POST['nickname']);//昵称

str_ireplace()函数类似于上面的str_replace(),但是它不区分大小写。

那么,黑客该如何绕过?

PaperFake
PaperFake

AI写论文

下载

答案是:双写script

alert(1)

d13fc9cca642e466de8a5946df0e9a0.png

原理就是str_ireplace()函数只找出了中间的script关键字,前面的S和后面的cript组合在一起,构成了新的Script关键字。

弹框成功!

b2c80a7f5749ddbbbcb405efc494cc0.png

0×03、使用preg_replace()函数进行正则表达式过滤script关键字

$nickname = preg_replace( "/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i", "", @$_POST['nickname']);//昵称

显然,弹框失败。

11.jpg

攻击者如何再一次绕过?

答案是:用img标签的oneerror属性

一次存储型XSS的攻防实战

0×04、过滤alert关键字

看到这里,不知道你烦了没有,以开发的角度来讲,我都有点烦。大黑阔你不是喜欢弹窗么?我过滤alert关键字看你怎么弹!

$nickname = preg_replace( "/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i", "", @$_POST['nickname']);//昵称
$nickname = preg_replace( "(.*)a(.*)l(.*)e(.*)r(.*)t/i", "", $nickname);//昵称

那么,攻击者该怎么办呢?

答案是:编码绕过

a

当点击页面上的超链接时,会弹框。

12.jpg

但是为什么呢?

这种编码方式为字符编码

字符编码:十进制、十六进制ASCII码或unicode 字符编码,样式为“数值;”, 例如“j”可以编码为“j”或“j ”

上述代码解码之后如下:

a

你能明显感觉到限制:由于使用到了a标签,所以只有点击时,才会弹框。

作为一个大黑阔,我们当然是不满意的,能不能让所有进入这个页面的人都弹框?

当然可以了:用iframe标签编码