编者:有时候我会碰到一些叫我瞠目结舌的事.比如这个文章,我发英文原文在我blog上,晚上来的时候居然发现有人把它翻译了.....

翻译:blcakwell (plmm:)

我的一个客户要求我们检查一下给他们的职员和顾客用的内网(企业网)。
这也是大范围安全检测的一部分。尽管对于sql注入的一般概念比较熟悉,
实际上,我们以前没有用过这种方法渗透网络。这次我们完全成功
的进行了渗透,我希望把过程图文并茂的重现。

“sql 注入未核实性/不稳健性用户输入脆弱性的一个子集
缓冲誉出是另一个不同的子集),
主要思路是确使数据库运行不应该被运行的sql语句,
如果冒然运行了这些语句,其产生的后果是让人惊讶的。(水平有现,没有把作者意思完全写出来)


/*无太大关系,幽默的类比*/

有很多关于sql注入的文章,包含一些,甚至更多的细节。
本文主要说明合理的发现问题比攻击的过程要重要。


目标网站
客户的数据库就在上面,但是,我们没有进入之前我们没有任何关于它的源代码。
这是一次没有把握的攻击,简单的测探之后显示服务器是微软的iis 6.0运行着asp
并且表明数据库是微软的sql服务器,我们相信这些技术几乎应用于任何sql服务器支持的网络

登陆页面有着传统的用户名”“密码表格单,还有一个电邮给我”“我的密码的连接;
后者结果让我们攻入了这个服务器。


当填入一个邮件地址,系统在用户数据库里面这个地址,然后给这个地址发邮件。
而我的邮件地址没有发现,所以不会给我发任何东西。

