2.2.1 手工检查

我们进行应用剖析的第一件工作通常是简单地点击各处。熟悉网站,查找所有菜单,查看导航时URL目录名的变化。

Web应用很复杂,它们可能包含十几个文件,或者可能包含十几个有大量文件的目录。因此,以精心编排的方式记录应用的结构可以帮助你跟踪不安全的页面并且为组织一次有效的攻击提供必要的参考。

记录应用文档

打开文本编辑器是第一步,但是在类似Microsoft Excel的程序中建立一个矩阵来存储应用中每个页面信息是更简洁的方式。我们建议记录下面这些内容:

·页面名称: 按照字母顺序列出文件使得跟踪特定页面的信息更容易。这些矩阵可能相当长!

·页面的完整路径: 这是通向该页面的目录结构。你可以与页面名称相结合来提高效率。

·页面是否需要验证?: 是或者否。

·页面是否需要SSL?: 页面的URI可能是HTTPS,但是并不意味着页面不能通过普通的HTTP访问。用删除键删掉那个“S”!

·GET/POST参数: 记录传递给页面的参数。许多应用由操作大量参数的一些页面驱动。

·注释: 对页面进行个人的注解。这是搜索功能、管理功能还是帮助页面?这个页面“感觉”是不是不安全?它是否包含隐私信息?这是包罗万象的一列。

表2-1是部分完成的一个矩阵的示例。

注意  我们将在第4章中更多地讨论验证。简单地识别这种方法很重要。而且,仅仅/main/login.jsp页面需要验证并不意味着所有页面都需要验证,例如,/main/menu.jsp可能不需要。这一步开始暴露错误的配置。

另一个调查辅助手段是流程图。流程图帮助合并关于网站的信息并且以更清晰的方式表达。用一个精确的框图,你能够形象地表示应用的进程并且可能发现设计中的弱点或者不足之处。流程图可以是白板上的框图,或者是带有表示静态页面、动态页面、数据库访问例程及其他宏功能的色码块的3页图表。许多Web爬虫应用如WebSphinx,具有作图能力,图2-3显示了一个Web应用流程图的示例。

表2-1 记录Web应用结构的示例矩阵

图2-3 类似这个示例的流程图对于记录Web应用结构可能相当有用

对于严格的深入评审,我们建议在你的本地硬盘上镜像应用作为你的文档。你可以使用工具来自动建立映像(我们将在稍后的2.2.3节中讨论),或者手工进行映像。最好是保持和目标应用相同的目录结构,例如:


www.victim.com
/admin/admin.html
/main/index.html
/menu/menu.asp

提示  根据你对目标网站在未来的月份中预期修改的频率来调整花费在镜像上的精力。

应该考虑记录在矩阵/流程图上的其他信息包括:

·静态和动态生成的页面

·目录结构

·常用文件扩展名

·常用文件

·助手文件

·Java类和applet(小脚本)

·Flash和Silverlight对象

·HTML源代码

·表单

·查询串和参数

·常用cookie

·后端访问点

我们将在接下来的几个小节中更详细地讨论这些信息。

静态和动态生成的页面

静态页面通常是用于常见问题和联络信息的一般.html文件。它们缺乏使用输入验证测试的攻击所需要的功能,但是HTML源代码可能包含注释或者信息。最起码,联络信息会泄露电子邮件地址和用户名。动态生成的页面(asp、.jsp、.php等)更加有趣。记录感兴趣的页面的简短注释,如“管理员功能”、“用户简档信息”或者“购物车视图”。

我们前面已经提到,在手工剖析应用时,镜像应用的结构和内容到本地硬盘是个好主意。例如,如果www.victim.com有一个/include/database.inc文件,那么创建一个顶级目录www.victim.com和一个子目录“include”,并将database.inc文件放在该目录中。基于文本的浏览器lynx能够加速这一进程:


[root@meddle ]# mkdir www.victim.com
[root@meddle ]# cd www.victim.com
[root@meddle www.victim.com]# lynx -dump www.victim.com/index.html >index.html

netcat可能更好,因为它还能转储服务器首部,如下所示:


[root@meddle ]# mkdir www.victim.com
[root@meddle ]# cd www.victim.com
[root@meddle www.victim.com]# echo -e "GET /index.html HTTP/1.0\n\n" | \
> nc -vv www.victim.com 80 > index.html
www.victim.com [192.168.33.101] 80 (http) open
sent 27, rcvd 2683: NOTSOCK

为了使这个进程更加自动化(懒惰是种美德!),为netcat创建一个包装器脚本。这个脚本能在UNIX/Linux系统和安装了Cygwin实用程序的Windows系统上运行。创建名为getit.sh的文件并将其放置在执行路径中。下面是我们用于Web安全评估的一个getit.sh脚本示例:


