前言 #
本文详细的介绍了Sql Server安全基础,包括环境搭建,T-sql语法,sqlserver用户权限,以及sqlserver注入的方法和提权方式。
Microsoft SQL Server(微软结构化查询语言服务器),也叫Mssql,是由美国微软公司所推出的关系型数据库。默认端口号为1433
常见版本如下
版本 |
年份 |
发布名称 |
8.0 |
2000年 |
SQL Server 2000 |
8.0 |
2003年 |
SQL Server 2000 64-bit版本 |
9.0 |
2005年 |
SQL Server 2005 |
10.0 |
2008年 |
SQL Server 2008 |
10.25 |
2009年 |
SQL Azure |
10.50 |
2010年 |
SQL Server 2008 R2 |
11.0 |
2012年 |
SQL Server 2012 |
12.0 |
2014年 |
SQL Server 2014 |
13.0 |
2016年 |
SQL Server 2016 |
14.0 |
2017/09/29 |
SQL Server 2017 |
15.0 |
2019/11/4 |
SQL Server 2019 |
Mssql常用场景
- 学校
- 政府
- OA
- 棋牌游戏
- 人事考试网站
常见搭配:asp/aspx+sqlserver
一、SQL Server基础 #
1. SQL Server 2012安装启动 #
- win2012
- sqlserver 2012
安装
下载地址:
,如下复制下载链接,使用迅雷打开进行下载接下来可以进行安装,整个安装过程还是比较简单,可参考:
这里我使用的混合模式进行身份验证
启动
开始-搜索 " ssms",然后双击“Microsoft SQL Server Management Studio”
其中服务器名称如果是在本地登录则可以输:127.0.0.1,localhost,. ,计算机名。远程登录则输:服务器ip,端口。
输入账号 sa ,密码为安装时设定的,点击连接
如下,成功连接
navicat远程连接 #
- 版本:Navicat Premium16
sqlserver 2012安装完后就默认允许远程连接
主机填写 ip,端口
Navicat并没有初始化安装sqlncli, 所以连接的时候会报没有默认驱动,点击是进行安装
安装之后就能正常连接了
2. SQL Server概念 #
数据库的组成 #
如下,我们新建一个数据库,右键新建数据库
输入数据库名称,然后改下数据库文件的存储路径
新建完后,能看到多出来了两个文件
在sqlserver中:
- 数据库以文件的形式存在
- 数据库由文件和文件组组成
数据库文件
- 主要数据文件:存放数据和数据库的初始化信息。每个数据库有且只能有一个主要数据文件。.mdf结尾
- 次要数据文件:存放除了主要数据文件以外的所有数据文件。次要数据文件不是必须的,可以没有。如果有的话,可以是一个,也可以有多个。.ndf扩展名
- 事务日志文件:存放用户回复数据库的所有日志信息。每个数据库至少要有一个日志文件,也可以有多个。.ldf结尾
文件组
文件组:是数据库文件的一种逻辑管理单位,它将数据库文件分成不同的文件组,方便对文件的分配和管理。分为两种类型
- 主文件组 Primary :主要数据文件和没有明确指派给其他文件组的文件。
- 用户自定义的文件组:Create DataBase或 alter database 语句,fileGroup关键字指定的文件组
设计原则:
- 文件只能是一个文件组的成员
- 文件或文件组不能由一个以上的数据库使用
- 白志不能作为文件组的一部分。
数据库中常用对象 #
在一个数据库中又存在很多类似菜单栏一样的东西,我们可以称为数据库中的对象
在数据库中新建表,如下,然后输入表的字段名,ctrl+s保存然后输入表的名字“student”
然后刷新
就可以看到刚才新建的表,dbo.表名
数据库中的常用对象含义如下:
- 表:包含数据库中所有数据的对象,行和列组成。用于组织和存储数据。
- 字段:表中的列,一个表可以有多个列。数据类型(决定了该字段存储哪种类型的数据),大小(长度)
- 视图:表(虚拟表)一张或多张表中导出的表,用户查看数据的一种方式,结构和数据是建立在对表的查询基础之上的。
- 索引:为了给用户提供一种快速访问数据的途径,索引是依赖于表而建立,检索数据时,不用对整个表进行扫描,可以快速找到所需的数据。
- 存储过程:是一组为了完成特定功能的SQL语句的集合(可以有查询、插入、修改、删除),编译后,存储在数据库中,以名称进行调用,当调用执行时,这些操作就会被执行。
- 触发器:在数据库中,属于用户定义的SQL事务命令集合,针对于表来说,当对表执行增删改操作时命令就会自动触发而去执行。
- 约束:对数据表的列,进行的一种限制。可以更好的规范表中的列。
- 缺省值:对表中的列可以指定一个默认值,当进行插入时,如果没有为这个列插入值,那么就会自动以预先设置默认值进行自动补充。
默认库介绍 #
SQLServer数据库有6个默认的库,分别是4个系统数据库:master 、model 、msdb 、tempdb,和2个实例数据库:ReportServer、ReportServerTempDB。
- master数据库:master数据库控制SQL Server的所有方面。这个数据库中包括所有的配置信息、用户登录信息、当前正在服务器中运行的过程的信息。
- model数据库:model数据库是建立所有用户数据库时的模板。当你建立一个新数据库时,SQL Server会把model数据库中的所有对象建立一份拷贝并移到新数据库中。在模板对象被拷贝到新的用户数据库中之后,该数据库的所有多余空间都将被空页填满。
- msdb数据库:msdb数据库是SQL Server中的一个特例。如果你查看这个数据库的实际定义,会发现它其实是一个用户数据库。不同之处是SQL Server拿这个数据库来做什么。所有的任务调度、报警、操作员都存储在msdb数据库中。该库的另一个功能是用来存储所有备份历史。SQL Server Agent将会使用这个库。
- tempdb数据库:tempdb数据库是一个非常特殊的数据库,供所有来访问你的SQL Server的用户使用。这个库用来保存所有的临时表、存储过程和其他SQL Server建立的临时用的东西。例如,排序时要用到tempdb数据库。数据被放进tempdb数据库,排完序后再把结果返回给用户。每次SQL Server重新启动,它都会清空tempdb数据库并重建。永远不要在tempdb数据库建立需要永久保存的表。
3. T-SQL语言 #
在mysql中使用sql对数据库进行操作,而在sqlserver中使用的是Transaction-SQL,简称T-SQL。T-SQL是在sql基础之上的一种数据库编程语言
创建数据库 #
- 用T-sql新建一个名为TestNewBase的数据库,语句如下
这个过程其实和图形化新建数据库是一样的
创建新的数据库为什么要 use master?
master:系统数据库,它记录了SOL Server系统的所有系统级信息,还记录了所有其他数据库文件的位置,及SQL Server的初始化信息等。
创建表 #
在TestNewBase中新建两张表,新建表的时候要同时指明字段信息
插入数据 #
使用insert在users表中插入数据
以窗口的形式查看表中的数据
基础语法总结 #
- T-sql和sql一样,单词不区分大小写
- 注释符: -- 和 /*......*/
- 语句不强制以分号结尾
数据操作类
select --查询 insert --插入 DELETE --删除 UPDATE --更新
数据定义类
create table --创建表 drop table --删除表 alert table --修改表结构
- 查询所有数据库
- 获取当前数据库所有表名
- 获取表中所有字段名
Select Name FROM SysColumns Where id=Object_Id('users');
- 查询表中的所有数据
select * from users
4. sqlserver权限 #
sqlserver中的权限控制被分成服务器和数据库两个级别,一个服务器可以包含多个数据库。
服务器级别的权限可以让我们控制登录、服务器资源操作等,而数据库级别的权限可以让我们对具体的表/视图/数据等数据库内资源进行操作控制。
- 在服务器级别,SQL server为我们提供了:服务器角色、登录名和安全对象。
服务器默认有10个登录名(安装时选择的功能不同,数量也会有差别),其中sa默认拥有服务器角色sysadmin(最高权限)和public。(可以把角色理解为权限的集合,如windows中的组)
- 在数据库级别,SQL server为我们提供了:数据库角色、用户名、架构和安全对象。
新建一个数据库默认拥有10个角色,其中public角色是每个数据库用户必须拥有的,不可撤销;db_owner角色表示数据库的拥有者(默认被dbo账户拥有),对这个数据库拥有至高的权力,相当于服务器角色中的sysadmin。
新建一个数据库,默认拥有四个用户,其中dbo账户拥有数据库角色db_owner,也就是说拥有了数据库的至高操作权力
当我们进行远程连接sqlserver时,需要提供服务器级别的登录名来登录到服务器,如下面的sa用户
新建用户并赋予权限 #
如何给服务器新建一个类似于sa的用户了?
设置登录名
选择服务器角色,授予用户权限,这里选择和sa用户一样的角色,这样就拥有管理员权限
接着就可以使用该用户进行登录了
权限总结 #
在渗透测试中我们关注的是sqlserver服务器级别的权限,可以把权限简单的归个类:
- sa权限:即服务器角色sysadmin。拥有数据库操作,文件管理,命令执行,注册表读取等权限。SQLServer数据库的最高权限
- db权限:文件管理,数据库操作等权限 users-administrators
- public权限:数据库操作 guest-users
判断当前用户权限
二、Sqlserver手工注入 #
sqlServer注入也叫MSSQL注入,是最为复杂的数据库攻击技术,由于该数据库功能十分强大,存储过程以及函数语句十分丰富,这些灵活的语句造就了新颖的攻击思路。
对于mssql的一个注入点我们往往最关心的这个注入点的权限问题,是sa、db_owner还是public;其次是这个注点是否显错,注释语句是否可用,例如sql server中注释符“--”;还有就是注入点是什么类型的,是字符型注入,还是数字型注入。
环境搭建 #
为什么这里推荐手动搭建环境而不用在线靶机了?因为自己搭建的环境更加有利于自身对sqlserver注入漏洞的理解。
实验环境:
- sqlserver 2012
- phpstudy2018,php5.6.27(为了方便使用php语言,asp语言有点麻烦)
- 在sqlserver中新建数据库和表
- phpstudy添加sqlsrv扩展
下载:
右键解压得出下面的dll文件,因为我的php版本是5.6,所以将如下两个dll文件复制到 “phpStudy\PHPTutorial\php\php-5.6.27-nts"中
并在php.ini中添加如下两行
- 安装ODBC Driver
ODBC Driver 下载
电脑是64位的则安装64位的。
最后重启phpstudy,查看phpinfo,如果存在如下扩展则说明安装成功
- 在www目录下添加一个php文件,源码如下:
到此,环境搭建完成,开始手工注入学习!
注入手法 #
总的来说和mysql注入的方法差不多,差别在于一些函数的不同
1. 联合查询 #
MSSQL的系统自带库–>master。其实在每个网站中,一般一个网站不会跨库,而在MSSQL中每个库都有一个系统自带表–>sysobjects
此系统表中对我们有用的只有3个字段,NAME字段和XTYPE字段和ID字段。name就是表名信息。xtype是代表表的类型,只有两个参数,S代表系统自带表,U代表用户创建的表。id字段的值用来连接syscolumns表
top关键字:由于MSSQL中不存在limit,那么想要输出一条数据怎么办呢,直接top 1,输出两条数据top 2
- 判断是否是mssql
返回正常,说明网站使用的数据库是Mssql!
- 判断字段长度
order by 3返回正常,说明字段长度是3!
- 寻找字符串显示位
如下两个显示位可以利用
- 查询相关信息
@@version-:获取版本信息
db_name():数据库名字
获取当前数据库名
- 查询表名
将获取到的数据库名与.sys.sysobjects拼接
查询出了第一个表名Users
然后查第二个,如果想显示更多数据再在后面加and name != '第一次输出中的表名'以此类推
- 获取列名
这样查询出了列为 id username passwd
- 获取数据
获取username字段的数据
得到username值:alice wgy alun
以同样的方式获取passwd值
这样数据库中的信息通过联合查询注入就都获取到了!
2. 报错注入 #
mssql数据库是强类型语言数据库,当类型不一致时将会报错,配合子查询即可实现报错注入。
对于报错注入,这里会使用到,convert()函数,CONVERT()函数是把⽇期转换为新数据类型的通⽤函数。
语法:
示例
结果类似
Dec 29 2008 11:45 PM 12-29-2008 29 Dec 08 29 Dec 2008 16:25:46.635
故,对于 convert(int,@@version),convert 函数⾸先会执⾏第⼆个参数指定的SQL查询,然后尝试将查询结果转换为int类型。但是,由于这个SQL查询的结果是varchar类型,⽆法进⾏指定的转换,所以,convert函数会抛出 ⼀个SQL server错误消息,指出“SQL查询结果”⽆法转换为“int”类型,这样的话,攻击者就能得到这个SQL查询的结果了。
满⾜条件的函数还有很多:
convert()函数
- 查询基本信息
获取当前数据库
或者同时将所有数据库爆出来
- 爆表名
得出Users表
同时爆News中的所有表
得出表:Users manage sys
- 爆字段
爆news数据库Users表中的所有字段
- 爆数据
爆Users表中username字段的所有数据
爆Users表中passwd字段的所有数据
cast()函数
直接报错
等号两边数据类型不一致配合子查询获取数据。
- 获取当前数据库名
获取所有数据库
- 获取库中的所有表
- 获取表中的所有字段
- 获取所有数据
获取Users表中username字段的所有数据
3. 布尔盲注 #
如果不能直接通过页面查看到数据库返回的信息,页面根据用户的输入只回显两种状态true和false,则可以通过构造逻辑判断(比较大小)来得到需要的信息
- 判断是否存在盲注
和mysql盲注一样,先如下测试,看是否存在布尔盲注
- 猜测当前数据库名长度
所以数据库名长度为4个字符
- 获取当前数据库名
查询数据库名第一个字符的ascii码为78,对应字母N
查询数据库名第二个字符的ascii码为78,对应字母e
按照同样的方法获取到数据库名为“News”
4. 延时注入 #
延时函数:WAITFOR DELAY
WAITFOR是
中Transact-SQL提供的⼀个流程控制语句。它的作⽤就是等待特定时间,然后继续执⾏后续的语句。它包含⼀个参数DELAY,⽤来指定等待的时间。如果将该语句成功注⼊后,会造成数据库返回记录和 Web请求也会响应延迟特定的时间。由于该语句不涉及条件判断等情况,所以容易注⼊成功。根据Web请求是否有延迟,渗透测试⼈员就可以判断⽹站是否存在注⼊漏洞。同时,由于该语句并不返回特定内容,所以它也是盲注的重要检测⽅法。
语法:
- 判断是否存在注入
- 猜测当前数据库名长度
- 猜测数据库名
查询数据库名第一个字符的ascii码为78,对应字母N
其实这过程和布尔盲注类似,可以完全套用布尔盲注中的测试语句,将其中的and去了,然后再在后面的语句外面套一个if ()语句就行。
三、SQlserver提权 #
sql server提权(执行命令)主要依赖于sql server自带的存储过程。目的:sqlserver权限 —> 系统权限
存储过程是一个可编程的函数,它在数据库中创建并保存,是存储在服务器中的一组预编译过的T-SQL语句。数据库中的存储过程可以看做是对编程中面向对象方法的模拟。它允许控制数据的访问方式(可以将存储过程理解为函数调用的过程),使用execute命令执行存储过程。
主要分为系统存储过程、扩展存储过程、用户自定义的存储过程三大类。
- 系统存储过程主要存储在master数据库中,以sp_为前缀,在任何数据库中都可以调用,在调用的时候不必在存储过程前加上数据库名;
- 扩展存储过程则是对动态链接库(DLL)函数的调用,主要是用于客户端与服务器端或客户端之间进行通信的,以xp_为前缀,使用方法与系统存储过程类似;
- 用户定义的存储过程是SQLServer的使用者编写的存储过程。
getshell #
要执行系统命令,首先需获取sqlserver数据库的权限(一般是sa),然后借助数据库自带的存储过程进行提权,由开始的sqlserver权限提升到执行操作系统命令的权限。
xp_cmdshell执行系统命令 #
xp_cmdshell可以让系统管理员以操作cmd的方式执行给定的命令,并以文本方式返回输出,是一个功能非常强大的扩展存储过程。xp_cmdshell在SQLserver2000中默认开启,可以直接执行系统命令。2005本身及之后的版本默认禁止,所以想要使用其,就需要拥有SA账号相应权限,使用sp_configure将其开启。
2005的xp_cmdshell的权限一般是system,而2008多数为nt authority\network service。
- 判断是否为sa权限,返回1则是
- 判断 xp_cmdshell 是否存在,1就是存在,0就是不存在
当结果为0时,可以通过下列命令恢复
如果xp_cmdshell被删除,则可以通过下列命令重新加载。
如果连xplog70.dll也被删除,则可以通过下列命令恢复(未验证)
- 开启 xp_cmdshell
返回ok,则成功
如果不开启,直接执行命令的话会报错
- 执行系统命令
可以看到当前用户权限是 network service权限,也有可能是system 权限,这个是跟安装过程中,设置启动服务的用户权限相关,建议使用 network service 权限,毕竟如果是 system 权限,那么对于攻击者而言都省下提权的操作了,如图:
如果在安装过程中"sql server数据库引擎"服务选择system账户
那么执行命令时,则为system权限
sp_oacreate执行系统命令 #
当xp_cmdshell被删除时,可以借助SQLServer中的COM组件SP_OACREATE来执行系统命令,原理是SQL Server提供了一些函数访问OLE对象,分别是sp_oacreate和sp_oamethod,可利用它们调用OLE控件,间接获取一个shell。
- 使用下面命令查看是否可使用 sp_oacreate 执行系统命令
如果SQLServer 阻止了对组件 'Ole Automation Procedures' 的过程 'sys.sp_OACreate' 的访问,可以使用以下命令打开。
- 执行命令
这个没有 xp_cmdshell 好用的地方就是不能回显,可以将执行命令的结果进行重定向,然后再在系统中进行查看,比如命令:
那我们可以再使用type命令查看文件内容吗?答案是不行!如下,查看文件内容无任何回显。只能登录到系统中查看
使用CLR执行系统命令 #
从SQL Server 2005 (9.x) 开始,SQL Server 集成了用于 Microsoft Windows 的 .NET Framework 的公共语言运行时 (CLR) 组件。 这意味着现在可以使用任何 .NET Framework 语言(包括 Microsoft Visual Basic .NET 和 Microsoft Visual C#)来编写存储过程、触发器、用户定义类型、用户定义函数、用户定义聚合和流式表值函数。
这种方法比较麻烦,需要自行根据目标创建项目代码,然后进行编译,当然这里直接使用已经编译好的文件的代码
数据库差异备份写webshell #
差异备份数据库得到webshell。在sqlserver里dbo和sa权限都有备份数据库权限,我们可以把数据库备份成asp文件,这样我们就可以通过mssqlserver的备份数据库功能生成一个网页小马。实际情况中,我们得先获取网站的绝对路径,再写shell
前提条件
- 具有db_owner权限
- 知道web目录的绝对路径
这里为了演示方便,就直接生成一个php文件。分为两步执行
生成两个文件,phpinfo.php为webshell
日志差异备份写webshell #
无论是日志备份还是差异备份,都是利用备份的过程中写入一句话木马。
LOG备份的要求是他的数据库备份过,而且选择恢复模式得是完整模式,至少在2008上是这样的。log备份的好处就是备份出来的webshell的文件大小非常的小
生成phpinfo.php
参考: