首页 > 开发 > 综合 > 正文

关于SQL注入,你应该知道的那些事

2024-07-21 02:47:18
字体:
来源:转载
供稿:网友
关于SQL注入,你应该知道的那些事

戴上你的黑帽,现在我们来学习一些关于SQL注入真正有趣的东西。请记住,你们都好好地用这些将要看到的东西,好吗?

SQL注入攻击因如下几点而是一种特别有趣的冒险:

  • 1.因为能自动规范输入的框架出现,写出易受攻击的代码变得越来越难——但我们仍然会写差劲的代码。
  • 2.因为你使用了存储过程或者ORM框架,你不一定很清楚的是(虽然你意识到SQL注入可能穿透他们,对吗) 我们在这些保护措施之下编写的代码依然是易受攻击的。
  • 3.通过精心设计的爬取web搜寻易受攻击站点的自动化工具使这类站点更易远程检测出来。而我们依旧在发布它们(译注:指站点)。

SQL注入攻击因一个非常恰当的原因而被保留在OWasp(Open Web application Security PRoject 开放Web应用安全项目)的十大隐患列表中第一位——它特别常见,非常容易利用,而且影响十分剧烈。一个很微小的注入风险经常就能使整个系统中的所有数据都被泄漏——而我将要展示给你如何运用大量不同的技术自己来这样做。

我几年前写《the OWASP Top 10 for .NET developers》时展示过如何防范SQL注入攻击,所以我不会专注在这些,这都是漏洞利用。受够了那些无聊的防御工具,让我们来攻击别的东西。

如果我们能攻破查询内容,你们的数据就都是我们的了

让我们对让SQL注入攻击成为可能的原因做一个快速概括。简而言之,这就是输入查询并解密数据。让我把所说的可视化给你:比如说你有一个包含有类似于“id=1”之类的字符串参数的URL,容纳后那个参数通过如下方式构造了一个SQL查询。

这整个URL可能和这个东西看起来很像:

这是挺基础的东西,而当你能掌控链接中的信息并改变传递给查询的值时会变得有趣。好了,把1变成2会给你另一个你期待的东西,但是如果你这样做呢?

http://widgetshop.com/widget/?id=1 or 1=1

那可能在数据库服务器中存留成这样的:

1SELECT * FROM Widget WHERE ID = 1 OR 1=1

这告诉我们的是数据没有被净化——在上例中ID应该只是一个整数但“1 OR 1=1”的值也被接受。更重要的是,因为数据只是简单地被添加到查询中,它能够改变语句的功能。这个查询将能够选择所有的记录而不是单个记录,因为”1=1″语句是恒成立的。

或者,我们可以通过把“or 1=1”改成“and 1=2”来强制页面不返回任何记录,因为它一直都不成立所以没有结果返回。在这两个可选的方案中我们能方便地确定程序是否受注入攻击威胁。

这是SQL注入攻击的本质——通过不被信任的数据巧妙地操纵查询的执行——而在开发者做这样子事时发生。

123query = "SELECT * FROM Widget WHERE ID = "+ Request.QueryString["ID"];//Execute the query...//执行查询...

当然他们做的是将不被信任的数据参数化,但本文中我不会过多叙述(如果想要了解防范措施,转回part one of my OWASP series),而将更多谈论如何发动攻击。

好了,于是背景部分介绍了如何展示SQL注入风险存在,但你能拿它怎么办?让我们开始探寻一些普遍的注入模式。

抽丝剥茧:合并基于查询的注入

让我们举个例子,表示我们想要返回一堆记录的页面,在这里是一个有一堆带有“TypeId”1的小东西的URL。像这样:

http://widgetshop.com/Widgets/?TypeId=1

页面上的结果会像这样:

我们会期待这个查询进入到数据库时变成像这样的东西:

1SELECT Name FROM Widget WHERE TypeId = 1

但是如果我们能应用我上述描绘的,也就是说我们可能能够给查询字符串中的数据添加SQL,我们可能会做出这样的东西:

http://widgetshop.com/Widgets/?TypeId=1 union all select name from sysobjects where xtype=’u’

然后它将产生一个如下的SQL查询:

1SELECT Name FROM Widget WHERE TypeId = 1 union all select name from sysobjects where xtype='u'

现在记好了系统对象表列举数据库中所有对象,而在这个例子中我们用 xtype “u” 来筛选这个表,换言之,用户表。

当一个注入风险存在的时候将会有如下的输出:

这就是叫做合并基于查询的注入攻击,就像我们刚才简单地像原始结果添加一项,它直接到了HTML输出中——简单吧!既然我们已经知道有一个数据表叫“User”,我们可以做这样的事:

http://widgetshop.com/Widgets/?TypeId=1 union all select passWord from [user]

如果数据表中“user”不被中括号括起来,考虑到“user”这个词在数据库看来有其他含义,SQL服务器会变得不易控制。不管怎样,这是它返回的:

当然,UNION ALL语句只在第一个SELECT语句和第二个有相同的字段时起作用。这很容易被发现,你只需试试一些“union all select ‘a’”,如果它查询失败就试试“union all select ‘a’, ‘b’”之类的,以此类推。根本上你是在不断猜测列数直到你构造的查询发挥作用。

我们可以继续研究这个方面并揪出各种数据,但还是学习下一种攻击方式吧。有时一个基于合并查询的注入不会发挥作用,与输入格式、查询中添加的数据甚至结果如何显示都有关。为了绕开它我们需要变得更有创造性一些。

让程序自己泄密:基于错误信息的注入

http://widgetshop.com/widget/?id=1 or x=1

等一下,这不是一个合法的SQL语句,那个“x=1”不会被处理,至少在没有一个叫做x的列时不会被处理。那么它不会抛出一个异常吗?严格地说,事实上你将会看到像这样的异常:

这是一个asp.net的错误,而其他的框架也有类似的样式。但是重要的是这些错误信息暴露了内部的实现方式,换言之,这告诉我们数据库中没有叫做“x”的字段。为什么这很重要?从根本上说,这是因为你一旦确立了一个应用程序在泄漏SQL异常,你就可以做这样的事:

http://widgetshop.com/widget/?id=convert(int,(select top 1 name from sysobjects where id=(select top 1 id from (select top 1 id from sysobjects where xtype=’u’ order by id) sq order by id DESC)))

这有好多需要吸收理解,我等会将回来详细解释。更重要的是通过那条语句你能够在浏览器中得到这样的结果:

现在我们得到了,我们已经发现那数据库里有一个表单叫做“Widget”。你将经常能看到这中注入攻击因依赖于数据库内部的错误而被称作“基于错误信息的注入”。让我们解构URL中的这个查询:

12345678convert(int, (select top 1 name from sysobjects where id=(select top 1 id from (select top 1 id from sysobjects where xtype='u' order by id) sq order by id DESC)))
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表