写在前面 2
知识回顾 2
XSS的定义2
XSS的危害2
XSS的产生3
如何攻击 4
深入解读XSS4
XSS分类4
XSS出现场景4
实战XSS9
攻击篇 9
防御篇 10
其他 11
写在前面
本周五为大家带来的是安全分享之XSS的进阶篇,这部分的内容是基于前2次的安全分享的基础之上的,希望通过这次分享让大家在对XSS有了一个理论层面的认识之上做一个小小的加深,或者以前迷迷糊糊的孩纸们能够通过这次从开发者角度演示XSS对XSS有一个系统的了解。
知识回顾
首先还是先回忆一下老生常谈的概念问题:
XSS的定义
看百科怎么说XSS
XSS又叫CSS(CrossSiteScript),跨站脚本攻击。它指的是恶意攻击者往Web页面里插入恶意html代码,当用户浏览该页之时,嵌入其中Web里面的html代码会被执行,从而达到恶意攻击用户的特殊目的。XSS属于被动式的攻击,因为其被动且不好利用,所以许多人常忽略其危害性。
XSS的危害
说到危害,到底有哪些呢?且看:
1.钓鱼欺骗;
2.网站挂马;
3.身份盗用;
4.盗取网站用户信息;
5.垃圾信息发送;
6.劫持用户Web行为;
7.XSS蠕虫:XSS蠕虫可以用来打广告、刷流量、挂马、恶作剧、破坏网上数据、实施DoS攻击等。
XSS的产生
说了一大堆理论,都是不怎么靠谱的东西,还是来看一下他是怎么产生的吧。
****************************************************************
[zhangyongqiao.pt@search041125htdocs]$cattest.php
<?PHP
echo"欢迎你,".$_GET['name'];
?>
[zhangyongqiao.pt@search041125htdocs]$
****************************************************************
首先在一个具有LAMP环境的机器上建立如上的一个PHP脚本,这个脚本大概的意思就是输出“欢迎你,”加上后面赋值给name属性的值。
那么我们访问一下这个页面,
【由于机器的编码问题,导致“欢迎你”这几个字是乱码,我们先无视他。】
看地址栏显示,当给name赋值时,会正常在html页面中展示。同时看到页面返回的源文件内容。
然后我们对name的值做一些改动。
出现了如图的信息,那么表示这段脚本就成功的被注入了。
我们看一下源文件的内容:
****************************************************************
欢迎你,zhangyongqiao<script>alert(1);</script>
****************************************************************
如何攻击
也许有人就要问,证明脚本注入了又会怎么样呢?
设想一下,如果黑客同学将这段脚本改成如下形式:
获取当前用户的cookies
返回给服务器,并生成相应的日志。
所作的事情不用太多,对于存在这类安全问题的网站,往往其他安全措施也不完善。那么,简单的,利用你的cookie登录网站,黑客同学得到了你的权限,你的信息也全部暴露在黑客同学的面前了。仅仅是一个普通的用户可能对网站产生的影响不会很大。试想一下,如果这个被攻击的人是管理员呢?
当然,这只是上面那么多危害的一种,别忘了我可是列出了7种危害。
深入解读XSS
XSS分类
跨站脚本一般分为两类,非持久型XSS(反射XSS)与持久型XSS(存储XSS)
非持久型的是指那些浏览器每次都要在参数中提交恶意数据才能触发的跨站脚本漏洞。前面演示的XSS漏洞属于这种类型。
与非持久型XSS相反,它是指通过提交恶意数据到存储器(比如数据库、文本文件等),Web应用程序输出的时候是从存储器中读出恶意数据输出到页面的一类跨站脚本漏洞。
XSS出现场景
接下来看一下XSS的出现场景,XSS一般的注入点会在以下四种情况。
1.输出在HTML页面
2.输出在HTML属性中
3.输出在JS代码中
4.基于DOM
下面我们对每种情况做一次实例,让大家有更直观的了解。
输出在HTML页面
首先第一种情况,输出在HTML页面中的注入,前面的唯一一个实例就是如此。
输出在HTML属性中
我们再来看第二种情况:输出在HTML属性中的:
源代码如下:
****************************************************************
[zhangyongqiao.pt@search041125htdocs]$cattest3.php
<?php
echo"<ahref=\"".$_GET['name']."\">enter</a>";
?>
[zhangyongqiao.pt@search041125htdocs]$
****************************************************************
这段代码大概的意思就是返回一个带有超链接的字段“enter”,超链接的内容需要自己赋值。我们访问一下页面,然后对这个页面做手工注入:
注入的脚本为:
http://10.232.41.125:8713/test3.php?name=test">hi</a><script>alert(1);</script><!--
返回的页面源代码如下:
****************************************************************
<ahref="test">hi</a><script>alert(1);</script><!--">enter</a>
****************************************************************
通过分析这段脚本看出,首先用下引号对属性name赋值的闭合,然后是对a标签做了一次闭合,最后再进行脚本注入就ok了。当然,这里会发现后面的脚本">enter</a>这段会遗留下来,其实是否对它做屏蔽是无关紧要的。有兴趣的孩纸可以试一下。因为关键代码已经被解释出来了,不影响注入,这里注释掉是从实战出发,为了不在页面注入的时候留下痕迹。
(别忘了,还有个enter会输出哦~)
输出在JS代码中
下面是第三种情况,输出在js中的
****************************************************************
[zhangyongqiao.pt@search041125htdocs]$cattest4.php
<?php
echo"<script>";
echo"varyourname=".$_GET['name'].";";
echo"</script>";
?>
[zhangyongqiao.pt@search041125htdocs]$
****************************************************************
这块内容的主要是UED的孩纸们在写JS的时候会遇到,当对name这个变量做赋值的时候,就会存在跨站,
注入脚本如下:
http://10.232.41.125:8713/test4.php?name="a";alert(1);</script><!--
同上面的2个例子一样,这里对"varyourname=".$_GET['name'].";";这段代码做了各种闭合,得到的html源文件如下:
<script>varyourname="a";alert(1);</script><!--;</script>
首先是闭合了赋值语句,然后输出注入脚本,最后注释掉了分号。当然,最后一个闭合js的标签是不会被HTML解释出来的。
以上的三种注入虽然出现的场景不一样,但是仔细研究就会发现重现的方式与HTML的源码回显等等都是类似的,最后一种出现场景比较特殊,待我们细细来看:
基于DOM
引用一段师姐的话:
DOM是DocumentObjectModel的缩写。据W3CDOM规范,DOM是一种与浏览器,平台,语言无关的接口,使得你可以访问页面其他的标准组件。
把DOM认为是JavaScript输出的页面,基于DOM的跨站脚本漏洞就是出现在JavaScript代码中的漏洞。请注意,之前的3种输出是属于Web应用程序(CGI程序)代码中的漏洞。
然后我们再来看实例:
****************************************************************
[zhangyongqiao.pt@search041125htdocs]$cattest5.php
<script>
document.write(window.location.search);
</script>
[zhangyongqiao.pt@search041125htdocs]$
****************************************************************
先解释一下这段代码,window.location.search,这个函数的意思就是返回url中非文件部分的内容,也就是url从问号开始之后的所有内容。
这里解释一下url中的第一个问号的作用:
Get请求有如下特性:它会将数据添加到URL中,通过这种方式传递到服务器,通常利用一个问号?代表URL地址的结尾与数据参数的开端,后面的参数每一个数据参数以“名称=值”的形式出现,参数与参数之间利用一个连接符&来区分。
那么我们就可以邪恶的利用这个函数对页面进行注入了。我们看到如下效果:
但是,神奇的是,我们查看页面的源代码
****************************************************************
<script>
document.write(window.location.search);
</script>
****************************************************************
页面里面并没有回显那些被注入的脚本,因此,这个地方我们在开发的时候需要重点关注,对于window.location.search的理解应该是页面中window。location对象中封装的一个search属性。只能深入到这里了。具体的还是要找一个专业写JS的孩纸来剖析。
POST请求的XSS
讲了这么多的xss的注入场景,这些场景有一个共同点,就是他们都属于GET方式的请求,那么试问POST的请求就不能进行注入吗?
当然可以。
在此之前,还是要重申一下get与post的区别。这里直接借用网上比较犀利的一段解释:
1.get是从服务器上获取数据,post是向服务器传送数据。
2.get是把参数数据队列加到提交表单的ACTION属性所指的URL中,值和表单内各个字段一一对应,在URL中可以看到。post是通过HTTPpost机制,将表单内各个字段与其内容放置在HTMLHEADER内一起传送到ACTION属性所指的URL地址。用户看不到这个过程。
3.对于get方式,服务器端用Request.QueryString获取变量的值,对于post方式,服务器端用Request.Form获取提交的数据。
4.get传送的数据量较小,不能大于2KB。post传送的数据量较大,一般被默认为不受限制。但理论上,IIS4中最大量为80KB,IIS5中为100KB。
5.get安全性非常低,post安全性较高。但是执行效率却比Post方法好。
建议:
1、get方式的安全性较Post方式要差些,包含机密信息的话,建议用Post数据提交方式;
2、在做数据查询时,建议用Get方式;而在做数据添加、修改或删除时,建议用Post方式;
这里基本上已经说的非常之全了。那么对于稍微安全一点的请求方式,我们怎么来进行手工注入呢?惯例是先看脚本:
****************************************************************
[zhangyongqiao.pt@search041125htdocs]$catindex.php
<?php
echo"sa,".$_POST['name'];
?>
[zhangyongqiao.pt@search041125htdocs]$
****************************************************************
对比一下最开始的那段脚本,只是简单的把get请求换成了post请求,怎么注入呢?别急,咱们有工具。这里推荐一个强有力的模拟post请求发送的firefox插件hackbar,效果如下:
我们所要做的就是在loadurl的位置写上访问的地址,然后在postdata的位置写上我们要传送出去的数据,最后点击execute就可以了。最后得到的效果就和get的相同了。
得到页面源代码如下:
sa,<script>alert(1)</script>
有人要问,那我如何去获取这些post请求对应的参数呢?在chrom和firefox中都带有请求截获的工具,firefox的httpfox和firebug都有这个功能,而chrom的控制台也有这方面的功能。
实战XSS
攻击篇
我们从开发者写代码的角度对XSS做了一个简单的剖析,那么如果真的遇到XSS漏洞了,我们怎么去寻找和注入呢?
接下来我们就来简单的演示一下如何去寻找一个漏洞和“攻击”一个网站。(这里只做测试,不做恶意破坏。)
先来一个准备工作,如此庞大的互联网,如果要对网站做手工检测,当然整个人直接就崩溃了,所以我们用一个轻量级可随身携带的安全扫描工具webcruiser,利用这个工具找到网站的漏洞比起手动探索性测试效率高多了。具体工具的使用方法大家还是看说明书吧,在这里不多做介绍,首先找到一个目标网站(出于道德,这里还是不把具体的网站给写出来了)
1.首先扫描出那些安全漏洞。
然后我们复制含有可注入点的url
当我们访问这个网页的时候,发现网页上有一个可以输出的编辑框
在编辑框中输出一些有区分度的字符串,提交搜查请求,
我们得到一个返回结果页,这时候我们查看源文件,在源文件中搜索aaaaaa字符串,
这时候我们在页面中得到了如下返回情况
<tdwidth="180"align="left"><inputtype="text"name="key"id="key"value="aaaaaa"size="26"οnfοcus="this.select();"></td>
这下大家应该都明白了吧。这种场景就是存在在html属性的xss漏洞。我们需要做的就是在字符串后面将input标签闭合,然后写入脚本即可。马上来动手试试吧。
修改请求串如下:aaaaaa"/><script>alert(1)</script>
防御篇
学习安全当然不是为了去攻击网站了,我们是好孩纸啊,那么我们来看一下如何预防这类攻击呢?太简单了,只要对脚本做转译就可以啦。
我们拿最后的那个post的例子来看,修改脚本如下:
****************************************************************
[zhangyongqiao.pt@search041125htdocs]$catindex.php
<?php
$n="sa,".$_POST['name'];
echohtmlspecialchars($n);
?>
[zhangyongqiao.pt@search041125htdocs]$
****************************************************************
我们利用htmlspecialchars对在html中输出的脚本做转译,当然当输出的是url的时候,php还提供了类似的函数。
然后我们再进行一次XSS注入:
如此脚本已经完全被转译,同时能够正常输出啦。也就是说页面没有翻译这些脚本,那么函数到底做了什么呢?我们看一下html源文件:
sa,<script>alert(1)</script>
好了,这下知道了吧,函数仅仅是将特殊符号做了转译。
其他
最后的最后,在写上面这些脚本做尝试的时候,需要对自己PHP的配置文件做一个小修改:
magic_quotes_gpc:这是在PHP中一个特殊的函数魔术函数,它在引用的过程中只有在传递$_GET,$_POST,$_COOKIE时才会发生作用。magic_quotes_gpc=on将单引号转换为\’,所以大家在编码的时候记得配置一下。不然第三个脚本是不能重现的。其他几个脚本不会有影响。
【有人说那么这不就是一个php安全过滤操作的一个函数吗?当然是,但是由于这个函数的很多局限性,如在对数据库写操作的时候,对字符串做一些转译,导致很多类似操作都变的很麻烦,所以一般的开发人员都会将这个值给off了,然后自己重写一个类似的函数】