6.4.2 规范化攻击

这些攻击针对使用模板文件或者引用Web服务器上的替代文件的页面(dot-dot-slash)。攻击的基本形式是转移到Web文档根目录之外,以便访问系统文件,也就是“../../../../../../../../../boot.ini”。实际的服务器例如IIS和Apache在正常情况下都所能阻止这种攻击。IIS成为这种问题的受害者是因为在解码URL代码和执行目录遍历安全检查中的逻辑错误。IIS过剩解码(..%255c..)和IIS Unicode目录遍历(..%c0%af..)漏洞是两个著名的例子。关于这些漏洞的更多信息可在Microsoft的网站http://www.microsoft.com/technet/security/bulletin/MS01-026.mspx和http://www.microsoft.com/technet/security/bulletin/MS00-078.mspx上看到。

Web应用的安全总是取决于最弱的一环。即使是一个健壮的Web服务器也会因为不安全的应用而崩溃。规范化攻击的最大受害者是使用来自服务器的模板或者解析文件的应用。如果这种应用不限制应该查看的文件类型,Web文档根目录之外的文件就成为猎物。这种类型的功能明显来自于URL,不限于任何编程语言或者Web服务器:


/menu.asp?dimlDisplayer=menu.html
/webacc?User.html=login.htt
/SWEditServlet?station_path=Z&publication_id=2043&template=login.tem
/Getfile.asp?/scripts/Client/login.js
/includes/printable.asp?Link=customers/overview.htm

这种技术在Web应用不校验请求文件的位置和内容的时候能取得成功。例如,Novell的基于Web的Groupwise应用的登录页面URL的一部分是/servlet/webacc?User.html=login.htt。这种应用会遭到操纵User.html参数的攻击:


/servlet/webacc?User.html=../../../WebAccess/webacc.cfg%00

这种目录遍历将我们带到Web文档根目录之外的配置目录中。突然间,登录页面成了目标Web服务器的一扇窗户——我们甚至不需要登录!

提示  许多嵌入式设备、媒体服务器和其他连接到互联网的设备都具有基本的Web服务器——看看许多家庭网络用的路由器和无限访问点。在面对这种服务器时,始终可以在URL上尝试简单的目录遍历,看看会发生什么。安全性往往屈服于应用的大小和性能!

高级目录遍历

我们更仔细地看看Groupwise的例子。正常的HTTP请求返回login.htm的HTML内容。


<HTML>
<HEAD>
<TITLE>GroupWise WebAccess Login</TITLE>
</HEAD>
<!login.htm>
..remainder of page truncated...

第一声警报是webacc servlet以一个HTML文件(login.htt)作为参数,因为它暗示着应用装入和显示提供给User.html参数的文件。如果User.html参数接收一个不存在的文件,那么我们可以预期发生某种类型的错误,这些错误很可能给我们提供一些有用的信息。URL中一个攻击示例http://website/servlet/webacc?user.html=nosuchfile生成如下的响应:


File does not exist:
c:\Novell\java\servlets\com\novell\webaccess\
templates/nosuchfile/login.htt
Cannot load file:
c:\Novell\java\servlets\com\novell\webaccess\
templates/nosuchfile/login.htt.

这个错误泄露了应用的完整安装路径。而且,我们发现默认情况下login.htt文件附加到user.html参数指定的目录后。这是很有意义的,因为如果user.html参数没有传递,应用需要一个默认的模板。但是,login.htt文件妨碍了合适的目录遍历攻击。为了避开它,我们尝试了用于对付Web应用的一个老招数:空字符串。例如:

http://website/servlet/webacc?user.html=../../../../../../../boot.ini%00

[boot loader]

timeout=30

default=multi(0)disk(0)rdisk(0)partition(5)\WINNT[operating systems]

multi(0)disk(0)rdisk(0)partition(5)\WINNT="Win2K"/fastdetect

C:\BOOTSECT.BSD="OpenBSD"

C:\BOOTSECT.LNX="Linux"

C:\CMDCONS\BOOTSECT.DAT="Recovery Console"/cmdcons