#!/bin/sh
# mike's getit.sh script
if [ -z $1 ]; then
echo -e "\n\tUsage: $0 <host> <URL>"
exit
fi
echo -e "GET $2 HTTP/1.0\n\n" | \
nc -vv $1 80

等一下!Lynx和Mozilla能够处理只能通过SSL访问的页面。能使用netcat做同样的事情吗?答案是:不能。但是,你可以使用OpenSSL程序包。创建第二个文件,名为sgetit.sh,放在执行路径中:


#!/bin/sh
# mike's sgetit.sh script
if [ -z $1 ]; then
echo -e "\n\tUsage: $0 <SSL host> <URL>"
exit
fi
echo -e "GET $2 HTTP/1.0\n\n" | \
openssl s_client -quiet -connect $1:443 2>/dev/null

注意  getit脚本的多功能性不只在有2个命令行参数。你可以改造它,添加cookie、用户代理串或者其他HTTP首部。你所需要修改的是echo-e这一行。

现在你已经可以使用工作于HTTP和HTTPS的命令行了。Web应用将要失守!不用从你的浏览器或者Lynx中保存每个文件了,用前面展示过的getit脚本来代替,例如:


[root@meddle ]# mkdir www.victim.com
[root@meddle ]# cd www.victim.com
[root@meddle www.victim.com]# getit.sh www.victim.com /index.html >
index.html
www.victim.com [192.168.33.101] 80 (http) open
sent 27, rcvd 2683: NOTSOCK
[root@meddle www.victim.com ]# mkdir secure
[root@meddle www.victim.com ]# cd secure
[root@meddle secure]# sgetit.sh www.victim.com /secure/admin.html >
admin.html

OpenSSL s_client比netcat更冗长,查看输出时,过一会儿就令人厌倦。在我们走查Web应用的时候,你就会看到getit.sh和sgetit.sh脚本的重要性。保存这些脚本。你可以用getit脚本下载动态生成的页面,只要该页面不需要POST请求。这是很重要的功能,因为有些页面的内容很大程度上因接受的参数而变化。下面是另一个示例;这次getit.sh读取相同的menu.asp页面输出,但是用于两个不同的用户:


[root@meddle main]# getit.sh www.victim.com \
> /main/menu.asp?userID=002 > menu.002.asp
www.victim.com [192.168.33.101] 80 (http) open
sent 40, rcvd 3654: NOTSOCK
[root@meddle main]# getit.sh www.victim.com \
> /main/menu.asp?userID=007 > menu.007.asp
www.victim.com [192.168.33.101] 80 (http) open
sent 40, rcvd 5487: NOTSOCK

记住网站用于页面的命名惯例。程序员是不是不喜欢元音字母?(usrMenu.asp、Upld.asp、hlpText.php)?他们是否啰嗦?(AddNewUser.pl)他们是否大量利用脚本(main.asp的功能比瑞士军刀还多)?命名管理提供了对程序员思路的洞察。如果你发现一个页面叫做UserMenu.asp,那么很可能也存在一个叫做AdminMenu.asp的页面。调查应用的艺术不仅限于你通过归纳所找到的东西,它还包括了“猎鹿帽” [1] 和一些推理。

目录结构

Web应用的结构通常提供独特的识别标志。检查目录结构、文件扩展名、参数名和值的命名惯例等看似简单的项目,都能揭示可立即识别所运行的应用的线索(本章稍后的2.2.4节中可以看到一些新奇的例子)。获取网站公共部分的目录结构很容易。毕竟,应用是设计来让用户访问的。但是,不要停留在浏览器所能看到的部分和网站的菜单选择。Web户服务器可能有用于管理员的目录、老版本的网站、备份目录、数据目录和没有在HTML代码中引用的其他目录。试着猜测管理员和网站开发人员的思路。例如,如果静态内容在/html目录,动态内容在/jsp目录,那么cgi脚本就可能在/cgi目录里。

其他常用的目录包括:

·据推测通过SSL、验证或者混淆进行安全保证的目录:/admin//secure//adm/

·包含备份或者日志文件的目录:/.bak//backup//back//log//logs//archive//old/

·Apache个人目录:/~root//~bob//~cthulhu/

·包含文件目录:/include//inc//js//global//local/

·用于国际化的目录:/de//en//1033//fr/

这个列表并不完整。一个应用的整个目录结构可能会被移动到/en/下,来表示其用的是英语。因此,访问/include/可能返回404错误,但是访问/en/include就可以成功。回到你使用目录检查得到的已知目录和页面记录文档。程序员或者系统管理员采用什么风格来设计网站?你能在/scripts/下面找到/inc/目录吗?如果可以,接着尝试/scripts/js/或者/scripts/inc/js/。