所以,第一步的测试(sql -ish 这个-ish不清楚)是把填入表单的电邮地址数据加上个单引号(')
目的在于看看是否能构成sql语句字面上的不稳定性。当提交这个有着单引号电邮地址的表单,
我们得到一个500 错误(服务器错误),这表示我们的输入的语法不正确的数据被系统运行了(进行了解析

)。

让我们来推测一下系统是怎么运行我们输入的数据的,情况如下:
         select 什么什么什么(一般是表里面的列)注入  //我们不知道是什么
         from 哪个哪个表  //我们也不知道是什么
         where 什么什么='$email';  //这是我们的推测,具体是不是我们也不知道。
这个$email是用户从表单提交来的,并且更多的查询由双引号设置一个字符串,我们不知道
上面的什么什么什么哪个哪个表的具体名字,但是我们知道它们的性质,所以我们
等会儿能有些合理的猜测。

我们输入什么什么@什么什么'”--注意最后的引号--这个产生出sql语句结构
         select 什么什么
         from 哪个哪个表
         where 什么什么='什么什么@什么什么'';
单这个语句被执行,sql解析发现多余的引号,然后因为句法错误而中断了。而把错误到底能多清楚明白
的显示给用户看,要取决于系统内部错误恢复的过程。但是,一般不同于显示电邮地址未知
如果错误反映出我们的输入导致发现它完全具有不稳定性,那么这个系统攻击时机就成熟了。


因为我们填入的数据出现在where这个从句那里,让我们来以slq合法的方式改变一下这个从句的属性
看看会发生什么。通过输入“anything' or 'x'='x,” slq的结果如下:
      select 什么什么什么
      from 哪个哪个表
      where 什么什么什么='anything' or 'x'='x';

由于系统不会象人一样思考这些查询---仅仅是构成语句--我们用的引号就把where从句的一个
部件结合成两个部件,并且那个'x'='x'肯定是合法的不管第一个从句是什么( 有一个更好的
让系统肯定是合法的方法,等下我们将介绍)

不象真实查询那样,每次应该返回一个项值,将会返回数据库的每个项值。唯一能弄清楚
系统在这样的环境下将有什么反映的方法就是努力的去试。试了之后,我们可能得到如下信
息:
     你的登陆信息已经发送到什么什么@什么什么

我们最好的猜测而且有效果的输入能让查询的第一个记录能返回。而某人会收到一封密码遗失
信,这将让他惊讶恐惧。

我们现在知道我们有能力控制查询为我们目的服务,虽然我们还不知道查询结构的更多信息。
但是我们已经通过我们不同的输入看到三种不同的结果。
  1你的登陆信息已经通过电邮发送
  2你的电邮地址无法识别
  3 服务器错误
 
前两个结果是正确的sql形式,而最后一个是不正确的,而用这个特性,当我们设法试着去猜
测查询的结构
是非常有用的。

先验式(纲要)映射
第一步我们必须猜测出一些表内的域名;必须合理的确定查询包含电邮地址密码
并且可能存在美国电邮地址或者用户id”或者电话号码。我们最好执行 show table
命令,可是我们不知道表的名字。然而没有太多方式让我们等到输出的结果(原文为比喻)。

所以我们将一步一步来,在每一步,我们将运用我们所知道到的来显示整个查询,用我们自己这小部分来
作特别的显示,我们知道查询的尾部是一个电邮地址,所以,我们可以把电邮做为表内域名来猜测一下。
     select 什么什么什么
     from 那个那个表
     where 什么什='x' and email is null; --';
目的是用一个合适的域名(电邮)去构成查询,出是否sql合法或者不合法。我们不关心电邮地址是不是
匹配(这也是我们为什么用空变量 'x'的原因),-- 这个表示sql注释的开始。这是一种有效的方式
去掉最后的引号而且不用理会是不是存在匹配的问题。

如果我们得到服务器错误,这就意味着sql句法错误很有可能是由于不正确的域名导致的。如果我们能得到
然后正确的反映或者结果,那么我们就正确地猜测到名字了。这样我们会得到电邮未知或者密码已经
发送的结果。

注意,我们用and而不是or去注入,在sql先验性映射阶段,我们不是考虑猜到某个具体的电邮地址,
我们也不希望很多用户收到由系统发送的诸如你的密码这样的电邮。这样将会使大家警觉。
通过用and去注入一个电邮地址,即使电邮地址不正确,我们也能确定查询总是会返回0行(也就是
什么也查不到)

当我们提交后系统给了我们一个电邮地址未知的反映。所以现在我们知道电邮地址是存放在以电邮为
域名的这一列了。如果这个方法不起作用,我们可以试着用"电邮_地址"或者 "邮件"或者类似的名字
去试试。当然这要试很多次。

接下来我们将猜测其他的名字:密码,用户号,姓名等等。所有这些我们可以一次做掉。只要不是
服务器错误的结果,我们就正确的猜测到了。


       selcet 什么什么什么
        from 那个那个表
       where email = 'x' and userid is null; --';

这个的结果,我们会发现几个正确的域名
  1:邮件
  2:密码
  3:登陆号
  4:全名

当然我们等下会进一步了解,但是我们现在还没有过多的发现,因为我们不知道表的名字,
怎么样才能知道表的名字呢?

到表的名字
系统的查询是在表里面进行,但是我们不知道表的名字,有几种方式去弄清楚表的名字。
首先我们用subselect

格式如下:
   select count(*) from 哪个哪个表

将返回表内记录的数量,如果表名不存在,那么这个语句不生效。我们可以用以下语句去弄清楚
表名:
   
   select 电邮,密码,登陆号,全名
   from   那个哪个表
   where email = 'x' and 1=(select count(*) from  表名); --';

我们并不关心到底有多少记录,只关心表名有或者没有。经过几次猜测我们能确信“member
s”
数据库里面一个表名。但是它和我们的查询有关系吗?为了弄清楚,我们用table.field来试试,
这个表达式只对查询有关系的部分起作用,即表名是存在的和查询没有关系那么不起作用。

   select email, passwd, login_id, full_name
    from members
   where email = 'x' ail is null; --';

当返回电邮未知,这就证实了我们的猜测是正确的,也弄清楚表members和我们需要的是有联系的。
等下我们将看到这个方法的重要性。


寻用户名
我们已经知道members表的一些情况,但是我们只知道一个用户名,就是我们以前测试时系统发送的你的
密码邮件的那个用户,但是我们没有收到这个邮件。我们需要猜测更多的用户名,以便得到更多的信息。

首先,我们去网页上看看,在关于我们或者这样的页面,往往会列出些相关的用户名。
并且往往还列出电邮地址。总之这里会给我们很多线索,为我们的渗透提供方便。

我们做一个电邮名字或者人称全名或者其他有关信息的查询,每次我们用like名字支持的通配符%来进行。
        select email,passwd,login_id,full_name
        from members
        where email ='x' or full_name like '%Bob%';

记住,即使有很多个bob我们也只能得到一个bob的信息,这是like的精确匹配的问题。
最后,我们仅仅需要个正确的电邮地址就能知道我们想要的。

暴力破解密码
有一点可以肯定,在主登陆页面进行暴力破解。系统会设法给予识别和限制。可能关闭登陆页面,
锁定帐户,或者其他方式,这些会阻碍我们的破解。但是,因为它存在输入不没有过滤掉有害成分。
所以,我们有另外一条路饶过这种保护。

我们直接输入包含电邮名和密码的查询而不是仅仅做密码测试。看下面这个例子,我们用“bob@example

作为我们查询的电邮名来猜测密码。
   SELECT email, passwd, login_id, full_name
   FROM members
   WHERE email = 'bob@example' AND passwd = 'hello123';

这是个很清楚而正确的sql语句,因此我们不会看到任何服务器错误,而当我们看到你的密码已经电邮给你

的时候,那么我们就到了密码。这个信息泄露出密码是正确的。而我们的确知道了密码。

当然,我们可以编写个perl脚本自动的进行,在我们实际去做这些事情之前,我们来看点别的。


数据库是可读写的
到目前为止,我们除了查询数据库之外没有做其他的事情,而即使一个select是只读的,但是不表示
sql也是,sql用分号(;)表示一个语句的结束。但是如果输入不能正确的过滤的话,那么没有什么能
防止我们在查询结尾加上不相关连的我们自己的命令。一个可怕的例子如下:
   SELECT email, passwd, login_id, full_name
  FROM members
WHERE email = 'x'; DROP TABLE members; --';

在第一部分我们给了一个空的电邮地址---'x'---我们不用管它的返回,我们来看看我们的不相关连的
命令起到什么作用,显然是要完全删除整个members表。这很可怕。

以上表明,我们不仅仅能运行单个sql命令,而且我们还能修改数据库。我能保证这点:)

