SQL 注入是一种攻击方式,在这种攻击方式中,恶意代码被插入到字符串中,然后将该字符串传递到 SQL Server 的实例以进行分析和执行。任何构成 SQL 语句的过程都应进行注入漏洞检查,因为 SQL Server 将执行其接收到的所有语法有效的查询。一个有经验的、坚定的攻击者甚至可以操作参数化数据。
CREATEPROCEDURE sp_MySetPassword @loginname sysname, @old sysname, @new sysname AS -- Declare variable. -- Note that the buffer here is only 200 characters long. DECLARE@commandvarchar(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 设置新密码。
CREATEPROCEDURE sp_MySetPassword @loginname sysname, @old sysname, @new sysname AS -- Declare variables. DECLARE@login sysname DECLARE@newpassword sysname DECLARE@oldpassword sysname DECLARE@commandvarchar(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
CREATEPROCEDURE sp_MySetPassword @loginname sysname, @old sysname, @new sysname AS -- Declare variables. DECLARE@login sysname DECLARE@newpassword sysname DECLARE@oldpassword sysname DECLARE@commandvarchar(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
当 SQL Server 安全对象的名称被传递给使用 QUOTENAME(@variable, ']') 形式的语句时,可能发生截断。以下代码显示了这一可能性。
CREATEPROCEDURE 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