枚举目录结构可能是个艰苦的过程,但是getit脚本能够帮你对付任何目录树。Web服务器对服务器上某个目录的GET请求会返回一个非404的错误码。这个错误码可能是200、302或者401,但是只要不是404,你就发现了一个目录,这种技术很简单:


[root@meddle]# getit.sh www.victim.com /isapi
www.victim.com [192.168.230.219] 80 (http) open
HTTP/1.1 302 Object Moved
Location: http://tk421/isapi/
Server: Microsoft-IIS/5.0
Content-Type: text/html
Content-Length: 148
<head><title>Document Moved</title></head>
<body><h1>Object Moved</h1>This document may be found <a HREF="http://
tk-421/isapi/">
here</a></body>sent 22, rcvd 287: NOTSOCK

用我们信赖的getit.sh脚本,我们发出了一个对/isapi/目录的请求;但是,我们忽略了一个重要的部分。后缀的斜杠从目录名中漏掉,导致IIS服务器重定向到实际的目录中。副作用是,这也泄露了服务器的内部主机名或者IP地址——即使它位于防火墙或者负载平衡器之后也是一样。Apache同样受到影响,它不会泄露服务器的内部主机名或者IP地址,但是会泄露虚拟服务器:


[root@meddle]# getit.sh www.victim.com /mail
www.victim.com [192.168.133.20] 80 (http) open
HTTP/1.1 301 Moved Permanently
Date: Wed, 30 Jan 2002 06:44:08 GMT
Server: Apache/2.0.28 (Unix)
Location: http://dev.victim.com/mail/
Content-Length: 308
Connection: close
Content-Type: text/html; charset=iso-8859-1
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>301 Moved Permanently</title>
</head><body>
<h1>Moved Permanently</h1>
<p>The document has moved <a href="http://dev.victim.com/mail/">here</a>.</p>
<hr />
<address>Apache/2.0.28 Server at dev.victim.com Port 80</address>
</body></html>
sent 21, rcvd 533: NOTSOCK

正是如此!如果目录不存在,则会收到404错误。否则继续挖掘目录树。

遍历Web应用查找隐藏文件夹时能够减少所花时间和精力的另一个工具是OWASP DirBuster。DirBuster是一个多线程Java应用,设计用于暴力破解Web服务器上的目录和文件。根据一个用户提供的字典文件,DirBuster将试图在应用中爬行,并且猜测非链接的目录和有特定扩展名的文件。例如,如果应用使用PHP,用户可以指定“php”为特定文件扩展名,DirBuster将在每个爬虫程序遇到的目录中猜测名为[字典中的词].php的文件(见图2-4)。DirBuster能够递归扫描查找的新目录,性能可以调整。应该注意的是,使用DirBuster进行递归扫描会导致大量流量,而在过度请求不受欢迎的环境里,线程数量应该减少。

图2-4 OWASP DirBuster工具用于暴力破解隐藏的目录和文件

常见文件扩展名

文件扩展名是应用类型很好的标志。通过语言或者应用关联,文件扩展名用于确定文件类型。文件扩展名还通知Web服务器如何处理该文件。某些扩展名是可执行文件,其他的则只是模板文件。下面的列表包含了Web应用中常见的扩展名以及它们的关联。如果你不知道扩展名所关联的应用程序,只要用Google之类的互联网搜索引擎搜索该扩展名(例如,使用语法“allinurl:.cfm”)。这将允许你识别可能使用这一扩展名的网站,能帮助你缩小扩展名关联的应用程序的范围。

提示  另一个研究文件扩展名的方便资源是http://filext.com/,使你能找出一个扩展名所关联的应用程序。

表2-2列出了一些常见的文件扩展名和使用它们的应用或者技术。

表2-2 常见文件扩展名和使用它们的应用或者技术

了解最新的常用Web应用软件:因为评估Web应用是我们的工作,我们通常希望尽可能熟悉流行的Web应用软件。我们始终和最新的现有/开放源码Web应用打交道。到www.sourceforge.net或者www.freshmeat.net查看最流行的50个免费Web应用,它们用于许多应用。了解它们的工作原理和观感将能帮助你在评估网站时很快地发现它们的存在。

常见文件

大部分软件安装时还会带有一些众所周知的文件,例如:

·Readme(自述文件)

·ToDo

·Changes(更改说明文件)

·Install.txt(安装说明文件)

·EULA.txt

搜索网站中的所有文件夹和子文件夹,你可能会发现丰富的有用信息,它们能告诉你正在运行的应用及其版本,以及指向软件和更新下载页面的URL。如果没有时间或者能力检查所有文件夹,你应该确保至少查看网站的根目录,这些文件类型通常保存在那里(例如,http://www.site.com/Readme.txt)。大部分管理员和开发人员会遵循默认的安装,或者会将整个档案的内容解压到Web根目录。这些家伙非常帮忙!

助手文件

助手文件是对所有支持应用但是通常不出现在URL中的文件的总称。常见的“助手”是JavaScript文件。它们通常用于格式化HTML,以适应流行浏览器的怪癖或者执行客户端输入验证。

·层叠样式单: CSS文件(.css)指示浏览器如何格式化文本。它们很少包含敏感信息,但是不管怎么说要将它们列举出来。

·XML样式单: 应用正在转向用XML表现数据。样式单(.xsl)定义XML请求和格式化的文档结构。它们可能拥有丰富的信息,通常列出数据库域或者引用其他助手文件。

·JavaScript文件: 几乎所有Web应用都使用JavaScript(.js),其中大部分都嵌入到实际的HTML中,但是也存在单独的文件。应用将JavaScript文件用于从浏览器定制到会话处理等各个方面。除了列举这些文件以外,重要的是要注意文件包含的函数类型。

·包含文件: 在IIS系统上,包含文件(.inc)通常控制数据库访问或者包含应用内部使用的变量。程序员喜欢将数据库连接串放在这个文件里——密码和所有其他信息!

·其他: 对ASP、PHP、Perl、文本和其他文件的引用可能在HTML源代码中。

URL很少直接引用这些文件,所以你必须转向HTML源代码中寻找它们。在服务器端包含指令(Server Side Include directives)和脚本标记中查找这些文件。你可以手工检查页面,或者使用方便的命令行工具,下载文件并且开始搜索。尝试常见的文件后缀和标志:


[root@meddle tb]# getit.sh www.victim.com /tb/tool.php > tool.php
[root@meddle tb]# grep js tool.php
www.victim.com [192.168.189.113] 80 (http) open
var ss_path = "aw/pics/js/"; // and path to the files
document.write("<SCRIPT SRC=\"" + ss_machine + ss_path +
"stats/ss_main_v-" + v +".js\"></SCRIPT>");

这样的输出告诉我们两件事。第一,有两个目录我们之前没有找到:aw/pics/js/和stats/。第二,有多个遵循ss_main_v-*.js命名惯例的JavaScript文件,这里的*代表某个取值。稍作一些源代码筛选就能告诉我们这一取值。

你也可以猜测常见的文件名称。在前面的步骤中列举的目录中尝试如下文件名:

同样,这些搜索不需要手工进行。我们将在稍后的2.2.2节和2.2.3节介绍这些工具,探讨自动化搜索方法。

Java类和小应用程序(Applet)

基于Java的应用是源代码筛选和调查网站功能的一种特殊情况。如果你能够下载Java类或者编译后的小服务程序(Servlet),那么你就可以实际地从内部拆解应用。想象一下,如果应用使用以Java servlet编写的自定义加密方案,而你能够下载这个Servlet并且窥探其代码。

在Web应用当中查找小应用程序相当简单:只要查找applet标记代码如:


<applet code = "MainMenu.class"
codebase="http://www.site.com/common/console" id = "scroller">
<param name = "feeder" value
="http://www.site.com/common/console/CWTR1.txt">
<param name = "font" value = "name=Dialog, style=Plain, size=13">
<param name = "direction" value = "0">
<param name = "stopAt" value = "0">
</applet>

Java设计为一种编写一次、到处运行的语言。显著的副作用是实际上你可以反汇编Java类为原始的源代码,最佳的工具是Java反汇编程序(jad)。使用jad反汇编Java很简单:


[root@meddle]# jad SnoopServlet.class
Parsing SnoopServlet.class... Generating SnoopServlet.jad
[root@meddle]# cat SnoopServlet.jad
// Decompiled by Jad v1.5.7f. Copyright 2000 Pavel Kouznetsov.
// Jad home page:
// http://www.geocities.com/SiliconValley/Bridge/8617/jad.html
// Decompiler options: packimports(3)
// Source File Name: SnoopServlet.java
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;
import javax.servlet.*;
import javax.servlet.http.*;
public class SnoopServlet extends HttpServlet
{
...remainder of decompiled Java code...

使用这个工具并不要求训练有素的Java编码人员。能够访问这个网站的内部功能你就可以检查数据库调用、文件格式、输入验证(或者验证的缺失)以及其他服务器功能。

你可能发现获得实际的Java类很困难,但是可以尝试下面这几种技巧:

·在小服务程序名后面加上.java或者.class。例如,如果网站使用一个小服务程序“/servlet/LogIn”,就查找“/servlet/LogIn.class”。

·在备份目录中搜索小服务程序:如果小服务程序在一个Servlet引擎没有识别为可执行的目录中,那么你可以读取实际的文件来代替接收其输出。

·搜索常见的测试Servlet:SessionServlet、AdminServlet、SnoopServlet和Test是一些测试小服务程序的名称。注意,许多Servlet引擎是大小写敏感的,所以你必须正确输入名称。

小应用程序(applets)看上去是软件中最不安全的部件,大部分开发人员没有意识到它很容易反汇编从而泄露大量信息。小应用程序实际上是包含所有与服务器通信所需代码的胖客户端。我们已经多次看到小应用程序直接发送SQL查询给应用,或者使用特殊的来宾账户执行某些功能,代码中嵌入了用户名和密码。如果你看到一个用于敏感操作的小应用程序,那是令人欣喜的,十有八九你会在反编译之后发现真正的安全问题。如果小应用程序由于使用了好的混淆技术而无法反编译,那么研究发往Web服务器的通信,对其进行逆向工程。大部分小应用程序将遵循浏览器的代理设置,所以通过将其设置为指向你掌握的代理工具,这样的小应用程序的通信将是可见的。在某些情况下,小应用程序将不会遵循浏览器代理设置,在这种时候,退回到老式的方法将是有效的,所以可以用上你所信赖的嗅探程序。

Flash和Silverlight对象

交互式网站组件越来越流行。随着开发人员接受新的技术如Flash和Silverlight,更多的应用逻辑被放到客户端。与这个潮流并行,客户端逻辑也变成了现代攻击者的目标。正如有可能反汇编Java小应用程序,窥探客户端代码如Flash SWF文件和强大的Silverlight组件的内部功能也是可能的。我们将在第9章介绍对Flash和Silverlight的攻击,以及防御对策。

HTML源代码

HTML源代码可能包含许多有趣的信息片段。

HTML注释: 攻击者所看到的最明显的位置是HTML注释,这是源代码的特殊部分,作者通常在这里放置可能透露许多信息的非正式摘要。<--字符表示所有基本的HTML注释。

HTML注释内容的价值是未知的。它们可能无处不在却不提供什么信息,也可能很少,但是包含了用于后续SQL查询的数据库表的描述,甚至更糟——含有密码。

接下来的示例展示了我们的getit.sh脚本如何获取网站的ndex.html文件,然后通过UNIX/Linux grep命令查找HTML注释(你可以使用类似grep命令的Windows findstr命令)。

注意  !字符在UNIX/Linux命令行上有特殊的含义,在grep搜索中必须用“\避开。


[root@meddle ]# getit.sh www.victim.com /index.html | grep "<\!--"
www.victim.com [192.168.189.113] 80 (http) open
<!-- $Id: index.shtml,v 1.155 2002/01/25 04:06:15 hpa Exp $ -->
sent 17, rcvd 16417: NOTSOCK

最起码,这个示例向我们展示了,index.html文件实际上链接到index.shtml。.shtml扩展名暗示这个页面使用服务器端包含创建。在剖析应用时归纳起着很重要的作用,这就是熟悉各种类型Web技术的重要性。

突击测试一下:哪类程序对上例中$Id里的信息负责?

你可以使用这种技术(使用我们的getit脚本或者你选择的自动化Web爬行工具)将整个网站的注释转储到一个文件中,然后审阅该文件,寻找任何有趣的项目。如果你发现了有感兴趣的内容,可以在网站上搜索该注释,查找其所在的页面,然后小心地研究该页面来理解注释的上下文。这一过程可能揭示更多有趣的信息,包括:

·类似文件名的注释: 你一般会看到许多插入了模板文件名的注释。下载这些模板并查看其代码。你永远不知道可能发现什么。

·老代码: 寻找可能被注释掉的链接。它们可能指向网站中包含安全漏洞的老部件。该链接也可能指向曾经的工作文件,而现在你访问它时会显示错误信息。

·自动生成的注释: 你可能看到许多注释是Web内容软件自动生成的。在搜索引擎中寻找这些注释,看看是哪些其他网站出现相同的注释。你可能会发现这些注释是什么软件产生的,并且得到有用的信息。

·显而易见的信息: 我们曾经注释中看到完整的SQL语句、数据库密码和IRC聊天记录中为其他开发人员留下的注释等信息。

其他HTML源代码宝藏: 不要停留在注释的分隔符号上。HTML源代码有所有类型的宝藏。尝试搜索如下字符串:

如果你发现了SQL字符串,感谢Web入侵之神——应用可能很快就会沦陷(但是你还必须等到第8章才能发现原因)。特定字符串的搜索总是硕果累累,但是最后,你必须在记事本或者vi中打开文件,了解整个情况。

注意  使用grep命令时,尝试-i标志(忽略大小写),-AN标志(显示匹配行之后的N行)和-BN标志(显示匹配行之前的N行)。

偶尔,语法错误会蔓延到动态页面中。不正确的语法可能导致文件部分执行,这可能在HTML源代码中留下原始的代码片段。以下是由于错误放置的PHP标记导致的一个代码片段(来自一个网站):


Go to forum!\n"; $file = "http://www.victim.com/$subdir/list2.php?
f=$num"; if (readfile($file) == 0) { echo "(0 messages so far)"; } ?>

HTML中另一个值得搜索的有趣项目是指出服务器端执行的标记,例如PHP所用的<?和?>,ASP页面所用的<%、%>和<runat=server>。这些标记能够指出网站开发人员从未打算让公众看见的有趣部分。

HTML源代码信息还能在与互联网搜索引擎如Google的组合时提供有用的信息。例如,你可能在注释中找到开发人员姓名和电子邮件地址。这种信息本身可能没有什么意义,但是如果你在Google上搜索并且发现这位开发人员张贴了与他的应用开发相关的一些问题呢?现在你突然间洞察了这个应用开发的方式。你还可以假设相同的信息可能是网站验证部分的一个用户名,尝试对这个用户名进行暴力密码攻击。

举个例子,用HTML注释中出现的一个用户名进行Google搜索,能够找出该开发人员开发的能从其网站上下载的其他应用。查看这些代码,我们发现它的应用使用的配置数据在开发人员自己的网站上!稍微花了一点工夫,我们在这个配置数据中发现一个DES管理员密码文件。我们下载这个文件并且运行密码破解工具。在一个小时内,我们得到密码并且以管理员密码登录。这次的成功完全归功于一个注释和非常有帮助的开发人员主页。

关于HTML源代码筛选的最终思路:经验法则是查找所有包含你尚不知道的信息的内容。当你发现文件中每个页面上的知识中有一些奇怪的随机数字字符串,对其进行研究。这些随机数字可能属于一个具有Web访问界面的媒体管理应用。Web评估中最少量的信息也可能带来最大的突破,所以别让任何内容从你面前溜走,不管它第一眼看上去多么微不足道。

表单

表单是所有Web应用的骨干。曾经有多少次当你在网站上创建一个账号,你取消了标有“不要取消此检查框,否则将接收到垃圾邮件!”的检查框?由于难以理解的选择性退出(Opt-out)验证(或者选择性加入?),甚至英语专业学生的收件箱也充斥着主动提供的电子邮件。当然,表单中有与安全相关的更加重要的部分。你必须得到这些信息,因为大部分输入验证攻击是对付表单信息的。在手工检查应用时,并不是每个页面都有输入域。你可以点击遍历网站找到大部分表单,但是视觉的确认是不够的,你必须再一次转向源代码。对于喜欢镜像整个网站并使用grep命令行的朋友来说,从查找表单最简单的标志——它的标记开始。记住避开<字符,因为它在命令行上有特殊的意义。


[root@meddle]# getit.sh www.victim.com /index.html |
grep -i \<form www.victim.com [192.168.33.101] 80 (http) open sent 27,
rcvd 2683: NOTSOCK
<form name=gs method=GET action=/search>

现在你得到了表单的名称——gs,你知道它使用GET来代替POST,它调用Web根目录下的一个“search”脚本。回到搜索助手文件那一步,我们可能要搜索下面几个文件:search.inc、search.js、gs.inc和gs.js,猜测一下无伤大雅。记住,如果有可能的话下载/search文件的HTML源代码。

接下来,找出表单包含的域。源代码筛选在这一阶段是必需的,但是我们将组合grep来简化这一过程:


[root@meddle]# getit.sh www.victim.com /index.html |
grep -i "input type" www.victim.com [192.168.238.26] 80 (http) open
<input type="text" name="name" size="10" maxlength="15">
<input type="password" name="passwd" size="10" maxlength="15">
<input type=hidden name=vote value="websites">
<input type="submit" name="Submit" value="Login">

这个表单显示了3项:登录域、密码域和带有“Login”文本的提交按钮。用户名和密码都必须等于或者少于15个字符(这个应用是这么认为的)。HTML源代码揭示了第4个域“name”。应用使用隐含域有多种目的,大部分都严重地影响了网站的安全。会话处理、用户标识、密码、货物价格和其他敏感信息常常被放到隐含域里。我们知道你们急于实际尝试输入验证,但是请耐心一点。我们必须收集所有与网站相关的信息。

如果你打算创建一个进行表单登录的暴力脚本,就会希望列举所有密码域(你可能必须忽略\"字符串):


[root@meddle]# getit.sh www.victim.com /index.html |
\> grep -i "type=\"password\""
www.victim.com [192.168.238.26] 80 (http) open <input type="password"
name="passwd" size="10" maxlength="15">

机警的程序员可能不使用密码输入类型或者在表单上使用“password”、“passwd”或“pwd”等词语。你可以搜索不同的字符串,但是命中率可能较低。较新的Web浏览器支持自动完成功能,使用户不用在每次访问网站时输入相同的信息。例如,浏览器可能保存用户的地址。然后,每当浏览器发现一个地址域(也就是说,它在表单中搜索“address”)时,它将自动提供用户信息。但是,对于密码域,自动完成功能通常设置为“关”:


[root@meddle]# getit.sh www.victim.com /login.html | \
> grep -i autocomplete
www.victim.com [192.168.106.34] 80 (http) open
<input type=text name="val2"
size="12" autocomplete=off>

这可能表示“val2”是一个密码域。至少,它似乎包含了程序员明确不希望浏览器存储的敏感信息。在这个例子中,没有使用type="password"是一个安全问题,因为当用户向域中输入数据时未被遮蔽。所以,在检查页面表单时,记下所有方面:

·Method(方法): 表单使用GET还是POST提交数据?GET请求比较容易在URL上操纵。

·Action(操作): 哪个脚本执行表单调用?使用哪种脚本语言(.pl、.sh、.asp)?如果你看到一个表单调用了带有.sh扩展名(shell脚本)的脚本,做出标记。Shell脚本在Web服务器上不安全是臭名昭著的。

·Maxlength(最大长度): 输入域是否应用了输入限制?长度限制很容易绕开。

·Hidden(隐含): 该域是否应该对用户隐藏?隐含域的值是什么?这些域很容易修改。

·Autocomplete(自动完成): 是否应用自动完成标记?为什么?输入域是否请求敏感信息?

·Password(密码): 这是个密码域吗?对应的登录域是什么?

查询字符串和参数

给定URL的最重要的部分可能是查询串,也就是问号(大部分情况下)之后的部分,指出某种反馈给应用中的动态可执行文件或者库文件的变量或参数。下面是一个示例:

http://www.site.com/search.cgi?searchTerm=test

这个URL表明值为test的searchTerm参数反馈到这个网站的可执行文件search.cgi。

查询串及其参数可能是需要收集的最重要信息,因为它们代表动态Web应用的核心功能,通常是最不安全的部分,因为它有最易变动的部件。你可以操纵参数值,试图假冒其他用户、获取受限的数据、运行任意系统命令,或者执行应用开发人员不期望的其他操作。参数名也能提供关于应用内部工作原理的信息。它们可能代表数据库列名、明显的会话ID或者包含用户名。应用管理这些字符串,但是可能没有恰当地进行验证。

查询字符串指纹识别: 根据应用或者应用的调整方式,参数具有可辨识的外观和实现,对此应该加以注意。前面我们已经提到过,通常在查询串中的?之后包含参数。但是,在复杂和定制的应用中,这条规则不总是适用。所以你所要做的第一件事是识别路径、文件名和参数。例如,在表2-3列出的URL中,参数的定位由易到难。

表2-3 常见查询串结构

我们用于确定如何分离这些参数的方法是从URL中删除项。应用服务器通常为每个部分生成一个标准的错误信息。例如,我们可以从URL中删除到斜杠的所有东西,这样可能会生成一个错误信息,指示“错误的未知过程”之类的意思。接着继续删除URL的各部分,直到接收到一个不同的错误。一旦我们到达404错误的地方,就可以推测删除的部分是一个文件。你始终可以复制错误信息中的文本,看看能否用Google找到应用文档。

在接下来的2.2.4节“常见Web应用剖析”中,我们将提供丰富的查询串结构指纹识别示例。我们已经在这里展示了两个,作为开胃小菜:


file.xxx?OpenDocument or even !OpenDatabase (Lotus Domino)
file.xxx?BV_SESSIONID=(junk)&BV_ENGINEID=(junk) (BroadVision)

分析查询串和参数: 收集查询串和参数是一件复杂的工作,很少有两个应用是相同的。在收集变量名称和值时,注意某些趋势。我们将(再次)使用如下的示例来说明某些重要的趋势:

http://www.site.com/search.cgi?searchTerm=testing&resultPage=testing&db=/templates/db/archive.db

这些参数中有三个有趣的地方:

·resultPage值等于搜索词,任何获取用户输入,并将输入用于设计意图之外的工作都是很好的安全问题勘查点。

·resultPage这个名称带来了一些问题。如果这个参数的值看上去不像一个URL,那么可能用于创建一个文件或者告诉应用装入一个以这个值命名的文件。

·但是,实际上引起我们注意的是db=/templates/db/archive.db,接下来我们将对此进行讨论。

表2-4列出了我们在查询串中看到db=/[path]这种语法的前五分钟内要尝试的工作。任何使用文件系统路径作为输入的应用逻辑都可能有问题。这些常见的对Web应用文件路径漏洞的攻击技术,将说明许多这些问题的性质。我们也会对resultPage参数尝试所有这些策略。如果你希望更深入研究,那么搜索search.cgi archive.d,或者学习更多搜索引擎的工作原理,或者假定“db”是被搜索的数据库。

表2-4 攻击尝试和含义

来点创意——你可能猜到其他可能包含非公共信息的隐含数据库名称,例如:


db=/templates/db/current.db
db=/templates/db/intranet.db
db=/templates/db/system.db
db=/templates/db/default.db

这里有其他的一些常用查询串/参数“主题”,可能指出潜在的脆弱应用逻辑:

·用户标识: 查询代表用户的值。这可能是一个用户名、一个数字、用户的社会保险号或者其他与用户绑定的值。这种信息用于假冒攻击。相关的字符串是userid、username、user、usr、name、id、uid。例如:


/login?userid=24601.

·不要被这些用户参数的散列值吓倒。例如,你可能最终得到这样的参数:


/login?userid= 7ece221bf3f5dbddbe3c2770ac19b419

·实际上,这只不过是与上面相同的userid值用MD5值计算出的散列值而已。为了利用这个问题,只要把值递增为24602,并且计算该值的MD5散列值放入参数值中即可。识别这些转换过的参数的一种好办法是维护一个常用值(如编号、常见用户名、常见角色等)的散列值数据库。然后,取得应用中找到的任何MD5值进行简单的比较将会发现像刚才提到的那种简单散列技术。

·会话标识: 查找整个会话中保持恒定的值。cookie也能进行会话处理。一些应用可能在URL上传递会话信息。相关的字符串是sessionid、session、sid和s。例如:


/menu.asp?sid=89CD9A9347

·数据库查询: 检查URL中任何像是传递给数据库的值。常见的值有姓名、地址信息、偏好或者其他用户输入。这些参数是输入验证和SQL注入攻击的绝佳候选。除了匹配URL的操作及所处理的数据,没有其他简单的数据库值指示。例如:


/dbsubmit.php?sTitle=Ms&iPhone=8675309

·搜索编码/加密值: 不要被参数中复杂的值所吓倒。例如,你可能在ASP.NET的viewstate参数中看到:


"__VIEWSTATE=dDwtNTI0ODU5MDE1Ozs+ZBCF2ryjMpeVgUrY2eTj79HNl4Q="

·这看上去很复杂,但也不过是一个Base64编码值。通常可以通过查看字符串的组成来确定,这种编码值由随机的大小写字母A-Z和0-9加上分散的+和/组成。最容易露出马脚的是字符串末尾的=号(可能有两个)。很容易通过Base64解码工具看到网站开发人员存储的值。Web应用中使用的其他一些常见编码/加密算法包括:MD5、SHA-1和神圣的XOR。长度通常是发现加密算法的关键。但是要小心,许多Web应用会组合多种散列和其他数据类型。识别分隔符之类的字符是简化加密算法检测的关键。

·布尔参数: 这些参数很容易篡改,因为可能的取值很少。例如,对于“Debug”这样的布尔参数,攻击者可能尝试设置该值为TRUE、T或者1。其他布尔参数包括dbg、admin、source和show。

常见cookie

发现所运行的应用类型的场所不仅仅是URL。应用和Web服务器常常携带自己专用的cookie,表2-5中给出了示例。

表2-5 现有Web软件使用的常见cookie

后端访问点

最后收集的一组信息是后端连接的证据。注意,这些信息是应用进行更新地址信息或者改变密码时从数据库读取和写入的。标出与数据库或者其他系统直接相关的页面或者页面中的注释。

某些WebDAV选项启用Web服务器的远程管理。错误配置的服务器可能允许任何人上传、删除、修改或者浏览Web文档根目录。检查这些选项是否启用(我们将在第3章更多地讨论如何识别和评估WebDAV)。

[1] 猎鹿帽是《福尔摩斯》中的经典造型。——译者注