跨站脚本漏洞(xss)
Cross-Site Scripting 简称为“CSS”,为避免与前端叠成样式表的缩写"CSS"冲突,故又称XSS。一般XSS可以分为如下几种常见类型:
1.反射性XSS;
2.存储型XSS;
3.DOM型XSS;
XSS漏洞一直被评估为web漏洞中危害较大的漏洞,在OWASP TOP10的排名中一直属于前三的江湖地位。
XSS是一种发生在前端浏览器端的漏洞,所以其危害的对象也是前端用户。
形成XSS漏洞的主要原因是程序对输入和输出没有做合适的处理,导致“精心构造”的字符输出在前端时被浏览器当作有效代码解析执行从而产生危害。
因此在XSS漏洞的防范上,一般会采用“对输入进行过滤”和“输出进行转义”的方式进行处理:
- 输入过滤:对输入进行过滤,不允许可能导致XSS攻击的字符输入;
- 输出转义:根据输出点的位置对输出到前端的内容进行适当转义;
XSS漏洞可以用来进行钓鱼攻击,前端js挖矿,用户cookie获取。甚至可以结合浏览器自身的漏洞对主机进行远程控制等。
危害:存储型>反射型>DOM型
-
反射型
交互的数据一般不会被存放在数据库里,一次性,所见即所得,一般出现在查询类页面等
-
存储型
交互的数据会被存放在数据库里面,永久性存储,一般出现在留言板,注册等页面。
-
DOM型
不与后台服务器产生数据交互,是一种通过DOM操作前端代码输出的时候产生的问题,一次性也属于反射型。
跨站脚本漏洞测试流程
- 在目标站点上找到输入点,比如查询接口,留言板等;
- 输入一组“特殊字符+唯一识别字符”,点击提交后,查看返回的源码,是否有做对应的处理;
- 通过搜索定位到唯一字符,结合唯一字符前后语法确认是否可以构造执行js的条件(构造闭合);
- 提交构造的脚本代码(以及各种绕过姿势),看是否可以成功执行,如果成功执行则说明存在XSS漏洞;
TIPS:
- 一般查询接口容易出现反射型XSS,留言板容易出现存储型XSS;
- 由于后台可能存在过滤措施,构造的script可能会被过滤掉,而无法生效,或者环境限制了执行(浏览器);
- 通过变化不同的script,尝试绕过后台过滤机制;
实验
实验环境:Firefox,pikachu
测试目标:Pikachu——XSS
测试工具:firefox+浏览器开发者工具
从一个反射型的XSS(get)弹窗开始认识XSS漏洞
我们首先随便输入,比如‘ “<>6666返回的还是‘ “<>6666
查看网页源码,发现他是放在一个
标签里面的
确认它可以它可以执行js,我们开始输入。输入发现有字数限制;这种情况是很常见的,非常好处理,我们打开开发者工具,发现这个输入框限制20个字符,我们直接将其改为2000,然后继续输入
输入完成,我们提交,发现我们刚刚提交的JavaScript代码被执行了。
这就是一个反射型的XSS。反射型的XSS从前端的输入到后端的输出整个过程,后端是对他没有进行存储的。我们重新刷新这个页面,刚刚输入的代码就没了。
反射型跨站脚本漏洞之get&post
GET和POST典型区别:
GET是以url方式提交数据;POST是以表单方式在请求体里面提交;
GET方式的XSS漏洞更加容易被利用,一般利用的方式是将带有跨站脚本的URL伪装后发送给目标,而POST方式由于是以表单方式提交,无法直接使用URL方式进行攻击。
存储型XSS
存储型XSS漏洞跟反射型XSS形成的原因一样,不同的是存储型XSS下攻击者可以将脚本注入到后台存储起来,构成更加持久的危害,因此存储型XSS也称”永久型“XSS。
我们还是先测试一下
查看源码
我们可以看到它还是放在了一个p标签里,我们还是输入一个payload测试一下啊
我们输入这样一个脚本点提交。提交后的流程就是,我们从前端把这样的一串字符提交给后台,后台把它存下来以后,又在重新在前端页面刷新出来。
存储型和反射型的差别在于我们每次去刷新页面还是会弹出这个窗口,因为我们刚才的留言已经保存在数据库里了。我们每次打开网页,都会从数据库中把这个留言加载出来,触发这个脚本的运行。
显而易见,存储型的XSS危害性更大。
DOM型XSS
学习DOM型XSS之前,我们先搞清楚什么是DOM:
通过JavaScript,可以重构整个HTML文档。您可以添加,移除,改变或重排页面上的项目。要改变页面的某个东西,JavaScript就需要获得对HTML文档中所有元素进行访问的入口。这个入口,联同轨文档中所有元素进行添加,移动,改变或移除的方法和属性,都是通过文档对象模型来获得的(DOM)
所以你可以把DOM理解为一个一个访问HTML的标准编程接口。
HTML DOM 是 HTML 的标准对象模型和编程接口。它定义了:
- 作为对象的 HTML 元素
- 所有 HTML 元素的属性
- 访问所有 HTML 元素的方法
- 所有 HTML 元素的事件
换言之:HTML DOM 是关于如何获取、更改、添加或删除 HTML 元素的标准。
我们随便输入看一下:
然后下面出现what do you see?我们查看源码看一下进行了什么操作
<a href='"+str+"'>what do you see?</a>
这句就是我们的输入点,我们可以对其进行重新构思,比如
<a href='#' onclick="alert(111)">'>what do you see?</a>
那么,**#’ οnclick=“alert(111)”>**这就是我们要输入的语句,我们把它复制然后粘贴进去,提交
这是我们再点 ’>what do you see?应该就会弹出窗口了
DOM型XSS漏洞是由于前端的输入被DOM获取了,然后又被DOM输出了,不经过后台去进行交互。
还有一种DOM型XSS漏洞,DOM型xss-x
我们还是随便输入,然后提交,点击第一句话然后出现了第二句话 ”就让往事都随风,都随风吧“
我们还是看一下源码
这种和上一个的闭合是一样的,我们还是用刚才的那句#’ οnclick=“alert(111)”>
XSS漏洞测试:(cookie获取和钓鱼攻击演示)
- XSS漏洞测试:cookie的窃取和利用
- XSS漏洞测试:钓鱼攻击
- XSS漏洞测试:XSS获取键盘记录
GET型XSS利用:cookie获取
POST型XSS利用:cookie获取
接下来我们看下让用户访问的,伪造表单自动提交页面(在Pikachu中的pkxss下的xcookie下的post.html)
并修改漏洞页面为自己Pikachu靶机的ip,pkxss后台为自己的ip。为了方便也可以,将漏洞页面和pkxss搭建在一台主机上。
修改完后记得先去重启下phpstudy服务(如何用的别的软件,都一样,重启下环境服务就行)
修改完后,复制到,其他主机站点(www)下。
模拟的恶意站点:
http://192.168.43.118/post.html
当有用户点这个链接时,,就会实现我们的攻击目的。
XSS钓鱼
在一个存在xss漏洞上的页面上嵌入一个链接请求,请求会返回一个Basic认证的一个头部。若用户信息安全意识不够,输入了用户和密码,那么这些会被发送到pkxss后台
我们只需要在这个存储型的页面上去,嵌入一个能够访问我们后台的返回Basic认证的标签就行,
这里可以用a标签、img、< script >
查看下fish.php源码,其中location(重定向)换成自己的ip
和我们之前获取cookie一样,钓鱼的后台也有个接口(xfish.php),获取远程的数据,通过get方式去获取账号密码存到库里面。
返回输入框,输入(其实里面没有什么内容,只是用src调用我们的远端php文件)
输入了账号和密码,去pkxss后台可查看
XSS获取键盘记录
先了解下什么是跨域:
跨域—同源策略:
为了安全考虑,所有的浏览器都约定了“同源策略”,同源策略规定,两个不同域名之间不能使用JS进行相互操作。比如:x.com域名下的JavaScript并不能操作y.com域下的对象。
如果想要跨域操作,则需要管理员进行特殊的配置。比如通过:head(“Access-Control-Allow-Origin:x.com”)指定。
Tips:下面这些标签跨域加载资源(资源类型是有限制的)是不受同源策略限制的。
这一策略就违反啦同源策略,(ajax)
打开浏览器控制台,打开网络;随着键盘的输入,会显示错误。(当然这时,pkxss后台也是没有键盘记录的)
由于127.0.0.1/pkxss/rkeypress/rkserver.php是攻击者自己搭建的,攻击者可以允许所有的人跨域请求他,因为这个网站是攻击者自己的,为了实现攻击目的,可以rkserver.php把里面的Access-Control允许所有人访问。
这样的话,存在xss漏洞的页面调js跨越请求时候就可以正常访问啦。
改完,在页面输入后,pkxss后台会有键盘记录。
XSS盲打
什么是XSS盲打?
也就是说只有后台会看到前端输入的内容,从前端无法判断是否存在XSS,怎么办?
不管三七二十一,往里面插XSS代码,然后等待,可能会有惊喜!
由于是后端,可能安全考虑不太严格。当管理员登陆时,就会被X!
我们可以写个弹窗
这种弹窗是不会在我们前端显示的,管理员登陆后台,后台的界面会把我们输入的内容输出,后台的管理员会被X到。这种场景被称为xss的盲打
点击提示,模拟下后台登陆,输入账号admin 密码123456
对攻击者来说这就是一种尝试的行为。也说明了XSS漏洞的本质就是XSS的存储性。
XSS绕过
过滤-转换
0、前端限制绕过,直接抓包重放,或者修改html前端代码
1、大小写,比如:
2、拼凑:<scri>pt>
3、使用注释进行干扰:<scri<!- -test- ->pt>alert(111)</sc<!- -test- ->ript>
过滤-编码
核心思路:后台过滤了特殊字符,比如
在使用编码时需要注意编码在输出点是否会被正常识别和翻译!
例子1:
<img src=x onerror="alert('xss')"将alert('xss')进行URL编码,可以执行吗
<img src=x onerror="alert%28%27xss%27%29"/>
并不会执行,why?因为这些属性标签并不会正常解析这些编码
例子2:使用事件属性onxxx();
<img src=x onerror="alert('xss')"/>可以把alert('xss')进行html编码
<img src=x onerror="alert('xss')"/>
<img src=x onmouseover="alert('xss')"/>
可以执行,注意:事件标签里面并不会执行<script></script>标签里面的代码
XSS绕过的姿势有很多,取决于你的思路和对前端技术的掌握程度。XSS的绕过非常灵活,并没有固定的方法,所以需要大家平时多尝试多积累。
XSS之过滤
输入XSS语句
被过滤的只剩下">"了
查看靶场源代码,我们可以看到我们输入的script标签被干掉了,说明后台对我们输入的script标签进行了过滤。
尝试大小写绕过:
成功,说明他后台只是对小写的script进行了过滤
我们再回到源码,看一下它是怎么过滤的
这里会用replace这个方法使用正则对我们输入的message进行替换为空,也就是过滤掉。正则是区分大小写的。因为他这里过滤的是script标签,我们可以使用其他标签来代替script标签,比如img标签:
<img src=x οnerrοr=alert(111) /
关于htmlspecialchars()函数
htmlspecialchars()函数把预定义的字符转换为HTML实体。
预定义的字符是:
&(和号)成为&
“(双引号成为"
‘(单引号)成为'
<(小于)成为<
>(大于)成为>
可用的引号类型:
ENT_COMPAT -默认。仅编码双引号。
ENT_QUOTES -编码双引号和单引号。
ENT_NOQUOTES -不编码任何引导。
我们可以看到单引号并没有被处理,所以我们可以利用这一点
提交之后,我们点击一下那条输入的记录就会弹出我们的弹窗了。这个就是它后端处理的一个疏忽:
htmlspecialchars()默认是不对单引号(’)做处理的。
XSS常见防范措施
总的原则:输入坐过滤,输出做转义
- 过滤:根据一业务需求进行过滤,比如输入点要求输入手机号,则只允许输入手机号格式的数字。
- 转义:所有输出到前端的数据都根据输出点进行转义,比如输出到html中进行html实体转义,输入到JS里面的进行JS转义。
我们通过pikachu靶场里的两关来演示一下:
-
XSS之href输出
这里使用了htmlspecialchars()函数和ENT_QUOTES,对单引号,双引号,尖括号都进行了转义是不是就没有漏洞了呢。我们可以看到注释里写着提示:可以使用JavaScript协议来执行js,我们来尝试一下
我们回去看一下源码
我们可以看到这个payload在我们的a标签href里面。那么我们应该如何防范呢?
- href里面一般是链接或者超链接,所以我们可以规定href里面只允许http,https开头的协议才允许输出
- 其次在进行htmlspecialchars处理
我们来看下一个:XSS之js输出
我们先随便输入几个1,去看一下源码
我们可以看到它的输入点和之前的不一样,它被放在了js里面,然后再对这个变量进行判断,再决定输出。
它是拿我们输入的和tmac去作比较,那么我们去尝试输入一下tmac看看会有什么反应;
是一张图片,我们可以在这里去构造一个闭合
<script> $ms='x'</script><script>alert('xss')</script>; //主要是把前面的script闭合掉,然后插入我们的script if($ms.length != 0){ if($ms == 'tmac'){ $('#fromjs').text('tmac确实厉害,看那小眼神..') }else { // alert($ms); $('#fromjs').text('无论如何不要放弃心中所爱..') } } </script>
然后我们把这段我们写好的闭合x’输入进去
我们再来看一下源码:
这里讲输入动态的生成到了js中,形成xss
javascript里面是不会对tag和字符实体进行解释的,所以需要进行js转义讲这个例子主要是为了明白输出点在js中的xss问题,应该怎么修?
这里如果进行html的实体编码,虽然可以解决XSS的问题,但是实体编码后的内容,在JS里面不会进行翻译,这样会导致前端的功能无法使用。
所以在JS的输出点应该使用\对特殊字符进行转义
我们写好的闭合x’输入进去
我们再来看一下源码:
[外链图片转存中…(img-odPqEFaY-1670820632964)]
这里讲输入动态的生成到了js中,形成xss
javascript里面是不会对tag和字符实体进行解释的,所以需要进行js转义
讲这个例子主要是为了明白输出点在js中的xss问题,应该怎么修?
这里如果进行html的实体编码,虽然可以解决XSS的问题,但是实体编码后的内容,在JS里面不会进行翻译,这样会导致前端的功能无法使用。
所以在JS的输出点应该使用\对特殊字符进行转义