注意,尽管应用在user.html参数值后附加login.htt,我们还是成功地得到了Windows boot.ini文件。窍门在于在user.html参数值后加上了%00。%00是空字符的URL编码表现,与字符串变量一起使用时,在C这样的编程语言里有非常特殊的意义。在C语言里,字符串是任意长度的字符数组。为了让程序知道字符串结束的地方,读取字符直到遇到一个特殊的字符——空字符时结束。因此,Web服务器将把原始的参数传递给user.html参数,包括%00。当servlet引擎解释这个参数时,仍然附加login.htt,使整个参数字符串变成:


../../../../../../../boot.ini%00login.htt

像Perl这样的编程语言实际上接受字符串中有空字符,不将它们当作分隔符。但是,操作系统是以C语言编写的(混合了C++)。当Perl或Java语言必须与操作系统上的文件交互时,它必须与一个函数交互,这很可能是以C语言编写的。尽管Perl或Java语言中的字符串可以包含空字符,但是操作系统函数将读取字符串中到空字符为止的所有字符,这意味着login.htt被忽略。Web服务器将%xx序列解码为16进制值。因此,%00字符串首先被Web服务器转换为空字符,然后传递给应用代码(这里是Perl),应用接受空字符为参数值的一部分。

提示  使用Unicode的替代字符编码也给编程语言带来了挑战。IIS过剩解码漏洞就是以使用替代Unicode编码表示斜杠字符为基础的。

强制应用访问任意文件有时候可能采用比%00更多的手法。下面是其他一些技术。

·../../file.asp%00.jpg: 应用完成需要图像后缀(.jpg或者.gif)的基本名校验。

·../../file.asp%0a: 换行符的作用类似空字符。这在输入过滤器剥离%00字符,但是没有去掉其他恶意载荷的情况下可能有用。

·/valid_dir/../../../file.asp: 应用完成文件来源的基本名校验。文件必须在有效的目录中。当然,如果没有删掉目录遍历字符,你就可以轻松地离开该目录。

·valid_file.asp../../../../file.asp: 应用完成文件之上的名校验,但是只进行文件名的部分匹配。

·%2e%2e%2f%2e%2e%2ffi le.asp(../../file.asp): 应用在参数进行URL解码之前进行名校验,或者应用的名称校验例程较弱并且不能处理URL编码的字符。

无目录列表导航

规范化攻击允许Web文档根目录内外的目录遍历。不幸的是,它们很少提供生成目录列表的能力——没有地图的地形研究很困难!但是,有一些技巧能够简化文件的列举。第一种手法是找出实际根目录开始的位置,也就是Windows系统上的驱动器号和Unix系统上的根(“/”)目录。IIS中这项工作稍稍容易一些,因为最上级目录默认情况下是“InetPub”。例如,通过持续地添加目录遍历直到成功地获得目标HTML文件,在IIS主机上寻找根目录(驱动器号)。下面是跟踪目标应用根目录的default.asp文件的一个简短示例:


Sent: /includes/printable.asp?Link=../inetpub/wwwroot/default.asp
Return: Microsoft VBScript runtime error '800a0046'
File not found
/includes/printable.asp, line 10
Sent: /includes/printable.asp?Link=../../inetpub/wwwroot/default.asp
Return: Microsoft VBScript runtime error '800a0046'
File not found
/includes/printable.asp, line 10
Sent: /includes/printable.asp?Link=../../../inetpub/wwwroot/
default.asp
Return: Microsoft VBScript runtime error '800a0046'
File not found
/includes/printable.asp, line 10
Sent: /includes/printable.asp?Link=../../../../inetpub/wwwroot/
default.asp
Return: Microsoft VBScript runtime error '800a0046'
...source code of default.asp returned!...

当一个简单的../../../../../../../../../../就能满足需要的时候,费尽心机地寻求目录遍历的精确数量就显得书生气了。但是,在你做出判断之前,仔细地审视转义字符的数量。在printable.asp文件转储源代码之前,必须有4次目录遍历。如果我们假定完整的路径是/inetpub/wwwroot/includes/printable.asp,那么我们应该转移到上三级目录。额外的一个遍历步骤所指的是/includes目录被映射到驱动器上的其他地方,或者链接文件的默认位置在其他地方。