加入一个新成员

我们已经知道members表的部分结构,这好象存在一种可能的方式加入一个新记录到表中,如果起作用。
我们将能很简单的用新加入的数据登陆。

不用惊讶,加入几行sql命令就可以了,但是没成功之前,我们加入的命令还是存在偶然性的。
  SELECT email, passwd, login_id, full_name
  FROM members
  WHERE email = 'x';
        INSERT INTO members ('email','passwd','login_id','full_name')
        VALUES ('steve@unixwiz','hello','steve','Steve Friedl');--';

即使我们实际上知道表的名字和域名,但是有几件事情可能阻碍我们成功的进行攻击。

1:在网站上的登陆的地方,我们很可能没有足够的地方填写我们的命令
(尽管可以通过脚本程序来实现,但是这不是很方便)
2:网站管理员可能设置了不允许用insert命令向members表加入数据
3:毫无疑问members表内还有其他域,可能需要初始数据值,那么会导致insert失效。
4:即使我们设法插入新记录,对我们没提供数据值的域系统可能不会自动插入null(空值)。
5:一个合法的“member”除了是members表的一个记录以外,可能和其他的表也有关系,那么
单独加入一个表不会有什么效能。

这些情况,主要是4或者5我们不能十分确定--因为,我们去主登陆页面输入上面的用户名+密码
,会返回一个服务器错误。这表明我们加入的数据没有成功。没有处理正确。

一个可能的方法是去猜测其他的域,但是这是一个长而乏味的过程,我们将要猜测各种各样的域名
很难想象系统是怎么组织这些结构的。

所以,我们试着去看看另一个不同的方法。

电邮给我个密码

我们意识到即使我们不能往members表里面加入新的记录,但是我们能修改一个存在的记录。
这样我们将能够进入。

从上面步骤,我们知道bob@example是系统上的一个帐户。我们用sql注入把它更新成我们
的电邮地址。
        SELECT email, passwd, login_id, full_name
  FROM members
WHERE email = 'x';
      UPDATE members
      SET email = 'steve@unixwiz'
      WHERE email = 'bob@example';

运行了之后,我们看到无法识别你的电邮地址,这是预料中的,由于我们输入的是个空电邮地址(那个
email='x';) ,而更新的电邮地址我们没有注册,这个命令只是悄悄地执行而已。

我们去我丢失了密码的连接上更新我们的邮件地址,不久后我们将收到一个电邮:
     From: system@example
     To: steve@unixwiz
     Subject: Intranet login

此邮件发送给你的登陆信息。


Your User ID is: bob
Your password is: hello

现在要做的事情就是去登陆了。这个方法比我们用insert来创建一个可能受限制的用户要优越许多。

我们发现企业网站很全面,往往包含所有用户的列表。所以我们有理由相信其他用windows网络的企业
也可能这样。可能他们中的某一些在两个不同的地方用同一个密码。这将让我们很容易得到任何企业网的
密码。要是我们放一个open pptp vpn port (什么东西?不懂)到防火墙上,那么可以直接用这种方式进入。

我们还做了几个帐户的测试但是没有成功。我们不知道是否是密码不对或者是企业网的帐
户名不同于windows的帐户名。但是我们认为用自动工具来做的话将是容易的事情。

原文以下内容为作者介绍附加知识和深入知识,攻击实例到次为止。

/*  由于网络问题,编辑附加之后不能更新,bbs好象不稳定。所以发在后面。
到此虽然全文还没有翻译完,不过攻击示例部分已经翻译完成,希望对大家
有些须帮助。

我基本上是按直译来翻译的,不敢过多的改原作者的文法结构。他是一句话
我也尽量一句话。所以看起来有点古怪。此外我对sql和入侵手法不是很懂,
也许有的地方没有精确的翻译清楚,所以我更决定保持直译以免变样。

如有不足欢迎大家批评指正。*/

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。