当前位置: 主页 > 网络知识 > 网络安全 > 新型SQL截断攻击和防御方法

新型SQL截断攻击和防御方法

时间:2010-6-11来源:互联网 点击:

  SQL 注入漏洞

  接下来介绍存储过程,它可在验证了当前密码后更改用户帐户的密码(参见图 3)。

SQL 安全性: 新型 SQL 截断攻击和防御方法Figure3Changing a Password

CREATE PROCEDURE sp_setPassword
  @username varchar(25),
  @old varchar(25),
  @new varchar(25)
AS
DECLARE @command varchar(100)
SET @command=
  ‘update Users set password=‘‘‘ + @new +
  ‘‘‘ where username=‘‘‘ + @username +
  ‘‘‘ AND password=‘‘‘ + @old + ‘‘‘‘
EXEC (@command)
GO 

  快速浏览存储过程,会发现没有任何参数对单引号进行转义,这同样容易受到 SQL 注入攻击。攻击者可以传递几个特定的参数,并将 SQL 语句修改为:

update Users set password=‘NewP@ssw0rd‘
where username=‘admin‘ --‘ and password=‘dummy‘
结果是,无需实际密码即可设置管理员帐户(或任何已知的帐户)的密码。在 T-SQL 函数中,您可以通过使用 REPLACE 或 QUOTENAME 函数修复此代码。图 4 显示了使用 REPLACE 函数后正确的代码。

SQL 安全性: 新型 SQL 截断攻击和防御方法Figure4Using REPLACE to Avoid Injection

CREATE PROCEDURE sp_setPassword
  @username varchar(25),
  @old varchar(25),
  @new varchar(25)
AS
-- Declare variables.
DECLARE @command varchar(100)
-- Construct the dynamic SQL
SET @command=
  ‘update Users set password=‘‘‘ + REPLACE(@new, ‘‘‘‘, ‘‘‘‘‘‘) + ‘‘‘‘ +
  ‘ where username=‘‘‘ + REPLACE(@username, ‘‘‘‘, ‘‘‘‘‘‘) + ‘‘‘‘ +
  ‘ AND password = ‘‘‘ + REPLACE(@old, ‘‘‘‘, ‘‘‘‘‘‘) + ‘‘‘‘
-- Execute the command.
EXEC (@command)
GO

  可以看出,REPLACE 会将参数中所有单引号的出现次数都增加一倍。因此,如果攻击者传递相同的参数,该语句会变为:

update Users set password=‘NewP@ssw0rd‘
where username=‘admin‘‘--‘ and password=‘dummy‘
这样就不容易受到通常的 SQL 注入问题的影响了。

  通过截断进行修改

  如果您仔细留意上面显示的存储过程,您会发现 @command 变量只能存放 100 个字符,但当 25 个字符都为单引号时,这些字符的每个变量经过 REPLACE 函数处理后可返回 50 个字符。如果变量没有足够大的缓冲区,SQL Server 2000 SP4 和 SQL Server 2005 SP1 会自行截断数据。这就为攻击者提供了截断命令字符串的机会。

  在此例中,如果有人可以在 username=‘username‘ 表达式后截断命令,那么无需知道已知用户的当前密码,就可更改其帐户的密码。

  假设攻击者知道 administrator 用户名存在于 Web 应用程序中(这可以是任何用户帐户)。攻击者需要提供长度为 41 个字符的新密码,以使命令的长度足以被适当截断 — 之所以是 41 个字符,是因为在用于命令的 100 个字符中,27 个字符用于更新语句,17 个字符用于 where 子句,13 个字符用于“administrator”,2 个字符用于新密码前后的单引号。

  攻击者只能传递 25 个字符作为新密码。但他可以通过传递单引号避开这一限制,因为 REPLACE 函数会使单引号数量增加一倍。因此,通过传递 18 个单引号、1 个大写字母、1 个符号、2 个小写字母和 1 个数字,攻击者就可以截断 where username=‘administrator‘ 表达式后面的命令了。如果攻击者将 ‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘!Abb1 传递给 @new 参数,并将 administrator 作为用户名参数,那么 @command 就会变成:

update Users set password=
‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘!Abb1‘ where username=‘administrator‘

  图 5 使用 QUOTENAME 而非 REPLACE。上面的例子和此例的唯一不同在于,在上例中,开发人员为用户名、新密码和旧密码添加了单引号分隔符,而在此例中,由 QUOTENAME 函数添加。由于用户提供的数据没有变化,因此上例中使用的同一攻击字符串仍然可以被攻击者利用。图 6 是在中间层应用程序中编写的 C/C++ 函数的缩写版本,可实现相同功能。它容易受到相同的攻击。

SQL 安全性: 新型 SQL 截断攻击和防御方法Figure6Truncation Problems in C++

DWORD ChangePassword(char* psUserName, char* psOld, char* psNew)
{
  char* psEscapedUserName = NULL;
  char* psEscapedOldPW = NULL;
  char* psEscapedNewPW = NULL;
  char szSQLCommand[100];
  HRESULT hr=0;
  
  // Input Validation
  ...
  // Calculate and allocate the new buffer with length
  // userdatalen*2 + 1
  // Escape all single quotes with double quotes
  ...
  //Construct the query
  hr = StringCchPrintf(szSQLCommand, sizeof(szSQLCommand)/sizeof(char),
    "Update Users set password=‘%s’ where username=‘%s’"
    "AND password=‘%s’,
    psEscapedNewPW, psEscapedUserName, psEscapedOldPW);
  
  if (S_OK != hr)
  {
    // handle error cases
  }
  // Execute and return
}

SQL 安全性: 新型 SQL 截断攻击和防御方法Figure5Using QUOTENAME to Avoid Injection

CREATE PROCEDURE sp_setPassword
  @username varchar(25),
  @old varchar(25),
  @new varchar(25)
AS
-- Declare variables.
DECLARE @command varchar(100)
-- In the following statement, we will need 43 characters
-- to set an administrator password without knowing its current password.
-- 100 - 26 - 16 - 15 = 43 (26 for update stmt, 16 for where clause,
-- 15 for ‘administrator’). But @new only takes 25 characters, which we
-- can get around by using single quotes. So one can pass the following
-- parametes and set admin password. @new = 18 single quotes, 1 Capital
-- letter, 1 symbol, 2 small case letters, 1 digit
-- @username = administrator
-- @command becomes
-- update Users set password=‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘!Abb1’
-- where username=‘administrator’
SET @command= ‘update Users set password=‘ + QUOTENAME(@new,’’’’) +
‘ where username=‘ + QUOTENAME(@username,’’’’) + ‘ AND password = ‘ + QUOTENAME(@old,’’’’)
-- Execute the command.
EXEC (@command)
GO

站长资讯网
.
分页: [1] [2] [3] [4]
TAG: SQL攻击 防御
推荐内容最近更新人气排行
关于我们 | 友情链接 | 网址推荐 | 常用资讯 | 网站地图 | RSS | 留言