| 关键词: QUOTENAME sysname nbsp Declare characters newpassword command 缓冲区 oldpassword password |
如果分配给变量的任何动态 Transact-SQL 比为该变量分配的缓冲区大,那么它将被截断。如果攻击者能够通过将意外长度的字符串传递给存储过程来强制执行语句截断,则该攻击者可以操作该结果。例如,以下脚本创建的存储过程容易受到由截断启用的注入攻击。 CREATE PROCEDURE sp_MySetPassword @loginname sysname, @old sysname, @new sysname AS -- Declare variable. -- Note that the buffer here is only 200 characters long. DECLARE @command varchar(200) -- Construct the dynamic Transact-SQL. -- In the following statement, we need a total of 154 characters -- to set the password of 'sa'. -- 26 for UPDATE statement, 16 for WHERE clause, 4 for 'sa', and 2 for -- quotation marks surrounded by QUOTENAME(@loginname): -- 200 – 26 – 16 – 4 – 2 = 154. -- But because @new is declared as a sysname, this variable can only hold -- 128 characters. -- We can overcome this by passing some single quotation marks in @new. SET @command= 'update Users set password=' + QUOTENAME(@new, '''') + ' where username=' + QUOTENAME(@loginname, '''') + ' AND password = ' + QUOTENAME(@old, '''') -- Execute the command. EXEC (@command) GO 通过向 128 个字符的缓冲区传递 154 个字符,攻击者便可以在不知道旧密码的情况下为 sa 设置新密码。 EXEC sp_MySetPassword 'sa', 'dummy', '123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012''''''''''''''''''''''''''''''''''''''''''''''''''' 因此,应对命令变量使用较大的缓冲区,或直接在 EXECUTE 语句内执行动态 Transact-SQL。使用 QUOTENAME(@variable, '''') 和 REPLACE() 时的截断 如果 QUOTENAME() 和 REPLACE() 返回的字符串超过了分配的空间,该字符串将被自动截断。以下示例中创建的存储过程显示了可能出现的情况。 CREATE PROCEDURE sp_MySetPassword @loginname sysname, @old sysname, @new sysname AS -- Declare variables. DECLARE @login sysname DECLARE @newpassword sysname DECLARE @oldpassword sysname DECLARE @command varchar(2000) -- In the following statements, the data stored in temp variables -- will be truncated because the buffer size of @login, @oldpassword, -- and @newpassword is only 128 characters, but QUOTENAME() can return -- up to 258 characters. SET @login = QUOTENAME(@loginname, '''') SET @oldpassword = QUOTENAME(@old, '''') SET @newpassword = QUOTENAME(@new, '''') -- Construct the dynamic Transact-SQL. -- If @new contains 128 characters, then @newpassword will be '123... n -- where n is the 127th character. -- Because the string returned by QUOTENAME() will be truncated, -- it can be made to look like the following statement: -- UPDATE Users SET password ='1234. . .[127] WHERE username=' -- other stuff here SET @command = 'UPDATE Users set password = ' + @newpassword + ' where username =' + @login + ' AND password = ' + @oldpassword; -- Execute the command. EXEC (@command) GO 因此,以下语句将把所有用户的密码都设置为在前面的代码中传递的值。 EXEC sp_MyProc '--', 'dummy', '12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678' 使用 REPLACE() 时,可以通过超出分配的缓冲区空间来强迫字符串截断。以下示例中创建的存储过程显示了可能出现的情况。 CREATE PROCEDURE sp_MySetPassword @loginname sysname, @old sysname, @new sysname AS -- Declare variables. DECLARE @login sysname DECLARE @newpassword sysname DECLARE @oldpassword sysname DECLARE @command varchar(2000) -- In the following statements, data will be truncated because -- the buffers allocated for @login, @oldpassword and @newpassword -- can hold only 128 characters, but QUOTENAME() can return -- up to 258 characters. SET @login = REPLACE(@loginname, '''', '''''') SET @oldpassword = REPLACE(@old, '''', '''''') SET @newpassword = REPLACE(@new, '''', '''''') -- Construct the dynamic Transact-SQL. -- If @new contains 128 characters, @newpassword will be '123...n -- where n is the 127th character. -- Because the string returned by QUOTENAME() will be truncated, it -- can be made to look like the following statement: -- UPDATE Users SET password='1234…[127] WHERE username=' -- other stuff here SET @command= 'update Users set password = ''' + @newpassword + ''' where username=''' + @login + ''' AND password = ''' + @oldpassword + ''''; -- Execute the command. EXEC (@command) GO 与 QUOTENAME() 一样,可以通过声明对所有情况都足够大的临时变量来避免由 REPLACE() 引起的字符串截断。应尽可能直接在动态 Transact-SQL 内调用 QUOTENAME() 或 REPLACE()。或者,也可以按如下方式计算所需的缓冲区大小。对于 @outbuffer = QUOTENAME(@input),@outbuffer 的大小应为 2*(len(@input)+1). 。使用 REPLACE() 和双引号时(如上一示例),大小为 2*len(@input) 的缓冲区便已足够。 以下计算涵盖所有情况: While len(@find_string) > 0, required buffer size = round(len(@input)/len(@find_string),0) * len(@new_string) + (len(@input) % len(@find_string))使用 QUOTENAME(@variable, ']') 时的截断 当 SQL Server 安全对象的名称被传递给使用 QUOTENAME(@variable, ']') 形式的语句时,可能发生截断。以下代码显示了这一可能性。 CREATE PROCEDURE sp_MyProc @schemaname sysname, @tablename sysname, AS -- Declare a variable as sysname. The variable will be 128 characters. -- But @objectname actually must accommodate 2*258+1 characters. DECLARE @objectname sysname SET @objectname = QUOTENAME(@schemaname)+'.'+ QUOTENAME(@tablename) -- Do some operations. GO 当您串联 sysname 类型的值时,应使用足够大的临时变量来保存每个值的最多 128 个字符。应尽可能直接在动态 Transact-SQL 内调用 QUOTENAME()。或者,也可以按上一部分所述来计算所需的缓冲区大小。 |
|
声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系
[邮箱地址] 删除
|