在描述各种常见漏洞与攻击技巧的过程中,我们提到,应用程序经常使用名称或标识符指代各种数据;渗透测试员的任务是查明它使用的部分或全部有效的标识符。以下是一些需要枚举出标识符的情况。
应用程序的登录功能返回详尽的错误消息,指出登录失败是因为用户名不存在或密码错误。在这种情况下,可以遍历一组常见的用户名,并尝试用每一个用户名登录,从而将攻击范围缩小至那些已知有效的用户名。然后测试员就可以使用得到的用户名列表,实施密码猜测攻击。
许多应用程序使用标识符指代应用程序处理的各种资源,如文档ID、账号、雇员号码和日志记录。通常,应用程序会泄露一些确定特殊标识符是否有效的方法。因此,遍历应用程序使用的标识符的语法范围就可以获得所有这些资源。
如果应用程序生成的会话令牌可以预测,那么,以应用程序发布的一些令牌为基础进行推断,就可以劫持其他用户的令牌。根据这个过程的准确程度,可能需要测试大量令牌才能确定每一个有效的值。
设计一个枚举有效标识符的定制自动攻击的第一步是查找一个具有以下特点的请求/响应对。
请求的参数中包含所针对的标识符。例如,在一个显示应用程序页面的功能中,请求中可能包含参数PageNo=10069。
当改变这个参数的值时,服务器对这个请求的响应也会发生相应变化。例如,如果请求
一个有效的PageNo,服务器可能返回一个包含指定文档内容的响应。如果请求一个无效的值,它可能会返回一个常见的错误消息。
确定一个适当的请求/响应对后,接下来应向应用程序提交大量自动请求,循环浏览所有潜在的标识符,或者遍历已知应用程序使用的标识符的语法范围。然后,监控应用程序对这些请求的响应,查找表示提交有效标识符的“触点”。
改变请求中的参数值后,响应的许多特征会发生系统性的改变,它们是实施自动攻击的基础。
1.HTTP状态码
根据请求提交的参数值,许多应用程序系统性地返回各种不同的状态码。在枚举标识符的攻击中,最常见的状态码包括以下几种。
200
,默认状态码,表示请求成功提交。
301或302
,重定向到另外一个URL。
401或403
,请求未获授权或被禁止。
404
,被请求的资源未发现。
500
,服务器在处理请求时遇到错误。
2.响应长度
应用程序中的动态页面常常使用一个页面模板建立响应(其长度固定),并在这个模板中插入针对每个响应的内容。如果针对每个响应的内容不存在或无效(例如,请求了一个错误的文档ID),那么应用程序就会返回一个空白响应。这时,响应长度就是证明文档ID是否有效的一个可靠指标。
在其他情况下,响应长度不同可能表示发生错误或存在其他功能。根据我们的经验,在绝大多数情况下,HTTP响应码与响应长度就足以确定反常的响应。
3.响应主体
应用程序返回的数据中常常包含可用于探测“触点”的字面量字符串或模式。例如,如果请求一个无效的文档ID,响应中可能包含字符串Invalid document ID。有时,即使HTTP响应码没有变化,但由于响应中包含动态内容,总体响应长度会发生改变。因此,在响应中搜索一个特殊的字符串或模式可能是确定“触点”的最佳方法。
4.Location消息头
有时候,应用程序会以一个HTTP重定向(状态码为301或302)响应访问某个特殊URL的请求,重定向的目标则取决于在请求中提交的参数。例如,如果提交正确的报告名称,一个查看报告的请求可能会导致一个目标为/download.jsp的重定向;否则,重定向就指向/error.jsp。HTTP重定向的目标在Location消息头中指定,这种方法同样也可用于确定“触点”。
5.Set-Cookie消息头
有时候,应用程序可能会以同样的方式响应一组请求,唯一例外的是有些时候它会设定一个cookie。例如,每个请求都会遇到相同的重定向,但如果证书有效,应用程序就会设定一个包含 会话令牌的cookie。客户端访问重定向得到的内容取决于是否提交了有效的会话令牌。
6.时间延迟
少数情况下,无论提交的参数是否有效,服务器响应返回的实际内容可能完全相同,但是它返回响应的时间可能稍有不同。例如,如果使用一个无效的用户名登录,应用程序可能会立即通过一个并不包含太多信息的常规消息做出响应。但是,如果提交的是有效的用户名,应用程序就需要进行各种后端处理来确认用户提交的证书,其中一些处理可能要进行大量计算,如果发现证书错误,再返回相同的消息。如果远程检测到这种时间差异,就可以用它来确定攻击中的“触点”。(其他类型的软件,如旧版的OpenSSH中也常常发现这种漏洞。)
提示
选择“触点”指标的主要目的是找到一个或一组(如果结合在一起)完全可靠的“触点”。但是,在一些攻击中,提前并不知道什么是“触点”。例如,当渗透测试员针对登录功能实施攻击,尝试枚举用户名时,并没有一个有效的用户名可帮助他确定应用程序在遇到“触点”时的行为。在这种情况下,最好是监控应用程序中刚刚描述的各种特征,寻找其中出现的任何异常现象。
假设已经确定以下URL,如果提交一个有效的PageNo值,它将返回200响应码;否则它就返回500响应码:
这个请求/响应对满足实施自动攻击并且枚举有效页面ID所需要的两个条件。
在这样简单的情况下,可以立即创建一段定制的脚本,实施一次自动攻击。例如,下面的bash脚本从stdin读取一组潜在的页面ID,使用netcat工具请求一个包含每个ID的URL,同时记录服务器响应的第一行,其中包含HTTP状态码:
用一个适当的输入文件(input file)运行这段脚本,得到以下输出,可以迅速从中确定有效的页面ID:
提示
Cygwin环境可用于在Windows平台上运行bash脚本;此外,UnxUtils套件中包含大量有用的GNU实用工具的Win32端口,如head和grep。
使用一段Windows批处理脚本也可以达到相同的目的。下面的示例使用curl工具生成请求,并通过findstr命令过滤输出:
虽然这些简单的脚本非常适于执行一些不太复杂的任务,如循环浏览一组参数值及在服务器响应中解析某个属性,但是,在许多情况下,可能需要使用比命令行脚本更强大、更灵活的工具。我们首选一种适当的高级面向对象的语言,它必须便于处理基于字符串的数据,并提供支持套接字和SSL的API。满足这些标准的语言包括Java、C#和Python。下面将深入分析一个使用Java的示例。
JAttack是一个简单但功能强大的工具,通过它,任何人只要懂得一些编程基础知识,就可以使用定制自动技巧向应用程序实施强大的攻击。这个工具的完整源代码可从本书的同步网站(http://mdsec.net/wahh)下载。但是,比源代码更重要的是使用这个工具的基本技巧,下面将对此进行简要说明。
不要把请求仅当做一个非结构化的文本块处理,而是要利用该工具理解请求参数的概念:它是一个可被操控,并以特殊方式附加在请求上的命名数据。请求参数可能出现在URL请求字符串、HTTP cookie或POST请求主体中。下面创建一个Param类保存相关细节。
许多时候,请求中包含不希望在某个特定的攻击中修改的参数;但为了成功实施攻击,仍然需要包含这些参数。可以使用attack字段标记某个参数是否可在当前攻击中进行修改。
要以一种特定的方式修改某个参数的值,JAttack工具必须理解攻击有效载荷的概念。在不同类型的攻击中,需要创建各种有效载荷源(payload source)。首先建立一个所有有效载荷必须执行的界面,提高这个工具的灵活性:
nextPayload方法可用于监控有效载荷源的状态,直到它的全部有效载荷用完后才返回true。reset方法返回有效载荷源起始点的状态。getPayload方法返回当前有效载荷的值。
在枚举文档的示例中,想要修改的参数包含一个数字值,因此首先在PayloadSource界面中执行一个类,生成数字有效载荷。可通过这个类指定想要测试的数字范围:
了解请求参数与有效载荷源的概念后,我们已经拥有足够的资源,能够生成请求并处理服务器的响应。首先,对攻击进行一些配置:
这个配置包含目标的基本信息,创建一个叫做PageNo的请求参数,并指定10060~10080为数字有效载荷源的范围。
为了循环浏览一系列的请求并针对多个参数,需要保持某种状态。使用一个简单的nextRequest方法监控请求引擎的状态,它在浏览完所有请求后返回true值。
这个有状态的请求引擎将追踪当前正针对哪个参数,以及在其中插入了什么攻击有效载荷。接下来使用这些信息建立一个完整的HTTP请求。它包括在请求中插入每种类型的参数,并增加任何必要的消息头:
注解
如果自己编写代码生成POST请求,那么,和在前面的代码中一样,就需要在其中包含一个有效的Content-Length消息头,指定每个请求中HTTP主体的实际长度。如果提交的是无效的Content-Length,大多数Web服务器或者将提交的数据截短,或者等待再提交更多的数据。
要送出请求,需要与目标Web服务器建立网络连接。使用Java之后,建立TCP连接、提交数据并读取服务器响应的任务都变得极其简单。
获得服务器对每个请求所做出的响应后,需要解析这些响应,提取出相关信息,确定攻击中的“触点”。首先记录两个有用的数据——响应第一行的HTTP状态码与响应的总长度:
现在已经为实施攻击做好准备。最后只需要一些包装器代码轮流调用前面提到的每一个方法并指出其结果,直到提出所有请求,nextRequest方法返回false:
整个过程就是这样!为编写并运行这些代码,需要下载Sun公司的Java SDK与JRE,然后运行下面的脚本:
根据我们在示例中的配置,这个工具输出如下结果:
如果网络连接与处理能力一切正常,JAttack每分钟能够提出数百个请求,并输入相关细节,帮助迅速确定需要进一步研究的有效文档标识符。