通过截断进行 SQL 注入
图 7 显示了相同代码的另一变体,但可使用单独的变量进行修复。可以看出,此代码将转义后的字符串存放在单独的变量中,而且 @command 有足够的缓冲区来存放整个字符串。@escaped_username、@escaped_oldpw 和 @escaped_newpw 被声明为 varchar(25),但如果 @username、@old 和 @new 中的所有字符是 25 个单引号,则它们需要存放 50 个字符。这就为截断已转义的字符串创造了机会。
Figure7Using Seperate Variables to Avoid Injection
CREATE PROCEDURE sp_setPassword
@username varchar(25),
@old varchar(25),
@new varchar(25)
AS
-- Declare variables.
DECLARE @escaped_username varchar(25)
DECLARE @escaped_oldpw varchar(25)
DECLARE @escaped_newpw varchar(25)
DECLARE @command varchar(250)
SET @escaped_username = REPLACE(@username, ‘‘‘‘, ‘‘‘‘‘‘)
SET @escaped_oldpw = REPLACE(@old, ‘‘‘‘, ‘‘‘‘‘‘)
SET @escaped_newpw = REPLACE(@new, ‘‘‘‘, ‘‘‘‘‘‘)
SET @command =
‘update Users set password=‘‘‘ + @escaped_newpw + ‘‘‘‘ +
‘ where username=‘‘‘ + @escaped_username + ‘‘‘‘ +
‘ AND password = ‘‘‘ + @escaped_oldpw + ‘‘‘‘
EXEC (@command)
GO
攻击者可以传递 123...n‘ 作为新密码,其中 n 是第 24 个字符,使 @escaped_newpw 也成为 123...n‘(REPLACE 函数返回的第二个单引号字符会被截断),使最后的查询如下所示,攻击者可以通过用户名字段注入代码,从而利用此查询:
update users set password=‘123...n‘‘
where username=‘<SQL Injection here using Username>
这种代码模式更危险,因为这为注入 SQL 代码(而不仅仅是截断现有 SQL)提供了机会。
图 8 提供了使用 QUOTENAME 函数而非 REPLACE 的同一变体的另一个例子。由于 QUOTENAME 函数要添加分隔符,因此负载会有所不同,但仍旧容易受到 SQL 注入攻击。
Figure8Using QUOTENAME with Seperate Variables
ALTER PROCEDURE sp_setPassword
@username varchar(25),
@old varchar(25),
@new varchar(25)
AS
-- Declare variables.
DECLARE @quoted_username varchar(25)
DECLARE @quoted_oldpw varchar(25)
DECLARE @quoted_newpw varchar(25)
DECLARE @command varchar(250)
-- In the following statements, all the variables can only hold
-- 25 characters, but quotename() will return 52 characters when all
-- the characters are single quotes.
SET @quoted_username = QUOTENAME(@username, ‘‘‘‘)
SET @quoted_oldpw = QUOTENAME(@old, ‘‘‘‘)
SET @quoted_newpw = QUOTENAME(@new, ‘‘‘‘)
-- By passing the new password as 123...n where n is 24th character,
-- @quoted_newpw becomes ‘123..n
-- Observe carefully that there is no trailing single quote as it gets
-- truncated.
-- So the final query becomes something like this
-- update users set password=‘123...n where username=‘ <SQL Injection
-- here using Username>
SET @command= ‘update Users set password=‘ + @quoted_newpw +
‘ where username=‘ + @quoted_username +
‘ AND password = ‘ + @quoted_oldpw
EXEC (@command)
GO
在此例中,代码将分隔后的字符串存放在单独的变量中,而且 @command 有足够的缓冲区来存放整个命令字符串。正如上例所示,问题在于被引用的变量 @quoted_username、@quoted_oldpw 和 @quoted_newpw。它们都被声明为 varchar(25),但如果 @username、@old 和 @new 中的所有字符是 25 个单引号,则它们需要存放 52 个字符。(QUOTENAME 还将添加开始和结束的分隔符。)这就为攻击者截断已分隔的字符串创造了机会。
攻击者可以传递 123...n(其中 n 是第 24 个字符)作为新密码,使 @escaped_newpw 也成为 ‘123...n(开始的单引号由 QUOTENAME 添加),使最后的查询如下所示,攻击者可以通过用户名字段注入代码,从而利用此查询:
update users set
password=‘123...n where
username=‘ <SQL Injection here using Username>
图 9 是 C/C++ 中此代码的缩写版本,可实现相同功能。它同样容易受到相同攻击。
Figure9Variable Truncation Issues in C++
DWORD ChangePassword(char* psUserName, char* psOld, char* psNew)
{
char szEscapedUserName[26];
char szEscapedOldPW[26];
char szEscapedNewPW[26];
char szSQLCommand[250];
// Input Validation
// Escape User supplied data
Replace(psUserName, "’", "’’", szEscapedUserName,
sizeof(szEscapedUserName));
Replace(psPassword, "’", "’’", szEscapedOldPW,
sizeof(szEscapedOldPW));
Replace(psPassword, "’", "’’", szEscapedNewPW,
sizeof(szEscapedNewPW));
// Construct the query
StringCchPrintf(szSQLCommand, sizeof(szSQLCommand)/sizeof(char),
"Update Users set password=‘%s’ where username=‘%s’"
"AND password=‘%s’,
szEscapedNewPW, szEscapedUserName,szEscapedOldPW);
// Execute and return
}
.
分页: [1] [2] [3] [4]
- 上一篇:SQL Server 2000的安全配置
- 下一篇:SQL Server安全基础
TAG: SQL攻击 防御