注意  我们找到的printable.asp文件容易遭到这种攻击,是因为这个文件没有执行输入校验。从该文件的这行代码中很容易看出来:Link="D:\Site server\data\publishing\documents\"&Request.QueryString("Link")。注意这里的目录深度是多少。

错误代码也能帮助我们列举目录。我们使用“Path not found”(路径未找到)或者“Permission denied”(权限被拒绝)这样的信息追查存在于Web服务器之上的目录。回到前一个示例,我们将使用printable.asp列举目录:


Sent: /includes/printable.asp?Link=../../../../inetpub
Return: Micosoft VBScript runtime error '800a0046'
Permission denied
/includes/printable.asp, line 10
Sent: /includes/printable.asp?Link=../../../../inetpub/borkbork
Return: Micosoft VBScript runtime error '800a0046'
Path not found
/includes/printable.asp, line 10
Sent: /includes/printable.asp?Link=../../data
Return: Micosoft VBScript runtime error '800a0046'
Permission denied
/includes/printable.asp, line 10
Sent: /includes/printable.asp?Link=../../../../Program%20Files/
Return: Micosoft VBScript runtime error '800a0046'
Permission denied
/includes/printable.asp, line 10

这些结果告诉我们有可能区分Web服务器上存在和不存在的文件或者目录。我们证实/inetpub和“Program Files”目录存在,但是错误信息表明,Web应用对它们没有读访问权限。如果/inetpub/borkbork目录返回“权限拒绝”错误,那么这种技术就已经失败,因为我们没有办法区分真正的目录(Program Files)和不存在的目录(borkbork)。我们在列举阶段还发现了一个数据目录。这个目录指向printables.asp文件的神秘路径(D:\Site server\data\publishing\documents\)中。

下面是列举文件步骤的总结:

1.检查错误代码。确定应用对于不存在的文件、不存在的目录、存在的文件(但是可能读访问被拒绝)以及存在的目录是否返回不同的错误。

2.查找根目录。添加目录遍历字符,直到可以确定驱动器号或者根目录开始的地方。

3.在Web文档根目录中列举。Web文档根目录中的文件很容易列举。你应该在第一次研究应用时就列出了大部分文件。这些文件很容易寻找,因为它们是已知的。

4.寻找常见目录。查找临时目录(/temp、/tmp、/var)、程序目录(/Program Files、/winnt、/bin、/usr/bin)和流行的目录(/home、/etc、/downloads、/backup)。

5.尝试访问目录名称。如果应用对该目录有访问权,就会列出目录内容。这使得目录列举很简单!

注意  好的Web应用测试人员的笔记本应该包括Web服务器相关的常见程序的递归目录列表。拥有目录和配置文件的参考大大地提高了目录遍历攻击的成功率。应用列表应该包含Lotus Domino、Microsoft Site Server和Apache Tomcat这样的程序。

规范化攻击对策

对于规范化攻击最好的防御是从GET和POST中删除所有的点(.)。解析引擎也应该捕捉Unicode和16进制中对点的表现。

强制所有读取操作发生自特定的目录,应用删除与其文件名之前的所有路径信息的正则表达式过滤器。例如,将/path1/path2/./path3/file缩短为/file。

加强文件系统权限安全也能缓解这种攻击。首先,将Web服务器作为最低权限的用户运行:在Unix系统上创建“nobody”账户或者在Windows系统上创建具有运行应用所需最小权限的服务账户(为ASP.NET应用创建服务账户的方法参见“参考与延伸阅读”小节)。限制Web服务器账户,使其只能从与Web应用相关的目录中读取文件。

将敏感文件例如包含文件(*.inc)从文档根目录移出到具有合适访问控制的一个目录,确保匿名的互联网用户不能直接访问包含敏感文件的目录,只有具备合适授权的用户能够得到权限。这缓解了目录遍历攻击,使其只限于查看文档根目录中的文件。服务器和特权用户仍然能够访问这些文件,但是用户无法读取。