渗透测试步骤

(1)尝试输入一个结果等于原始数字值的简单数学表达式。例如,如果原始值为2,尝试提交1+1或3–1。如果应用程序做出相同的响应,则表示它易于受到攻击。

(2)如果证实被修改的数据会对应用程序的行为造成明显影响,则前面描述的测试方法最为可靠。例如,如果应用程序使用数字化PageID参数指定应返回什么内容,则用1+1代替2得到相同的结果明显表示存在SQL注入。但是,如果能够在数字化参数中插入任意输入,但应用程序的行为却没有发生改变,那么前面的检测方法就无法发现漏洞。

(3)如果第一个测试方法取得成功,你可以利用更加复杂的、使用特殊SQL关键字和语法的表达式进一步获得与漏洞有关的证据。ASCII命令就是一个典型的示例,它返回被提交字符的数字化ASCII代码。例如,因为A的ASCII值为65,在SQL中,以下表达式等于2。

img240a

(4)如果单引号被过滤掉,那么前面的测试方法就没有作用。但是,这时可以利用这样一个事实:即在必要时,数据库会隐含地将数字数据转化为字符串数据。例如,因为字符1的 ASCII值为49,在SQL中,以下表达式等于2。

img240b

img004  提示  在探查应用程序是否存在SQL注入之类的缺陷时,我们常常会犯一个错误,即忘记某些字符在HTTP请求中具有特殊含义。如果你希望在攻击有效载荷中插入这些字符,必须谨慎地对它们进行URL编码,确保应用程序按预料的方式解释它们,特别是以下字符。

img002 &和=用于连接名/值对,建立查询字符串和POST数据块。应当分别使用%26与%3d对它们进行编码。

img002 查询字符串中不允许使用空格,如果在其中提交空格,整个字符串会立即终止。必须使用+或%20对其编码。

img002 由于+用于编码空格,如果想在字符串中使用+,必须使用%2b对其编码。因此,在前面的数字化示例中,1+1应以1%2b1的形式提交。

img002 分号用于分隔cookie字段,必须使用%3b对其编码。

无论是通过拦截代理服务器直接从浏览器中编辑参数值,或是使用其他方法进行编辑,都必须使用这些编码方法。如果没有对相关字符进行编码,那么整个请求可能会无效,或提交预期之外的数据。

一般来说,前面描述的步骤足以确定绝大多数的SQL注入漏洞,包括许多向浏览器返回无用结果或错误信息的漏洞。但是,在某些情况下,可能有必要使用更加高级的技巧,如时间延迟,来确定漏洞是否存在。我们将在本章后面部分描述这些技巧。

3.注入查询结构

如果用户提交的数据被插入SQL查询结构,而不是查询中的数据项中,这时实施SQL注入攻击只需要直接应用有效的SQL语法,而不需要进行任何“转义”。

SQL查询结构中最常见的注入点是ORDER BY子句。ORDER BY关键字接受某个列名称或编号,并根据该列中的值对结果集进行排序。用户经常使用这种功能对浏览器中的表进行排序。

例如,使用以下查询可以检索一个可排序的图书表:

img241

如果ORDER BY中的列名称title由用户指定,就没有必要使用单引号,因为用户提交的数据已经直接修改了SQL查询的结构。

img004  提示  在极少数情况下,用户提交的输入可能会指定WHERE子句中的列名称。由于这些输入也没有包含在单引号中,因此会导致与前面介绍的漏洞类似的问题。笔者也曾遇到一些以用户提交的参数作为表名称的应用程序。最终,有大量应用程序允许用户指定排序关键字(ASC或DESC),可能认为这并不会导致SQL注入攻击。

在列名称中查找SQL注入漏洞可能会相当困难。如果提交一个并非有效列名称的值,查询将导致错误。这意味着,无论攻击者提交路径遍历字符串、单引号、双引号或任何其他任意字符串, 应用程序都会返回相同的响应。因此,采用常用的自动模糊测试和手动测试技巧往往会遗漏某些漏洞。如果提交用于探查各种漏洞的标准测试字符串全部导致相同的响应,这本身并不表示出现任何错误。

img001  注解  本章后面部分介绍的一些传统的SQL注入防御措施并不能防范用户提交的列名称。使用预处理的语句或转义单引号也不能阻止这类SQL注入。因此,现代应用程序应尤其小心这类攻击。