【51CTO.COM 独家特稿】跨站脚本的名称源自于这样一个事实,即一个Web站点(或者人)可以把他们的选择的代码越过安全边界线注射到另一个不同的、有漏洞的Web 站点中。当这些注入的代码作为目标站点的代码在受害者的浏览器中执行时,攻击者就能窃取相应的敏感数据,并强迫用户做一些用户非本意的事情。
在本文的上篇中,我们详细介绍了当前Web应用所采取的安全措施,如同源策略、cookie安全模型以及Flash的安全模型;而本文将介绍跨站脚本漏洞利用的过程,并对HTML注入进行深入分析。
一、跨站脚本漏洞利用的过程
现在,您已经熟悉了浏览器中的各种安全技术,下面我们开始设法利用XSS规避这些安全技术。XSS的主要目标是通过把攻击者选择的JavaScript、VBScript或者其它为浏览器所接受的脚本语言注入到(放进)某些Web应用程序之中。只要攻击者可以将脚本植入有弱点的Web应用程序中的任何地方,浏览器就会认为这个脚本是来自该有弱点的Web应用程序,而非非出自攻击者之手。
这样的话,该脚本就能够在这个有弱点的Web应用程序的域中运行了,并能进行下列活动:有权读取那个有弱点的Web应用程序使用的Cookie;能够看到该有弱点的Web应用程序提供的页面的内容,甚至能将它们发送给黑客;改变有弱点的Web应用程序的外观;回调运行有弱点的Web应用程序的服务器。
大体上,跨站点脚本攻击可以分为三步进行:
1.HTML注入。我们将介绍把脚本注入到Web应用程序的各种可能的方法。所有HTML注入范例只是注入一个JavaScript弹出式的警告框:a_lert(1)。
2.做坏事。如果您觉得警告框还不够刺激,我们将讨论当受害者点击了一个被注入了HTML代码的页面链接时攻击者能作的各种的恶意事情。
3.诱捕受害者。我们论述如何强制或者诱使受害者执行恶意JavaScript代码。
一、HTML注入简介
将HTML和(更为重要的)脚本代码注入Web应用程序的方法简直太多了。如果某个Web应用程序的HTTP响应中“照搬”了在HTTP请求中输入的内容,例如尖括号、圆括号、句号、等号等,那么说明这个Web应用程序和域具有HTML注入漏洞,并且该漏洞十有八九可以用于XSS。
本节将为读者介绍最常见的HTML注入方法,但是无法包括所有方法,因为这些方法是在太多了。对于大多数小型至中型的网站来说,这些技术很可能仍然奏效。只要有耐心,那么您或许也能够使用其中的一种技术成功应用于一个大型Web站点。
下面我们将分门别类的介绍各种注入方法。
二、传统的反射式和存储式HTML注入
传统的XSS攻击是一种反射式的HTML注入攻击,借此,一个Web应用程序接受在HTTP请求中的用户输入。该Web应用程序会返回一个HTTP响应,其主体中将包含原封不动的用户输入。如果该服务器的响应跟用户的原始输入完全一致,那么这些用户输入就会被浏览器当作有效的HTML、VBScript或者JavaScript进行解释。考虑下列的服务器端的PHP代码:
< html > < body > < ?php if (isset($_GET{'UserInput'})){ $out = '您输入的内容为: "' . $_GET{'UserInput'} . '".'; } else { $out = '< form method=”GET”>请在此输入内容: '; $out .= '< input name="UserInput" size="50" >'; $out .= '< input type="submit" >'; $out .= '< /form >'; } print $out; ? > < /body > < /html > |
图1展示了这段代码放置到http://publicpages.daxue.edu/~someuser/MyPhp.php上后,客户端看到的页面内容。
图1 一个简单的PHP脚本,用以接收用户输入(MyPhp.php) |
当用户点击“提交查询”按钮时,就会生成下列GET请求:
http://public-pages.daxue.edu/~someuser/MyPhp.php?input=hahaha
这个PHP应用程序看到用户输入的“hahaha”后,将响应一个页面,如图2所示。
图2 用户输入“hahaha”后MyPhp.php回复的响应 |
下面显示的是图2中看到的页面的HTML 源代码,为醒目起见用户输入的内容这里以蓝色字体显示。
您输入的内容为: "hahaha".
#p#
注意,实际上这里用户可以输入任何东西,例如〈 script 〉 a_lert( 1 )〈 / script 〉、〈 body onload = a_lert( 1 ) 〉、〈 img src = x onerror = a_lert( 1 ) 〉 或别的东西来把JavaScript代码注入到该页面。如果输入 的话,将向服务器发送下列GET请求:
http://publicpages.daxue.edu/~someuser/MyPhp.php?input=
如前所述,这个PHP应用程序只是把用户输入放到返回的响应页面中。这时候浏览器会把这些用户输入的内容当作JavaScript指令,同时认为该脚本来自服务器,这可真是应了那句老话“拿着鸡毛当令箭”了,所以浏览器就会执行这些JavaScript代码。图3展示了用户看到的样子。
图3 用户输入“ ”后MyPhp.php回复的响应 |
上图中显示的页面的源代码如下所示,其中用户输入用蓝色字体表示。
您输入的内容为: " ".
这是将 注入http://public-pages.daxue.edu/~someuser/MyPhp.php得到的结果。这个例子是一种典型的反射式的HTML注入,因为用户在HTTP请求中发送JavaScript代码,同时Web应用程序立即响应(反射回)一个完全相同的JavaScript代码。只要用户单击了下列链接,这个脚本就会执行:
http://publicpages.daxue.edu/~someuser/MyPhp.php?input=
从攻击者的角度来看,利用注入的ML代码让恶意的web页面完成单击或者指定次数的点击是非常重要的。假设前面的PHP应用程序只接受POST请求,而不接受GET,如下所示:
< html >
< body >
< ?php
if (isset($_POST{'UserInput'})){
$out = '您输入的内容为: "' . $_POST{'UserInput'} . '".';
} else {
$out = '< form method="POST" >请在此输入内容: ';
$out .= '< input name="UserInput" size="50" >';
$out .= '< input type="submit" >';
$out .= '< /form >';
}
print $out;
? >
< /body >
< /html >
在这种情况下,攻击者无法像上面的GET请求那样直接通过诱骗受害者点击一个链接来注入HTML代码;现在,他们必须采取一些额外的步骤。为此,攻击者可以创建下列HTML页面:
< html >
< body >
< form name="evilForm" method="POST ction="http://publicpages.
daxue.edu/~someuser/MyPhp.php">
< input type="hidden" name="input" value="〈 script 〉a_lert ( 1 )〈 / script 〉" 〉
< script >
document.evilForm.submit()
< /script >
< /body >
< /html >
document.evilForm.submit()
document.evilForm.submit()
document.evilForm.submit()
当用户单击了指向上述HTML页面的链接时,就会对http://public-pages.daxue.edu/~someuser/MyPhp.php进行HTML注入。当然,攻击者也能利用HTML注入干别的坏事,而不仅仅象征性地调用一个JavaScript的弹出窗口。“第二步:做坏事”部分将解释攻击者除了弹出一个窗口外还能做些什么。
存储式HTML注入跟反射式HTML注入非常相似,唯一区别在于攻击者将脚本植入Web应用程序后,这些脚本会被Web应用程序存储到一个可以检索的地方。例如,对于允许用户张贴和阅读消息的网络论坛,攻击者可以在张贴消息时注入HTML代码,然后其它用户阅读这则含有脚本的消息时,其中的脚本就会执行。
三、定位存储式和反射式HTML注入点
为了寻找存储式和反射式HTML注入点,可以尝试在所有表单输入以及GET或者POST请求的所有参数中注入脚本。我们要假设参数/值对中的值都可能有漏洞。甚至尝试在新生成的参数中注入HTML代码,如下所示:
〈 script 〉 a_lert ( ' parameter ' )= 不起作用,因为这些测试字符串并不出现在响应的HTML主体区。举例来说,假如向http://search.engine.com/search?p= 发送的这个请求返回的响应中,其预填充表单字段内是我们的HTML注入字符串,如: