跨站脚本攻击深入解析:详解漏洞利用过程

日期: 2009-03-15 作者:康凯 来源:TechTarget中国 英文

  跨站脚本的名称源自于这样一个事实,即一个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上后,客户端看到的页面内容。

简单的PHP脚本.gif


图1 一个简单的PHP脚本,用以接收用户输入(MyPhp.php)

  当用户点击“提交查询”按钮时,就会生成下列GET请求:

http://public-pages.daxue.edu/~someuser/MyPhp.php?input=hahaha

  这个PHP应用程序看到用户输入的“hahaha”后,将响应一个页面,如图2所示。

2 MyPhp.php回复的响应


图2 用户输入“hahaha”后MyPhp.php回复的响应

  下面显示的是图2中看到的页面的HTML 源代码,为醒目起见用户输入的内容这里以蓝色字体显示。

  您输入的内容为: “hahaha”.

  注意,实际上这里用户可以输入任何东西,例如〈 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回复的响应


  图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 >

  当用户单击了指向上述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注入字符串,如:

  遗憾的是,脚本标签会被作为用于表单输入字段的字符串,所以无法执行。相反,尝试http://search.engine.com/search?p=”> 的话,会得到如下所示的HTML应答:

〈 form input=”text” name=”p” value=”〈 ,那么保不住攻击者可以注入下列内容:

〈 /title 〉〈script 〉 a_lert( 1 ) 〈 /script 〉

  这样一来就摆脱了title标签。USERINPUT3被放在一个式样标签中,任何人都可以在IE中设置USERINPUT3成下面的样子:

black; background: url( ‘ javascript:a_lert( 1 ) ‘ );

  于是他就能够在Firefox使用它了:

1: expression( a_lert( 1 ) )

  同样的,有时候用户输入会作为其它的标签的一部分出现在式样参数中,如下所示:

  如果您可以将USERINPUT3设为下面的值,那么就能在IE中运行JavaScript了:

javascript : a_lert(1)

  或者对于Visual Basic爱好者,可以这样使用:

vbscript:MsgBox(1)

  Firefox不接受带有JavaScript:协议处理程序的background:url()。然而,Firefox允许JavaScript作为表达式来执行,在Firefox中将USERINPUT3A设为下列值:

); 1:expression(a_lert(1)

USERINPUT4可以直接利用,只要将USERPINUT4设为:

“;a_lert(1);

  USERINPUT5被深深嵌入到JavaScript内部。为了插入(确保会执行的)a_lert(1)函数,您必须把a_lert(1)放到所有代码块之外,并保证JavaScript代码的前前后后都是合法的,如下所示:

‘)){}a_lert(1);if(0)

  A_lert(1)之前的文本完成了原先的if语句,因此能确保a_lert(1)函数总是被执行。a_lert(1)之后的文本创建了一个if语句用于剩余代码块,所以脚本标签之间的全部代码都是合法的JavaScript代码。如果不这样,JavaScript就会因为语法错误而无法解释执行。

  您可以使用一些诡计来把JavaScript注入到USERINPUT6中,例如,可以使用下面的方法:

“> < script >a_lert(1)< /script >

  或者,如果不允许使用尖括号,则使用一个JavaScript事件处理程序,例如onclick事件处理程序,如下所示:

” onclick=”a_lert(1)

USERINPUT7 还可以是这样:

‘ >< script >a_lert(1)< /script >

  或者:

‘ style=’x: expression( a_lert ( 1 ) )

  甚至更简单一些:

javascript: a_lert( 1 )

  对于USERINPUT7的前两条利用方法能保证脚本在装入页面时执行,最后一种方法要求用户单击链接。您可以把它们都试一遍,看看是不是在某些情况下有些字符和字符串是不允许的。

USERINPUT8也面临类似的HTML注入字符串。下面是使用事件处理程序的最佳方式:

notThere’ onerror=’a_lert( 1 )

  XSS防御方法通常是对具有潜在恶意性的字符进行转义或者编码。举例来说,如果用户输入 到一个文本字段,服务器可能以下列转义后的字符串作为响应:


  根据转义后的字符串的所在位置,这些字符串将以本来面目出现并且不会执行。转义方法比较复杂,所以将在后面的对抗措施中加以详细讨论。大多数转义例程不是忘记对具有潜在恶意性的字符和字符串进行转义,就是使用了错误的编码方法进行换码。例如USERINPUT9,其事件处理程序把HTML实体编码为ASCII,所以任何人可以用下列两个字符串上演相同的攻击:

x’); a_lert ( 1 );

以及:

x’); a_lert( 1 )

  最后,USERINPUT10可以用事件处理程序利用,并突破输入标签,例子如下所示:

x onclick= a_lert ( 1 )

  这个例子说明,用户提供的字符串可以放到HTTP应答中的任何地方,看来真是一切皆有可能呀!

  如果您在任何前面的实例中成功进行了HTML注入,那么该HTML注入就可用于在那个域上的任何地方的XSS。您可以用多种不同的方法来向Web应用程序注入JavaScript。如果你的尝试曾经导致页面格式被破坏,诸如截断页面、显示了除您注入以外的脚本,那么很可能就是找到了一个XSS漏洞。

  四、重定向器中的反射式HTML注入

  HTML注入的另一个大舞台是重定向器。有些重定向器允许用户重定向到任何URL。 遗憾的是,JavaScript:a_lert(1)是一个合法的URL。许多重定向器会对URL进行解析,以确定重定向到那里是否安全。这些解析器以及他们的程序员并不总是人们想象的那么聪明,所以像下面的URL:

javascript://www.anywhere.com/%0da_lert( 1 )

  以及这个:

javascript://http://www.trustedsite.com/trustedDirectory/%0da_lert( 1 )

  可能被接受。在上面的例子中,任何字符串都可以放置在JavaScript注解所用的双斜杠之间以及URL编码的换行符(%0d)之间。

  五、移动式应用中的HTML注入
 
  有些流行的Web应用程序被移植到移动通信领域。这些移动式应用一般具有相同的功能,但是安全特性更差,并且仍然可以通过诸如IE 以及Firefox之类的浏览器进行访问。 因此,它们是HTML注入攻击以及跨站请求伪造的理想攻击目标。

  通常情况下,移动式应用作为主要的Web应用程序运行在相同的域上,因此移动式应用中的任何HTML注入都能够访问整个域,包括运行在该域上的主要的Web应用程序或者其它的Web应用程序。

  六、在Ajax响应以及错误信息中的HTML注入

  并非所有HTTP应答都会显示给用户。类似AJAX响应以及超文本传输协议(http)错误消息这些页面通常会被开发人员所忽视。开发人员可能没有考虑为AJAX响应提供HTML注入保护,因为这些请求通常不是由用户直接使用的。然而,攻击者可以用先前的代码片断模仿AJAX的GET以及POST请求。

  同样的,超文本传输协议(http)错误响应,诸如HTTP 404(Not Found)、HTTP 502(Server Error)等等,通常也会被开发人员所忽略。开发人员倾向于假定一切都是HTTP 200(OK)。您可以尝试触发其它的响应,而非仅仅HTTP 200,然后试着注入脚本。

  七、使用UTF-7编码进行HTML注入

  如果用户的IE自动选择编码集,那么攻击者就能规避大多数HTML注入预防措施。就像前面提到的那样,HTML注入的预防措施一般依赖于对潜在的有害字符进行转义处理。然而,UTF-7编码技术使用了无法正常转义的通用字符,而这些通用字符有时无法被某些Web应用程序进行换码。 的UTF-7转义版本将是下面的样子:

+ADw-script+AD4-a_lert(1)+ADw-/script+AD4-

  注意,这是一种不常见的攻击,因为用户一般不会打开自动选择编码技术选项。当然,也存在其他的利用字符编码可变长度的UTF编码攻击技术,但是这要求对UTF有着深入广泛的理解,所以它超出了本文的讨论范围。然而,这个问题说明其它编码(例如MIME类型)的疏漏也是能引起HTML注入的。

  八、利用MIME 类型不匹配来进行HTML注入

  IE具有许多令人惊讶的未公开特性,例如,IE7 以及之前的版本尝试加载一个图像或者其它的非HTML的响应并且失败时,它会将该响应作为HTML对待。为了弄明白这个情况,我们可以创建一个文本文件,并包含下列内容:


  之后,将其保存为alert.jpg,然后在IE的URL地址栏中或一个iframe中装载的这个“图像”,这就会导致这里的JavaScript被执行。
注意,如果该文件是从一个图像标签加载的话,它就不会作为脚本执行了。

  一般说来,当您试图上载这样的一个文件到一个图像托管服务时,该服务将拒绝这个文件,因为它根本就不是一个图像。但是图像托管服务通常情况下会忽视文件的扩展名,而只通过文件的幻数(开始几个字节)来确定文件类型。

  因此,攻击者可以避开它,方法是用GIF注释中的HTML来创建一个GIF图像,然后将这个GIF保存为.jpg文件扩展名的文件。下面是一个单像素的GIF文件,如下所示:

00000000 47 49 46 38 39 61 01 00 01 00 80 00 00 ff ff ff |GIF89a……….|
00000010 ff ff ff 21 fe 19 3c 73 63 72 69 70 74 3e 61 6c |…!.. .|
00000030 2c 00 00 00 00 01 00 01 00 00 02 02 44 01 00 3b |,………..D..;|

  将其命名为test.jpg,并在IE中加载它,这会导致执行这段JavaScript。这也是注入Flash跨域政策的一种好方法。只要把Flash安全策略的XML内容放入GIF注释,并保证这个GIF文件不包含扩展的ASCII字符或者字节NULL即可。您还可以把HTML注入到未压缩的图像文件(诸如XPM以及BMP文件)的图像数据部分,而不是注解中。

  九、使用Flash进行HTML注入

  在大多数HTML注入情形中,攻击者可以注入任意的HTML。举例来说,攻击可以注入一个对象和/或嵌入一个标签来加载该域上的Flash应用程序。 下面是一个例子:

  这里的HTML有些繁琐,但是它将JavaScript应用程序具有的控制权赋予一个Flash应用程序,例如(经过ExternalInterface类)读取Cookie、(经过ExternalInterface类)改变web页面外观、(经过XML类)读取用户私人数据以及(经过XML类)以受害者的名义建立HTTP请求。

  然而,Flash应用程序有时候会提供更多的功能。例如,flash应用程序可以通过Socket类创建原始的套按字连接。这允许攻击者构造他们的完整的HTTP数据包(包括通过ExternalInterface类窃取Cookie)或者连接到电脑允许的其它端口上。

  注意,Socket连接只能建立到达恶意脚本所源自的域的连接,除非攻击者为完成攻击还反射了一个不安全的跨域策略文件。

  有些开发人员通过把响应的MIME类型设置为text/plain或者除text /html以外的任何东西来防止AJAX响应被注入HTML。HTML注入将无法进行,因为浏览器不会把响应解释为HTML。然而,Flash并不关心跨域策略文件是哪种MIME类型,所以攻击者有可能使用AJAX响应来反射一个不安全的跨域策略文件。

  这允许恶意的Flash应用程序以受害者名义向有弱点的Web应用程序发送请求,读取该域上的任意的页面,并创建到达该域的套按字连接。这种类型的攻击的威胁相对较弱,因为恶意的Flash应用程序不能窃取Cookie(但是它仍然可以以用户的名义来完成任何动作),而且它不能在受害的用户前模仿成应用程序,除非恶意的Flash应用程序将用户重定向到一个攻击者控制下的域。

  然而,到目前为止,HTML注入所能做的最邪恶的事情还是在受害用户目前把自己装扮成Web应用程序,当然,通过其它方法也可以达到此目的,比如反射一个不安全的跨域策略文件,并使用ActionScript的XML类发送HTTP的GET和POST请求并且读取响应。 在下一节中,我们描述攻击是如何作恶的。

  十、结束语

  在浏览器中已经建立了一些安全措施——即同源策略和Cookie安全模型。此外,一些浏览器插件,诸如Flash Player、Outlook Express 以及Acrobat Reader等,带来了更多的安全问题和安全措施。然而,如果攻击者可以强迫用户执行源自特定域的JavaScript的话,这些额外的安全措施总是倾向于削弱同源策略的力量。

  跨站点脚本攻击(XSS)技术能够强迫用户执行攻击者以受害者名义在某个域上选择的脚本,如JavaScript、VBScript、ActionScript,等等。XSS要求某个域上的Web应用程序能够提供(即供应、返回)被攻击者所控制的字符。

  因此,攻击者可以向页面注入代码,而这些代码将来会在这个有弱点的域的上下文中执行。而本文将介绍跨站脚本漏洞利用的过程,并对HTML注入进行深入分析;我们将在下篇中详细介绍跨站脚本的危害,以及攻击者是如何诱骗受害者的,以及针对跨站脚本攻击的防御措施。

我们一直都在努力坚持原创.......请不要一声不吭,就悄悄拿走。

我原创,你原创,我们的内容世界才会更加精彩!

【所有原创内容版权均属TechTarget,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用。】

微信公众号

TechTarget微信公众号二维码

TechTarget

官方微博

TechTarget中国官方微博二维码

TechTarget中国

电子邮件地址不会被公开。 必填项已用*标注

敬请读者发表评论,本站保留删除与本文无关和不雅评论的权力。

作者

康凯
康凯

相关推荐